示例#1
0
        protected virtual bool ConstructRootElements(out ICollection <UIElement> rootElements, out UIAssetBase.UIDesign editorSettings)
        {
            var uiAsset = (UIAssetBase)AssetCloner.Clone(Asset.Asset, AssetClonerFlags.ReferenceAsNull);

            editorSettings = uiAsset.Design;
            var elements = new List <UIElement>();

            foreach (var part in uiAsset.Hierarchy.RootParts)
            {
                UIElementDesign elementDesign;
                if (uiAsset.Hierarchy.Parts.TryGetValue(part.Id, out elementDesign))
                {
                    elements.Add(elementDesign.UIElement);
                }
            }

            rootElements = elements;
            return(true);
        }
示例#2
0
        /// <summary>
        /// This method is called when an asset needs to be tracked
        /// </summary>
        /// <returns>AssetDependencies.</returns>
        private AssetDependencies TrackAsset(AssetId assetId)
        {
            lock (ThisLock)
            {
                AssetDependencies dependencies;
                if (Dependencies.TryGetValue(assetId, out dependencies))
                {
                    return(dependencies);
                }

                // TODO provide an optimized version of TrackAsset method
                // taking directly a well known asset (loaded from a Package...etc.)
                // to avoid session.FindAsset
                var assetItem = session.FindAsset(assetId);
                if (assetItem == null)
                {
                    return(null);
                }

                // Clone the asset before using it in this instance to make sure that
                // we have some kind of immutable state
                // TODO: This is not handling shadow registry

                // No need to clone assets from readonly package
                var assetItemCloned = assetItem.Package.IsSystem
                    ? assetItem
                    : new AssetItem(assetItem.Location, AssetCloner.Clone(assetItem.Asset), assetItem.Package)
                {
                    SourceFolder = assetItem.SourceFolder,
                };

                dependencies = new AssetDependencies(assetItemCloned);

                // Adds to global list
                Dependencies.Add(assetId, dependencies);

                // Update dependencies
                UpdateAssetDependencies(dependencies);
                CheckAllDependencies();

                return(dependencies);
            }
        }
        public static EntityGroupAssetBase ExtractSceneClone(EntityGroupAssetBase source, Guid sourceRootEntity)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }

            // Note: Instead of copying the whole asset (with its potentially big hierarchy), we first copy the asset only (without the hierarchy), then the sub-hierarchy to extract.

            // create the hierarchy of the sub-tree
            var subTreeRoot      = source.Hierarchy.Entities[sourceRootEntity].Entity;
            var subTreeHierarchy = new EntityHierarchyData {
                Entities = { subTreeRoot }, RootEntities = { sourceRootEntity }
            };

            foreach (var subTreeEntity in subTreeRoot.EnumerateChildren(true))
            {
                subTreeHierarchy.Entities.Add(source.Hierarchy.Entities[subTreeEntity.Id]);
            }

            // clone the entities of the sub-tree
            var clonedHierarchy = (EntityHierarchyData)AssetCloner.Clone(subTreeHierarchy);

            clonedHierarchy.Entities[sourceRootEntity].Entity.Transform.Parent = null;

            // set to null reference outside of the sub-tree
            EntityAnalysis.FixupEntityReferences(clonedHierarchy);

            // temporary nullify the hierarchy to avoid to clone it
            var sourceHierarchy = source.Hierarchy;

            source.Hierarchy = null;

            // clone asset without hierarchy
            var clonedAsset = (EntityGroupAssetBase)AssetCloner.Clone(source);

            clonedAsset.Hierarchy = clonedHierarchy;

            // revert the source hierarchy
            source.Hierarchy = sourceHierarchy;

            return(clonedAsset);
        }
        private bool MergeAsset(AssetItem item, AssetItem existingBase, List <AssetBase> existingBaseParts)
        {
            // No need to clone existingBaseParts as they are already cloned
            var baseCopy    = (Asset)AssetCloner.Clone(item.Asset.Base?.Asset);
            var newBaseCopy = (Asset)AssetCloner.Clone(existingBase?.Asset);

            // Computes the hash on the clone (so that we don't have a .Base/.BaseParts in them
            // TODO: We might want to store the hash in the asset in order to avoid a recompute at load time
            // (but would require a compute at save time)
            var baseId        = AssetHash.Compute(baseCopy);
            var newBaseCopyId = AssetHash.Compute(newBaseCopy);

            // If the old base and new base are similar (including ids and overrides), we don't need to perform a merge
            if (baseId == newBaseCopyId)
            {
                return(true);
            }

            // Delegates actual merge to the asset implem
            var result = item.Asset.Merge(baseCopy, newBaseCopy, existingBaseParts);

            if (result.HasErrors)
            {
                result.CopyTo(log);
                return(false);
            }

            item.Asset = (Asset)result.Asset;
            if (item.Asset.Base != null)
            {
                item.Asset.Base = newBaseCopy != null ? new AssetBase(item.Asset.Base.Location, newBaseCopy) : null;
            }

            // Use new existing base parts
            if (existingBaseParts != null)
            {
                item.Asset.BaseParts = existingBaseParts;
            }

            item.IsDirty = true;
            return(true);
        }
示例#5
0
        public void TestWithNewTypeFromChild()
        {
            var baseAsset = new TestDiffAsset()
            {
                Name = "Red", Value = 1, Dynamic = new DiffValueTypeA()
                {
                    Text = "Test1"
                }
            };
            var newBaseAsset = (TestDiffAsset)AssetCloner.Clone(baseAsset);

            var baseItem   = new AssetItem("/base", baseAsset);
            var childAsset = (TestDiffAsset)baseItem.CreateChildAsset();

            // Make New on Name value on first element
            var objDesc    = TypeDescriptorFactory.Default.Find(typeof(TestDiffAsset));
            var memberDesc = objDesc.Members.First(t => t.Name == "Dynamic");

            childAsset.SetOverride(memberDesc, OverrideType.New); // Override Dynamic and change type
            childAsset.Dynamic = new DiffValueTypeB()
            {
                Value = 2
            };

            var diff = new AssetDiff(baseAsset, childAsset, newBaseAsset)
            {
                UseOverrideMode = true
            };

            var diffResult = diff.Compute();

            var diffResultStripped = diffResult.FindLeafDifferences().ToList();

            // Check at least one field has merge from asset 1 (Dynamic)
            Assert.True(diffResultStripped.Any(node => node.ChangeType == Diff3ChangeType.MergeFromAsset1));

            // Check that merged result on Dynamic property is instance from asset2
            var mergeResult = AssetMerge.Merge(diff, AssetMergePolicies.MergePolicyAsset2AsNewBaseOfAsset1);

            Assert.True(childAsset.Dynamic is DiffValueTypeB);
            Assert.AreEqual(2, ((DiffValueTypeB)childAsset.Dynamic).Value);
        }
示例#6
0
        public void TestHash()
        {
            var obj1 = new TestAssetClonerObject
            {
                Name      = "Test1",
                SubObject = new TestAssetClonerObject()
                {
                    Name = "Test2"
                },
                ObjectWithAttachedReference = new TestObjectReference()
            };

            // Create a fake reference to make sure that the attached reference will not be serialized
            var attachedReference = AttachedReferenceManager.GetOrCreateAttachedReference(obj1.ObjectWithAttachedReference);

            attachedReference.Url = "just_for_test";
            attachedReference.Id  = AssetId.New();

            var obj2 = AssetCloner.Clone(obj1);

            var hash1 = AssetHash.Compute(obj1);
            var hash2 = AssetHash.Compute(obj2);

            Assert.AreEqual(hash1, hash2);

            obj1.Name = "Yes";
            var hash11 = AssetHash.Compute(obj1);

            Assert.AreNotEqual(hash11, hash2);
            obj1.Name = "Test1";

            var hash12 = AssetHash.Compute(obj1);

            Assert.AreEqual(hash12, hash2);

            obj2 = AssetCloner.Clone(obj1);

            var hash1WithOverrides = AssetHash.Compute(obj1);
            var hash2WithOverrides = AssetHash.Compute(obj2);

            Assert.AreEqual(hash1WithOverrides, hash2WithOverrides);
        }
示例#7
0
        private void Session_AssetDirtyChanged(Asset asset, bool oldValue, bool newValue)
        {
            // Don't update the dependency manager while saving (setting dirty flag to false)
            if (!isSessionSaving)
            {
                lock (ThisLock)
                {
                    AssetDependencies dependencies;
                    if (Dependencies.TryGetValue(asset.Id, out dependencies))
                    {
                        dependencies.Item.Asset = AssetCloner.Clone(asset);
                        UpdateAssetDependencies(dependencies);

                        // Notify an asset changed
                        OnAssetChanged(dependencies.Item, oldValue, newValue);
                    }
                }

                CheckAllDependencies();
            }
        }
示例#8
0
        public void TestMergeDictionaryNewKeyValue()
        {
            var baseDic = new DictionaryContainer()
            {
                Items = new Dictionary <string, string>()
                {
                    { "A", "AValue" },
                    { "B", "BValue" },
                    { "C", "CValue" },
                }
            };

            var newDic = new DictionaryContainer()
            {
                Items = new Dictionary <string, string>(baseDic.Items)
            };

            var newBaseDic = new DictionaryContainer()
            {
                Items = new Dictionary <string, string>()
                {
                    { "A", "AValue" },
                    { "B", "BValue" },
                    { "C", "CValue" },
                    { "D", "DValue" },
                }
            };

            var diff = new AssetDiff(AssetCloner.Clone(baseDic), newDic, AssetCloner.Clone(newBaseDic))
            {
                UseOverrideMode = true
            };

            var result = AssetMerge.Merge(diff, AssetMergePolicies.MergePolicyAsset2AsNewBaseOfAsset1);

            Assert.False(result.HasErrors);

            Assert.AreEqual(4, newDic.Items.Count);
        }
示例#9
0
        public void TestCloneAssetWithRemoveOverrides()
        {
            var obj = new TestAssetClonerObject
            {
                Name      = "Test1",
                SubObject = new TestAssetClonerObject()
                {
                    Name = "Test2"
                }
            };

            var objDesc    = TypeDescriptorFactory.Default.Find(typeof(TestAssetClonerObject));
            var memberDesc = objDesc.Members.First(t => t.Name == "Name");

            obj.SetOverride(memberDesc, OverrideType.New);
            obj.SubObject.SetOverride(memberDesc, OverrideType.Sealed);

            var newInstance = (TestAssetClonerObject)AssetCloner.Clone(obj, AssetClonerFlags.RemoveOverrides);

            // Check that we are not overriding anything
            Assert.AreEqual(OverrideType.Base, newInstance.GetOverride(memberDesc));
            Assert.AreEqual(OverrideType.Base, newInstance.SubObject.GetOverride(memberDesc));
        }
示例#10
0
        public void TestWithNewTypeFromNewBase()
        {
            var baseAsset = new TestDiffAsset()
            {
                Name = "Red", Value = 1, Dynamic = new DiffValueTypeA()
                {
                    Text = "Test1"
                }
            };
            var newBaseAsset = (TestDiffAsset)AssetCloner.Clone(baseAsset);

            newBaseAsset.Dynamic = new DiffValueTypeB()
            {
                Value = 1
            };

            var baseItem   = new AssetItem("/base", baseAsset);
            var childAsset = (TestDiffAsset)baseItem.CreateChildAsset();

            var diff = new AssetDiff(baseAsset, childAsset, newBaseAsset)
            {
                UseOverrideMode = true
            };

            var diffResult = diff.Compute();

            var diffResultStripped = diffResult.FindLeafDifferences().ToList();

            // Check that everything is merging from asset2
            Assert.True(diffResultStripped.All(node => node.ChangeType == Diff3ChangeType.MergeFromAsset2));

            // Check that merged result on Dynamic property is instance from asset2
            var mergeResult = AssetMerge.Merge(diff, AssetMergePolicies.MergePolicyAsset2AsNewBaseOfAsset1);

            Assert.True(childAsset.Dynamic is DiffValueTypeB);
            Assert.AreEqual(1, ((DiffValueTypeB)childAsset.Dynamic).Value);
        }
示例#11
0
        private void MapEntities(EntityHierarchyData hierarchyData, Dictionary <GroupPartKey, EntityRemapEntry> entities, Guid?instancePartIdArg = null)
        {
            if (hierarchyData == null)
            {
                return;
            }

            // Important, if the hierarchy is coming from a part, we need to clone it entirely
            // and associate correctly the instancePartId with each entities that it is composed of.
            if (instancePartIdArg.HasValue)
            {
                hierarchyData = (EntityHierarchyData)AssetCloner.Clone(hierarchyData);
            }


            foreach (var entityDesign in hierarchyData.Entities)
            {
                if (instancePartIdArg.HasValue)
                {
                    entityDesign.Design.BasePartInstanceId = instancePartIdArg;
                }

                var key = new GroupPartKey(instancePartIdArg, entityDesign.Entity.Id);

                if (entities.ContainsKey(key))
                {
                    continue;
                }

                var remap = new EntityRemapEntry(entityDesign, hierarchyData);
                // We are removing children from transform component for the diff
                remap.PushChildren();

                entities[key] = remap;
            }
        }
示例#12
0
        public void TestPackageAnalysis()
        {
            var package = new Package();

            var baseAsset = new TestDiffAsset()
            {
                Name = "Red", Value = 1
            };
            var baseItem = new AssetItem("base", baseAsset);

            var childAsset = (TestDiffAsset)baseItem.CreateChildAsset();
            var childItem  = new AssetItem("child", childAsset);

            var newBaseAsset = (TestDiffAsset)AssetCloner.Clone(baseAsset);

            newBaseAsset.Name = "Green";
            var newBaseItem = new AssetItem("base", newBaseAsset);

            package.Assets.Add(newBaseItem);
            package.Assets.Add(childItem);

            var session = new PackageSession();

            session.Packages.Add(package);

            var result   = new LoggerResult();
            var analysis = new PackageAssetTemplatingAnalysis(package, result);

            analysis.Run();

            Assert.False(result.HasErrors);

            var assetModified = (TestDiffAsset)package.Assets.Find("child").Asset;

            Assert.AreEqual("Green", assetModified.Name);
        }
示例#13
0
            protected override Task <ResultStatus> DoCommandOverride(ICommandContext commandContext)
            {
                // Reduce trees on CPU
                //var materialReducer = new MaterialTreeReducer(material);
                //materialReducer.ReduceTrees();

                //foreach (var reducedTree in materialReducer.ReducedTrees)
                //{
                //    material.Nodes[reducedTree.Key] = reducedTree.Value;
                //}

                // Reduce on GPU
                // TODO: Adapt GPU reduction so that it is compatible Android color/alpha separation
                // TODO: Use the build engine processed output textures instead of the imported one (not existing any more)
                // TODO: Set the reduced texture output format
                // TODO: The graphics device cannot be shared with the Previewer
                //var graphicsDevice = (GraphicsDevice)context.Attributes.GetOrAdd(CompilerContext.GraphicsDeviceKey, key => GraphicsDevice.New(DeviceCreationFlags.None, GraphicsProfile.Level_11_0));
                //using (var materialTextureLayerFlattener = new MaterialTextureLayerFlattener(material, graphicsDevice))
                //{
                //    materialTextureLayerFlattener.PrepareForFlattening(new UDirectory(assetUrl.Directory));
                //    if (materialTextureLayerFlattener.HasCommands)
                //    {
                //        var compiler = EffectCompileCommand.GetOrCreateEffectCompiler(context);
                //        materialTextureLayerFlattener.Run(compiler);
                //        // store Material with modified textures
                //        material = materialTextureLayerFlattener.Material;
                //    }
                //}

                // Check with Ben why DoCommandOverride is called without going through the constructor?
                var assetManager    = new ContentManager(MicrothreadLocalDatabases.ProviderService);
                var materialContext = new MaterialGeneratorContext
                {
                    GraphicsProfile = graphicsProfile,
                    Content         = assetManager,
                    ColorSpace      = colorSpace
                };

                materialContext.AddLoadingFromSession(AssetFinder);

                var materialClone = AssetCloner.Clone(Parameters);
                var result        = MaterialGenerator.Generate(new MaterialDescriptor {
                    MaterialId = materialClone.Id, Attributes = materialClone.Attributes, Layers = materialClone.Layers
                }, materialContext, string.Format("{0}:{1}", materialClone.Id, assetUrl));

                if (result.HasErrors)
                {
                    result.CopyTo(commandContext.Logger);
                    return(Task.FromResult(ResultStatus.Failed));
                }
                // Separate the textures into color/alpha components on Android to be able to use native ETC1 compression
                //if (context.Platform == PlatformType.Android)
                //{
                //    var alphaComponentSplitter = new TextureAlphaComponentSplitter(assetItem.Package.Session);
                //    material = alphaComponentSplitter.Run(material, new UDirectory(assetUrl.GetDirectory())); // store Material with alpha substituted textures
                //}

                // Create the parameters
                //var materialParameterCreator = new MaterialParametersCreator(material, assetUrl);
                //if (materialParameterCreator.CreateParameterCollectionData(commandContext.Logger))
                //    return Task.FromResult(ResultStatus.Failed);

                assetManager.Save(assetUrl, result.Material);

                return(Task.FromResult(ResultStatus.Successful));
            }
示例#14
0
            private void EnsureClonedSceneAndHash()
            {
                if (!sceneCloned)
                {
                    // Hash relevant scene objects
                    if (asset.Scene != null)
                    {
                        string sceneUrl   = AttachedReferenceManager.GetUrl(asset.Scene);
                        var    sceneAsset = (SceneAsset)AssetFinder.FindAsset(sceneUrl)?.Asset;

                        // Clone scene asset because we update the world transformation matrices
                        clonedSceneAsset = (SceneAsset)AssetCloner.Clone(sceneAsset);

                        // Turn the entire entity hierarchy into a single list
                        var sceneEntities = clonedSceneAsset.Hierarchy.Parts.Select(x => x.Value.Entity).ToList();

                        sceneHash = 0;
                        foreach (var entity in sceneEntities)
                        {
                            // Collect bounding box entities
                            NavigationBoundingBoxComponent boundingBoxComponent = entity.Get <NavigationBoundingBoxComponent>();
                            // Collect static collider entities
                            StaticColliderComponent colliderComponent = entity.Get <StaticColliderComponent>();

                            if (boundingBoxComponent == null && colliderComponent == null)
                            {
                                continue;
                            }

                            // Update world transform
                            entity.Transform.UpdateWorldMatrix();

                            if (boundingBoxComponent != null)
                            {
                                Vector3    scale;
                                Quaternion rotation;
                                Vector3    translation;
                                boundingBoxComponent.Entity.Transform.WorldMatrix.Decompose(out scale, out rotation, out translation);
                                var boundingBox = new BoundingBox(translation - boundingBoxComponent.Size * scale, translation + boundingBoxComponent.Size * scale);
                                boundingBoxes.Add(boundingBox);

                                // Hash collider for ComputeParameterHash
                                sceneHash = (sceneHash * 397) ^ boundingBox.GetHashCode();
                            }

                            if (colliderComponent != null)
                            {
                                staticColliderDatas.Add(new StaticColliderData
                                {
                                    Component = colliderComponent
                                });

                                if (colliderComponent.Enabled && !colliderComponent.IsTrigger && ((int)asset.IncludedCollisionGroups & (int)colliderComponent.CollisionGroup) != 0)
                                {
                                    // Load collider shape assets since the scene asset is being used, which does not have these loaded by default
                                    foreach (var desc in colliderComponent.ColliderShapes)
                                    {
                                        var shapeAssetDesc = desc as ColliderShapeAssetDesc;
                                        if (shapeAssetDesc?.Shape != null)
                                        {
                                            var assetReference = AttachedReferenceManager.GetAttachedReference(shapeAssetDesc.Shape);
                                            PhysicsColliderShape loadedColliderShape;
                                            if (!loadedColliderShapes.TryGetValue(assetReference.Url, out loadedColliderShape))
                                            {
                                                loadedColliderShape = contentManager.Load <PhysicsColliderShape>(assetReference.Url);
                                                loadedColliderShapes.Add(assetReference.Url, loadedColliderShape); // Store where we loaded the shapes from
                                            }
                                            shapeAssetDesc.Shape = loadedColliderShape;
                                        }
                                    }
                                }

                                // Hash collider for ComputeParameterHash
                                sceneHash = (sceneHash * 397) ^ Xenko.Navigation.NavigationMeshBuildUtils.HashEntityCollider(colliderComponent, asset.IncludedCollisionGroups);
                            }
                        }
                    }
                    sceneCloned = true;
                }
            }
示例#15
0
        private bool MergeAsset(AssetItem item, AssetItem existingBase, List <AssetBase> existingBaseParts)
        {
            // No need to clone existingBaseParts as they are already cloned
            var baseCopy    = (Asset)AssetCloner.Clone(item.Asset.Base?.Asset);
            var newBaseCopy = (Asset)AssetCloner.Clone(existingBase?.Asset);

            // Check base parts
            bool basePartsAreEqual = true;

            if (item.Asset != null && item.Asset.BaseParts != null)
            {
                foreach (var assetBasePart in item.Asset.BaseParts)
                {
                    var existingBasePart = existingBaseParts.First(e => (e.Id == assetBasePart.Id || e.Location == assetBasePart.Location));
                    if (!CompareAssets(assetBasePart.Asset, existingBasePart.Asset))
                    {
                        basePartsAreEqual = false;
                    }
                }
            }

            // If the old base and new base are similar (including ids and overrides), we don't need to perform a merge
            if (CompareAssets(baseCopy, newBaseCopy) && basePartsAreEqual)
            {
                return(true);
            }

            // Delegates actual merge to the asset implem
            var result = item.Asset.Merge(baseCopy, newBaseCopy, existingBaseParts, item.Location);

            if (result.HasErrors)
            {
                result.CopyTo(log);
                return(false);
            }

            item.Asset = (Asset)result.Asset;
            if (item.Asset.Base != null)
            {
                item.Asset.Base = newBaseCopy != null ? new AssetBase(item.Asset.Base.Location, newBaseCopy) : null;
            }

            // Use new existing base parts
            if (existingBaseParts != null)
            {
                item.Asset.BaseParts = existingBaseParts;
            }

            // Set this variable to true at debug time to check what is the output of the merge
            bool writeToDebug = false;

            if (writeToDebug)
            {
                var writer = new MemoryStream();
                YamlSerializer.Serialize(writer, item.Asset);
                writer.Flush();
                writer.Position = 0;
                var text = Encoding.UTF8.GetString(writer.ToArray());
                Debug.WriteLine(text);
            }

            item.IsDirty = true;
            return(true);
        }
示例#16
0
        /// <summary>
        /// This method is responsible to merge assets when loading. A 3-way merge of the asset is necessary because concurrent changes
        /// can happen on assets (people working with a SCM and different branches). This method will collect all assets that are
        /// using asset templating (including prefabs) and will perform the merge iteratively (incremental merge from the most inherited
        /// assets to the most derived asset)
        /// </summary>
        /// <param name="assetItem"></param>
        /// <param name="beingProcessed"></param>
        /// <returns></returns>
        private bool ProcessMergeAssetItem(AssetItem assetItem, HashSet <Guid> beingProcessed)
        {
            if (beingProcessed.Contains(assetItem.Id))
            {
                log.Error(package, assetItem.Asset.Base, AssetMessageCode.AssetForPackageNotFound, assetItem.Asset.Base, package.FullPath.GetFileName());
                return(false);
            }
            beingProcessed.Add(assetItem.Id);

            AssetItem        existingAssetBase = null;
            List <AssetBase> existingBaseParts = null;

            // Process asset base
            if (assetItem.Asset.Base != null)
            {
                if (!ProcessMergeAssetBase(assetItem.Asset.Base, beingProcessed, out existingAssetBase))
                {
                    return(false);
                }
            }

            // Process asset base parts
            if (assetItem.Asset.BaseParts != null && assetItem.Asset.BaseParts.Count > 0)
            {
                existingBaseParts = new List <AssetBase>();

                foreach (var basePart in assetItem.Asset.BaseParts)
                {
                    AssetItem existingAssetBasePart;
                    if (!ProcessMergeAssetBase(basePart, beingProcessed, out existingAssetBasePart))
                    {
                        return(false);
                    }

                    // Replicate the group with the list of ids
                    var newBasePart = new AssetBase(existingAssetBasePart.Location, (Asset)AssetCloner.Clone(existingAssetBasePart.Asset));

                    existingBaseParts.Add(newBasePart);
                }
            }

            // Don't process an asset that has been already processed
            if (!assetsProcessed.ContainsKey(assetItem.Id))
            {
                // For simple merge (base, newAsset, newBase) => newObject
                // For multi-part prefabs merge (base, newAsset, newBase) + baseParts + newBaseParts => newObject
                if (!MergeAsset(assetItem, existingAssetBase, existingBaseParts))
                {
                    return(false);
                }

                assetsProcessed.Add(assetItem.Id, assetItem);
                assetsToProcess.Remove(assetItem.Id);
            }

            return(true);
        }
示例#17
0
 /// <summary>
 /// Notifies this object that the asset has been modified.
 /// </summary>
 /// <remarks>This method will trigger the re-evaluation of properties containing the path to a source file.</remarks>
 public void NotifyAssetChanged()
 {
     clonedAsset = AssetCloner.Clone(sessionAsset);
     UpdateAssetImportPathsTracked(true);
 }
示例#18
0
        public void TestCascadedInheritance()
        {
            // Test with:
            // a1: an asset with 2 entities
            // a2: an asset using a1 by composition with 2 instances
            // a3: an asset based on a2
            //
            // Add one entity to a1. Check that a2 and a3 will get correctly the entities replicated

            // Before Merge
            // a1:      a2: (baseParts: a1, 2 instances)     a3: (base: a2)
            //  | ea     | ea1 (base: ea)                     | ea1' (base: ea1)
            //  | eb     | eb1 (base: eb)                     | eb1' (base: eb1)
            //           | ea2 (base: ea)                     | ea2' (base: ea2)
            //           | eb2 (base: eb)                     | eb2' (base: eb2)


            // After Merge
            // We add one entity to the base a1
            // a1:      a2: (baseParts: a1, 2 instances)     a3: (base: a2)
            //  | ea     | ea1 (base: ea)                     | ea1' (base: ea1)
            //  | eb     | eb1 (base: eb)                     | eb1' (base: eb1)
            //  | ec     | ec1 (base: ec)                     | ec1' (base: ec1)
            //           | ea2 (base: ea)                     | ea2' (base: ea2)
            //           | eb2 (base: eb)                     | eb2' (base: eb2)
            //           | ec2 (base: ec)                     | ec2' (base: ec2)

            var a1 = new EntityGroupAsset();
            var ea = new Entity("ea");
            var eb = new Entity("eb");

            a1.Hierarchy.Entities.Add(ea);
            a1.Hierarchy.Entities.Add(eb);
            a1.Hierarchy.RootEntities.Add(ea.Id);
            a1.Hierarchy.RootEntities.Add(eb.Id);

            var a2             = new EntityGroupAsset();
            var aPartInstance1 = (EntityGroupAsset)a1.CreateChildAsset("a1");
            var aPartInstance2 = (EntityGroupAsset)a1.CreateChildAsset("a1");

            a2.AddPart(aPartInstance1);
            a2.AddPart(aPartInstance2);

            // Modify a1 to add entity ec
            var ec = new Entity("ec");

            a1.Hierarchy.Entities.Add(ec);
            a1.Hierarchy.RootEntities.Add(ec.Id);

            var a3 = (EntityGroupAsset)a2.CreateChildAsset("a2");

            // Merge a2
            var result2 = a2.Merge(null, null, new List <AssetBase>()
            {
                new AssetBase("a1", (Asset)AssetCloner.Clone(a1))
            });

            Assert.False(result2.HasErrors);
            Assert.AreEqual(6, a2.Hierarchy.RootEntities.Count);
            Assert.True(a2.Hierarchy.Entities.All(it => it.Design.BaseId.HasValue && it.Design.BasePartInstanceId.HasValue));

            // Merge a3
            var result3 = a3.Merge((Asset)AssetCloner.Clone(a3.Base.Asset), (Asset)AssetCloner.Clone(a2), null);

            Assert.False(result3.HasErrors);
            Assert.AreEqual(6, a3.Hierarchy.RootEntities.Count);
            Assert.True(a3.Hierarchy.Entities.All(it => !it.Design.BasePartInstanceId.HasValue));
            Assert.True(a3.Hierarchy.Entities.All(it => it.Design.BaseId.HasValue && a2.Hierarchy.Entities.ContainsKey(it.Design.BaseId.Value)));
        }
示例#19
0
        public void TestMergeSimpleWithBasePartsAndLinks()
        {
            // part1:                part2:                  newAsset (BaseParts: part1):       newAssetMerged (BaseParts: part2):
            //   EA                    EA                      EA1 (base: EA)                     [0] EA1' (base: EA)
            //   EB                    EB                      EB1 (base: EB)                     [1] EB1' (base: EB)
            //   EC + link: EA         EC + link: EA           EC1 (base: EC) + link: EA1         [2] EC1' (base: EC) + link: EA1'
            //                         ED + link: EB           EA2 (base: EA)                     [3] EA2' (base: EA)
            //                                                 EB2 (base: EB)                     [4] EB2' (base: EB)
            //                                                 EC2 (base: EC) + link: EA2         [5] EC2' (base: EC) + link: EA2'
            //                                                                                    [6] ED1' (base: ED) + link: EB1'
            //                                                                                    [7] ED2' (base: ED) + link: EB2'
            var entityA = new Entity()
            {
                Name = "A"
            };
            var entityB = new Entity()
            {
                Name = "B"
            };
            var entityC = new Entity()
            {
                Name = "C"
            };

            // EC + link: EA
            entityC.Add(new TestEntityComponent()
            {
                EntityLink = entityA
            });

            // part1 Asset
            var basePart = new EntityGroupAsset();

            basePart.Hierarchy.Entities.Add(new EntityDesign(entityA, new EntityDesignData()));
            basePart.Hierarchy.Entities.Add(new EntityDesign(entityB, new EntityDesignData()));
            basePart.Hierarchy.Entities.Add(new EntityDesign(entityC, new EntityDesignData()));
            basePart.Hierarchy.RootEntities.Add(entityA.Id);
            basePart.Hierarchy.RootEntities.Add(entityB.Id);
            basePart.Hierarchy.RootEntities.Add(entityC.Id);

            // Create part1 asset
            var part1    = (EntityGroupAsset)basePart.CreateChildAsset("part");
            var entityB1 = part1.Hierarchy.Entities.First(it => it.Entity.Name == "B").Entity;
            var part12   = (EntityGroupAsset)basePart.CreateChildAsset("part");
            var entityB2 = part12.Hierarchy.Entities.First(it => it.Entity.Name == "B").Entity;

            // create part2 assset
            var entityD = new Entity()
            {
                Name = "D"
            };

            basePart.Hierarchy.Entities.Add(new EntityDesign(entityD, new EntityDesignData()));
            basePart.Hierarchy.RootEntities.Add(entityD.Id);
            // ED + link: EB
            var entityBFrom2 = basePart.Hierarchy.Entities.Where(it => it.Entity.Name == "B").Select(it => it.Entity).First();

            entityD.Add(new TestEntityComponent()
            {
                EntityLink = entityBFrom2
            });

            // originalAsset: Add a new instanceId for this part
            var asset = new EntityGroupAsset();

            asset.AddPart(part1);
            asset.AddPart(part12);

            // Merge entities (NOTE: it is important to clone baseAsset/newBaseAsset)
            var entityMerge = asset.Merge(null, null, new List <AssetBase>()
            {
                new AssetBase("part", (Asset)AssetCloner.Clone(basePart))
            });

            Assert.False(entityMerge.HasErrors);

            // EntityD must be now part of the new asset
            Assert.AreEqual(8, asset.Hierarchy.RootEntities.Count);
            Assert.AreEqual(8, asset.Hierarchy.Entities.Count);
            Assert.AreEqual(2, asset.Hierarchy.Entities.Count(it => it.Entity.Name == "D"));

            foreach (var entity in asset.Hierarchy.Entities.Where(it => it.Entity.Name == "D"))
            {
                // Check that we have the correct baesId and basePartInstanceId
                Assert.True(entity.Design.BasePartInstanceId.HasValue);
                Assert.True(entity.Design.BaseId.HasValue);
                Assert.AreEqual(entityD.Id, entity.Design.BaseId.Value);

                // Make sure that the entity is in the RootEntities
                Assert.True(asset.Hierarchy.RootEntities.Contains(entity.Entity.Id));
            }

            var entityDesignD1 = asset.Hierarchy.Entities.FirstOrDefault(it => it.Entity.Name == "D" && it.Design.BasePartInstanceId == part1.Id);

            Assert.NotNull(entityDesignD1);

            var entityDesignD2 = asset.Hierarchy.Entities.FirstOrDefault(it => it.Entity.Name == "D" && it.Design.BasePartInstanceId == part12.Id);

            Assert.NotNull(entityDesignD2);

            // Check components
            var testComponentD1 = entityDesignD1.Entity.Get <TestEntityComponent>();

            Assert.NotNull(testComponentD1);
            Assert.AreEqual(entityB1, testComponentD1.EntityLink);

            var testComponentD2 = entityDesignD2.Entity.Get <TestEntityComponent>();

            Assert.NotNull(testComponentD2);
            Assert.AreEqual(entityB2, testComponentD2.EntityLink);
        }
示例#20
0
 /// <summary>
 /// Merges the specified assets from <c>base</c> and <c>from2</c> into <c>from1</c>.
 /// </summary>
 /// <param name="assetBase">The asset base.</param>
 /// <param name="assetFrom1">The asset from1.</param>
 /// <param name="assetFrom2">The asset from2.</param>
 /// <param name="mergePolicy">The merge policy. See <see cref="AssetMergePolicies" /> for default policies.</param>
 /// <returns>The result of the merge.</returns>
 /// <exception cref="System.ArgumentNullException">
 /// assetFrom1
 /// or
 /// mergePolicy
 /// </exception>
 public static MergeResult Merge(Asset assetBase, Asset assetFrom1, Asset assetFrom2, MergePolicyDelegate mergePolicy)
 {
     if (assetFrom1 == null)
     {
         throw new ArgumentNullException("assetFrom1");
     }
     if (mergePolicy == null)
     {
         throw new ArgumentNullException("mergePolicy");
     }
     return(Merge(new AssetDiff((Asset)AssetCloner.Clone(assetBase), (Asset)AssetCloner.Clone(assetFrom1), (Asset)AssetCloner.Clone(assetFrom2)), mergePolicy));
 }
示例#21
0
        /// <summary>
        /// 3-way merge assets using an external diff tool.
        /// </summary>
        /// <param name="assetBase0">The asset base0.</param>
        /// <param name="assetFrom1">The asset from1.</param>
        /// <param name="assetFrom2">The asset from2.</param>
        /// <returns>The result of the merge.</returns>
        public static MergeResult MergeWithExternalTool(Asset assetBase0, Asset assetFrom1, Asset assetFrom2)
        {
            var result = new MergeResult();

            // If they are all null, nothing to do
            if (assetBase0 == null && assetFrom1 == null && assetFrom2 == null)
            {
                return(result);
            }

            if (!File.Exists(DefaultMergeTool))
            {
                result.Error("Unable to use external diff3 merge tool [{0}]. File not found", DefaultMergeTool);
                return(result);
            }

            var assetBase = (Asset)AssetCloner.Clone(assetBase0);
            var asset1    = (Asset)AssetCloner.Clone(assetFrom1);
            var asset2    = (Asset)AssetCloner.Clone(assetFrom2);

            // Clears base as we are not expecting to work with them directly
            // The real base must be passed by the assetBase0 parameter
            if (assetBase != null)
            {
                assetBase.Base = null;
            }
            if (asset1 != null)
            {
                asset1.Base = null;
            }
            if (asset2 != null)
            {
                asset2.Base = null;
            }

            var assetBasePath = Path.GetTempFileName();
            var asset1Path    = Path.GetTempFileName();
            var asset2Path    = Path.GetTempFileName();

            try
            {
                AssetSerializer.Save(assetBasePath, assetBase);
                AssetSerializer.Save(asset1Path, asset1);
                AssetSerializer.Save(asset2Path, asset2);
            }
            catch (Exception exception)
            {
                result.Error("Unexpected error while serializing assets on disk before using diff tool", exception);
                return(result);
            }

            var outputPath = Path.GetTempFileName();

            try
            {
                // TODO We need to access different diff tools command line
                // kdiff3.exe file1 file2 file3 -o outputfile
                var process = Process.Start(DefaultMergeTool, string.Format("{0} {1} {2} -o {3}", assetBasePath, asset1Path, asset2Path, outputPath));
                if (process == null)
                {
                    result.Error("Unable to launch diff3 tool exe from [{0}]", DefaultMergeTool);
                }
                else
                {
                    process.WaitForExit();

                    if (process.ExitCode != 0)
                    {
                        result.Error("Error, failed to merge files");
                    }
                }
            }
            catch (Exception ex)
            {
                result.Error("Unable to launch diff3 tool exe from [{0}]", ex, DefaultMergeTool);
            }

            if (!result.HasErrors)
            {
                try
                {
                    var mergedAsset = (Asset)AssetSerializer.Load(outputPath);

                    if (mergedAsset != null)
                    {
                        if (assetFrom1 == null)
                        {
                            mergedAsset.Base = assetFrom2 == null ? assetBase0.Base : assetFrom2.Base;
                        }
                        else
                        {
                            mergedAsset.Base = assetFrom1.Base;
                        }
                    }
                    result.Asset = mergedAsset;
                }
                catch (Exception ex)
                {
                    result.Error("Unexpected exception while loading merged assets from [{0}]", ex, outputPath);
                }
            }

            return(result);
        }
示例#22
0
        protected override void Compile(AssetCompilerContext context, string urlInStorage, UFile assetAbsolutePath, SpriteFontAsset asset, AssetCompilerResult result)
        {
            var colorSpace = context.GetColorSpace();

            if (asset.FontType == SpriteFontType.SDF)
            {
                // TODO Build scalable (SDF) font texture

                // copy the asset and transform the source and character set file path to absolute paths
                var assetClone     = (SpriteFontAsset)AssetCloner.Clone(asset);
                var assetDirectory = assetAbsolutePath.GetParent();
                assetClone.Source       = !string.IsNullOrEmpty(asset.Source) ? UPath.Combine(assetDirectory, asset.Source) : null;
                assetClone.CharacterSet = !string.IsNullOrEmpty(asset.CharacterSet) ? UPath.Combine(assetDirectory, asset.CharacterSet) : null;

                result.BuildSteps = new AssetBuildStep(AssetItem)
                {
                    new SignedDistanceFieldFontCommand(urlInStorage, assetClone)
                };
            }
            else
            if (asset.FontType == SpriteFontType.Dynamic)
            {
                UFile fontPathOnDisk;

                if (!string.IsNullOrEmpty(asset.Source))
                {
                    var assetDirectory = assetAbsolutePath.GetParent();
                    fontPathOnDisk = UPath.Combine(assetDirectory, asset.Source);
                    if (!File.Exists(fontPathOnDisk))
                    {
                        result.Error("The font source '{0}' does not exist on the PC.", asset.FontName);
                        return;
                    }
                    // set the source filename as font name instead of the font family.
                    asset.FontName = fontPathOnDisk.GetFileName();
                }
                else
                {
                    fontPathOnDisk = GetFontPath(asset, result);
                    if (fontPathOnDisk == null)
                    {
                        result.Error("The font named '{0}' could not be located on the PC.", asset.FontName);
                        return;
                    }
                }
                var fontImportLocation = FontHelper.GetFontPath(asset.FontName, asset.Style);

                result.BuildSteps = new AssetBuildStep(AssetItem)
                {
                    new ImportStreamCommand {
                        SourcePath = fontPathOnDisk, Location = fontImportLocation
                    },
                    new DynamicFontCommand(urlInStorage, asset)
                };
            }
            else
            {
                // copy the asset and transform the source and character set file path to absolute paths
                var assetClone     = (SpriteFontAsset)AssetCloner.Clone(asset);
                var assetDirectory = assetAbsolutePath.GetParent();
                assetClone.Source       = !string.IsNullOrEmpty(asset.Source) ? UPath.Combine(assetDirectory, asset.Source): null;
                assetClone.CharacterSet = !string.IsNullOrEmpty(asset.CharacterSet) ? UPath.Combine(assetDirectory, asset.CharacterSet): null;

                result.BuildSteps = new AssetBuildStep(AssetItem)
                {
                    new StaticFontCommand(urlInStorage, assetClone, colorSpace)
                };
            }
        }
示例#23
0
        public void TestMergeEntityWithChildren()
        {
            // Test merging an EntityGroupAsset with a root entity EA, and 3 child entities
            // - Add a child entity to NewBase
            // - Remove a child entity from NewAsset
            //
            //       Base         NewBase       NewAsset                  NewAsset (Merged)
            //
            //       EA           EA            EA'(base: EA)             EA'(base: EA)
            //        |-EA1       |-EA1         |-EA1'(base: EA1)         |-EA1'(base: EA1)
            //        |-EA2       |-EA2         |                         |
            //        |-EA3       |-EA3         |-EA3'(base: EA3)         |-EA3'(base: EA3)
            //                    |-EA4                                   |-EA4'(base: EA4)
            //

            var eA = new Entity()
            {
                Name = "A"
            };
            var eA1 = new Entity()
            {
                Name = "A1"
            };
            var eA2 = new Entity()
            {
                Name = "A2"
            };
            var eA3 = new Entity()
            {
                Name = "A3"
            };

            eA.Transform.Children.Add(eA1.Transform);
            eA.Transform.Children.Add(eA2.Transform);
            eA.Transform.Children.Add(eA3.Transform);

            // Create Base Asset
            var baseAsset = new EntityGroupAsset();

            baseAsset.Hierarchy.Entities.Add(new EntityDesign(eA, new EntityDesignData()));
            baseAsset.Hierarchy.Entities.Add(new EntityDesign(eA1, new EntityDesignData()));
            baseAsset.Hierarchy.Entities.Add(new EntityDesign(eA2, new EntityDesignData()));
            baseAsset.Hierarchy.Entities.Add(new EntityDesign(eA3, new EntityDesignData()));
            baseAsset.Hierarchy.RootEntities.Add(eA.Id);

            var baseAssetItem = new AssetItem("base", baseAsset);

            // Create new Base Asset
            var newBaseAsset   = (EntityGroupAsset)AssetCloner.Clone(baseAsset);
            var eA2FromNewBase = newBaseAsset.Hierarchy.Entities.First(item => item.Entity.Id == eA2.Id);

            newBaseAsset.Hierarchy.Entities[eA.Id].Entity.Transform.Children.Remove(eA2FromNewBase.Entity.Transform);

            // Create new Asset (from base)
            var newAsset = (EntityGroupAsset)baseAssetItem.CreateChildAsset();
            var eA4      = new Entity()
            {
                Name = "A4"
            };

            newAsset.Hierarchy.Entities.Add(new EntityDesign(eA4, new EntityDesignData()));
            newAsset.Hierarchy.Entities[newAsset.Hierarchy.RootEntities.First()].Entity.Transform.Children.Add(eA4.Transform);

            // Merge entities (NOTE: it is important to clone baseAsset/newBaseAsset)
            var result = newAsset.Merge((EntityGroupAssetBase)AssetCloner.Clone(baseAsset), (EntityGroupAssetBase)AssetCloner.Clone(newBaseAsset), null);

            Assert.False(result.HasErrors);

            Assert.AreEqual(1, newAsset.Hierarchy.RootEntities.Count);
            Assert.AreEqual(4, newAsset.Hierarchy.Entities.Count); // EA, EA1', EA3', EA4'

            var rootEntity = newAsset.Hierarchy.Entities[newAsset.Hierarchy.RootEntities.First()];

            Assert.AreEqual(3, rootEntity.Entity.Transform.Children.Count);

            Assert.AreEqual("A1", rootEntity.Entity.Transform.Children[0].Entity.Name);
            Assert.AreEqual("A3", rootEntity.Entity.Transform.Children[1].Entity.Name);
            Assert.AreEqual("A4", rootEntity.Entity.Transform.Children[2].Entity.Name);
        }
示例#24
0
        /// <inheritdoc />
        public override bool ProcessDeserializedData(AssetPropertyGraphContainer graphContainer, object targetRootObject, Type targetMemberType, ref object data, bool isRootDataObjectReference, AssetId?sourceId, YamlAssetMetadata <OverrideType> overrides, YamlAssetPath basePath)
        {
            if (targetRootObject == null)
            {
                throw new ArgumentNullException(nameof(targetRootObject));
            }
            if (data == null)
            {
                throw new ArgumentNullException(nameof(data));
            }

            var asset = (Asset)targetRootObject;
            var targetPropertyGraph = graphContainer.TryGetGraph(asset.Id);

            // We use a container object in case the data itself is an object reference
            var container = isRootDataObjectReference ? new FixupContainer {
                Data = data
            } : data;
            var rootNode           = targetPropertyGraph.Container.NodeContainer.GetOrCreateNode(container);
            var externalReferences = ExternalReferenceCollector.GetExternalReferences(targetPropertyGraph.Definition, rootNode);

            try
            {
                // Clone to create new ids for any IIdentifiable, except passed external references that will be maintained
                Dictionary <Guid, Guid> idRemapping;
                data = AssetCloner.Clone <object>(data, AssetClonerFlags.GenerateNewIdsForIdentifiableObjects, externalReferences, out idRemapping);
            }
            // TODO: have a proper exception type for serialization failure
            catch (Exception)
            {
                // Note: this can fail if the type doesn't have a binary serializer.
                return(false);
            }

            var  targetTypeDescriptor = TypeDescriptorFactory.Default.Find(targetMemberType);
            bool result;

            switch (targetTypeDescriptor.Category)
            {
            case DescriptorCategory.Collection:
                result = ConvertForCollection((CollectionDescriptor)targetTypeDescriptor, ref data);
                break;

            case DescriptorCategory.Dictionary:
                result = ConvertForDictionary((DictionaryDescriptor)targetTypeDescriptor, ref data);
                break;

            case DescriptorCategory.Primitive:
            case DescriptorCategory.Object:
            case DescriptorCategory.NotSupportedObject:
            case DescriptorCategory.Nullable:
                result = ConvertForProperty(targetTypeDescriptor.Type, ref data);
                break;

            case DescriptorCategory.Array:
            case DescriptorCategory.Custom:
                throw new NotSupportedException();

            default:
                throw new ArgumentOutOfRangeException();
            }

            if (!result)
            {
                return(false);
            }

            // Collect all referenceable objects from the target asset (where we're pasting)
            var referenceableObjects = IdentifiableObjectCollector.Collect(targetPropertyGraph.Definition, targetPropertyGraph.RootNode);

            // We use a container object in case the data itself is an object reference
            container = isRootDataObjectReference ? new FixupContainer {
                Data = data
            } : data;
            rootNode = targetPropertyGraph.Container.NodeContainer.GetOrCreateNode(container);

            // Generate YAML paths for the external reference so we can go through the normal deserialization fixup method.
            var externalReferenceIds = new HashSet <Guid>(externalReferences.Select(x => x.Id));
            var visitor = new ObjectReferencePathGenerator(targetPropertyGraph.Definition)
            {
                ShouldOutputReference = x => externalReferenceIds.Contains(x)
            };

            visitor.Visit(rootNode);

            // Fixup external references
            FixupObjectReferences.FixupReferences(container, visitor.Result, referenceableObjects, true);

            data = (container as FixupContainer)?.Data ?? data;
            return(true);
        }
示例#25
0
        public void TestMergeAddEntityWithLinks2()
        {
            // Test merging an EntityGroupAsset with a root entity EA, and 3 child entities
            // - Add a child entity to NewBase that has a link to an another entity + a link to the component of another entity
            //
            //       Base         NewBase                      NewAsset                  NewAsset (Merged)
            //
            //       EA           EA                           EA'(base: EA)             EA'(base: EA)
            //        |-EA1       |-EA1                        |-EA1'(base: EA1)         |-EA1'(base: EA1)
            //        |-EA2       |-EA2 + link EA4             |-EA2'(base: EA2)         |-EA2'(base: EA2) + link EA4'
            //        |-EA3       |-EA3                        |-EA3'(base: EA3)         |-EA3'(base: EA3)
            //                    |-EA4                                                  |-EA4'(base: EA4)
            //
            var eA = new Entity()
            {
                Name = "A"
            };
            var eA1 = new Entity()
            {
                Name = "A1"
            };
            var eA2 = new Entity()
            {
                Name = "A2"
            };
            var eA3 = new Entity()
            {
                Name = "A3"
            };

            eA.Transform.Children.Add(eA1.Transform);
            eA.Transform.Children.Add(eA2.Transform);
            eA.Transform.Children.Add(eA3.Transform);

            // Create Base Asset
            var baseAsset = new EntityGroupAsset();

            baseAsset.Hierarchy.Entities.Add(new EntityDesign(eA, new EntityDesignData()));
            baseAsset.Hierarchy.Entities.Add(new EntityDesign(eA1, new EntityDesignData()));
            baseAsset.Hierarchy.Entities.Add(new EntityDesign(eA2, new EntityDesignData()));
            baseAsset.Hierarchy.Entities.Add(new EntityDesign(eA3, new EntityDesignData()));
            baseAsset.Hierarchy.RootEntities.Add(eA.Id);

            var baseAssetItem = new AssetItem("base", baseAsset);

            // Create new Base Asset
            var newBaseAsset = (EntityGroupAsset)AssetCloner.Clone(baseAsset);
            var eA4          = new Entity()
            {
                Name = "A4"
            };
            var rootInNewBase = newBaseAsset.Hierarchy.Entities[newBaseAsset.Hierarchy.RootEntities.First()];

            var eA2InNewBaseTransform = rootInNewBase.Entity.Transform.Children.FirstOrDefault(item => item.Entity.Id == eA2.Id);

            Assert.NotNull(eA2InNewBaseTransform);

            // Add EA4 with link to EA1 entity and EA2 component
            var testComponent = new TestEntityComponent
            {
                EntityLink = eA4,
            };

            eA2InNewBaseTransform.Entity.Add(testComponent);
            newBaseAsset.Hierarchy.Entities.Add(new EntityDesign(eA4, new EntityDesignData()));
            rootInNewBase.Entity.Transform.Children.Add(eA4.Transform);

            // Create new Asset (from base)
            var newAsset = (EntityGroupAsset)baseAssetItem.CreateChildAsset();

            // Merge entities (NOTE: it is important to clone baseAsset/newBaseAsset)
            var result = newAsset.Merge((EntityGroupAssetBase)AssetCloner.Clone(baseAsset), (EntityGroupAssetBase)AssetCloner.Clone(newBaseAsset), null);

            Assert.False(result.HasErrors);

            Assert.AreEqual(1, newAsset.Hierarchy.RootEntities.Count);
            Assert.AreEqual(5, newAsset.Hierarchy.Entities.Count); // EA, EA1', EA2', EA3', EA4'

            var rootEntity = newAsset.Hierarchy.Entities[newAsset.Hierarchy.RootEntities.First()];

            Assert.AreEqual(4, rootEntity.Entity.Transform.Children.Count);

            var eA1Merged = rootEntity.Entity.Transform.Children[0].Entity;
            var eA2Merged = rootEntity.Entity.Transform.Children[1].Entity;
            var eA4Merged = rootEntity.Entity.Transform.Children[3].Entity;

            Assert.AreEqual("A1", eA1Merged.Name);
            Assert.AreEqual("A2", eA2Merged.Name);
            Assert.AreEqual("A3", rootEntity.Entity.Transform.Children[2].Entity.Name);
            Assert.AreEqual("A4", eA4Merged.Name);

            var testComponentMerged = eA2Merged.Get <TestEntityComponent>();

            Assert.NotNull(testComponentMerged);

            Assert.AreEqual(eA4Merged, testComponentMerged.EntityLink);
        }
示例#26
0
        /// <summary>
        /// Clones a sub-hierarchy of a composite hierarchical asset.
        /// </summary>
        /// <param name="sourceNodeContainer">The container in which are the nodes of the hierarchy to clone, used to extract metadata (overrides, etc.) if needed.</param>
        /// <param name="targetNodeContainer">The container in which the nodes of the cloned hierarchy should be created, used to re-apply metadata (overrides, etc.) if needed.</param>
        /// <param name="asset">The asset from which to clone sub-hierarchies.</param>
        /// <param name="sourceRootIds">The ids that are the roots of the sub-hierarchies to clone.</param>
        /// <param name="flags">The flags customizing the cloning operation.</param>
        /// <param name="idRemapping">A dictionary containing the remapping of <see cref="IIdentifiable.Id"/> if <see cref="AssetClonerFlags.GenerateNewIdsForIdentifiableObjects"/> has been passed to the cloner.</param>
        /// <returns>A <see cref="AssetCompositeHierarchyData{TAssetPartDesign, TAssetPart}"/> corresponding to the cloned parts.</returns>
        /// <remarks>The parts passed to this methods must be independent in the hierarchy.</remarks>
        public static AssetCompositeHierarchyData <TAssetPartDesign, TAssetPart> CloneSubHierarchies([NotNull] AssetNodeContainer sourceNodeContainer, [NotNull] AssetNodeContainer targetNodeContainer,
                                                                                                     [NotNull] AssetCompositeHierarchy <TAssetPartDesign, TAssetPart> asset, [NotNull] IEnumerable <Guid> sourceRootIds, SubHierarchyCloneFlags flags, [NotNull] out Dictionary <Guid, Guid> idRemapping)
        {
            if (sourceNodeContainer == null)
            {
                throw new ArgumentNullException(nameof(sourceNodeContainer));
            }
            if (targetNodeContainer == null)
            {
                throw new ArgumentNullException(nameof(targetNodeContainer));
            }
            if (asset == null)
            {
                throw new ArgumentNullException(nameof(asset));
            }
            if (sourceRootIds == null)
            {
                throw new ArgumentNullException(nameof(sourceRootIds));
            }

            // Extract the actual sub hierarchies to clone from the asset into a new instance of AssetCompositeHierarchyData
            var subTreeHierarchy = new AssetCompositeHierarchyData <TAssetPartDesign, TAssetPart>();

            foreach (var rootId in sourceRootIds)
            {
                if (!asset.Hierarchy.Parts.ContainsKey(rootId))
                {
                    throw new ArgumentException(@"The source root parts must be parts of this asset.", nameof(sourceRootIds));
                }

                subTreeHierarchy.RootParts.Add(asset.Hierarchy.Parts[rootId].Part);

                subTreeHierarchy.Parts.Add(asset.Hierarchy.Parts[rootId]);
                foreach (var subTreePart in asset.EnumerateChildParts(asset.Hierarchy.Parts[rootId].Part, true))
                {
                    subTreeHierarchy.Parts.Add(asset.Hierarchy.Parts[subTreePart.Id]);
                }
            }

            var assetType = asset.GetType();

            // Create a new empty asset of the same type, and assign the sub hierachies to clone to it
            var cloneAsset = (AssetCompositeHierarchy <TAssetPartDesign, TAssetPart>)Activator.CreateInstance(assetType);

            cloneAsset.Hierarchy = subTreeHierarchy;
            var assetDefinition = AssetQuantumRegistry.GetDefinition(assetType);

            // We get the node corresponding to the new asset in the source NodeContainer, to be able to generate metadata (overrides, object references) needed for cloning.
            var rootNode           = sourceNodeContainer.GetOrCreateNode(cloneAsset);
            var externalReferences = ExternalReferenceCollector.GetExternalReferences(assetDefinition, rootNode);
            var overrides          = (flags & SubHierarchyCloneFlags.RemoveOverrides) == 0 ? GenerateOverridesForSerialization(rootNode) : null;

            // Now we ready to clone, let's just translate the flags and pass everything to the asset cloner.
            var clonerFlags = AssetClonerFlags.None;

            if ((flags & SubHierarchyCloneFlags.GenerateNewIdsForIdentifiableObjects) != 0)
            {
                clonerFlags |= AssetClonerFlags.GenerateNewIdsForIdentifiableObjects;
            }
            if ((flags & SubHierarchyCloneFlags.CleanExternalReferences) != 0)
            {
                clonerFlags |= AssetClonerFlags.ClearExternalReferences;
            }
            // We don't need to clone the asset itself, just the hierarchy. The asset itself is just useful so the property graph is in a normal context to do what we need.
            var clonedHierarchy = AssetCloner.Clone(subTreeHierarchy, clonerFlags, externalReferences, out idRemapping);

            if ((flags & SubHierarchyCloneFlags.RemoveOverrides) == 0)
            {
                // We need to propagate the override information to the nodes of the cloned objects into the target node container.
                // Let's reuse our temporary asset, and get its node in the target node container.
                rootNode = targetNodeContainer.GetOrCreateNode(cloneAsset);
                // Replace the initial hierarchy by the cloned one (through the Update method, in case the target container is the same as the source one).
                rootNode[nameof(AssetCompositeHierarchy <TAssetPartDesign, TAssetPart> .Hierarchy)].Update(clonedHierarchy);
                // Remap the paths to overriden properties in case we generated new ids for identifiable objects.
                AssetCloningHelper.RemapIdentifiablePaths(overrides, idRemapping);
                // Finally apply the overrides that come from the source parts.
                ApplyOverrides((IAssetNode)rootNode, overrides);
            }

            return(clonedHierarchy);
        }
示例#27
0
        public void TestMergeSimpleWithBasePartsAndLinksForChildren()
        {
            // Similar to TestMergeSimpleWithBasePartsAndLinks, but perform merge on Entity.Transform.Children instead
            // Also Check that an asset that was removed is not added and links are actually removed as well

            // part1:                part2:                  newAsset (BaseParts: part1):       newAssetMerged (BaseParts: part2):
            // ERoot                 ERoot                   ERoot1                             ERoot1
            //   EA                    EA                      EA1 (base: EA)                     EA1' (base: EA)
            //   EB                    EB                      EB1 (base: EB)                     EB1' (base: EB)
            //   EC + link: EA         EC + link: EA           EC1 (base: EC) + link: EA1         EC1' (base: EC) + link: EA1'
            //                         ED + link: EB                                              ED1' (base: ED) + link: EB1'
            //                                               ERoot2                             ERoot2
            //                                                 EA2 (base: EA)                     EA2' (base: EA)
            //
            //                                                 EC2 (base: EC) + link: EA2         EC2' (base: EC) + link: EA2'
            //                                                                                    ED2' (base: ED) + noLink
            var eRoot   = new Entity("Root");
            var entityA = new Entity()
            {
                Name = "A"
            };
            var entityB = new Entity()
            {
                Name = "B"
            };
            var entityC = new Entity()
            {
                Name = "C"
            };

            // EC + link: EA
            entityC.Add(new TestEntityComponent()
            {
                EntityLink = entityA
            });
            eRoot.Transform.Children.Add(entityA.Transform);
            eRoot.Transform.Children.Add(entityB.Transform);
            eRoot.Transform.Children.Add(entityC.Transform);

            // part1 Asset
            var part1 = new EntityGroupAsset();

            part1.Hierarchy.Entities.Add(new EntityDesign(eRoot, new EntityDesignData()));
            part1.Hierarchy.Entities.Add(new EntityDesign(entityA, new EntityDesignData()));
            part1.Hierarchy.Entities.Add(new EntityDesign(entityB, new EntityDesignData()));
            part1.Hierarchy.Entities.Add(new EntityDesign(entityC, new EntityDesignData()));
            part1.Hierarchy.RootEntities.Add(eRoot.Id);

            // part2 Asset
            var part2      = (EntityGroupAsset)AssetCloner.Clone(part1);
            var eRootPart2 = part2.Hierarchy.Entities.Where(it => it.Entity.Name == "Root").Select(it => it.Entity).First();

            var entityD = new Entity()
            {
                Name = "D"
            };

            eRootPart2.Transform.Children.Add(entityD.Transform);

            // ED + link: EB
            var entityBFrom2 = part2.Hierarchy.Entities.Where(it => it.Entity.Name == "B").Select(it => it.Entity).First();

            entityD.Add(new TestEntityComponent()
            {
                EntityLink = entityBFrom2
            });
            part2.Hierarchy.Entities.Add(new EntityDesign(entityD, new EntityDesignData()));

            // originalAsset: Add a new instanceId for this part
            var asset = new EntityGroupAsset();

            // Create derived parts
            var eRoot1Asset = (EntityGroupAsset)part1.CreateChildAsset("part");
            var eRoot2Asset = (EntityGroupAsset)part1.CreateChildAsset("part");

            asset.AddPart(eRoot1Asset);
            asset.AddPart(eRoot2Asset);

            var eRoot2 = asset.Hierarchy.Entities[eRoot2Asset.Hierarchy.RootEntities[0]];

            var entityToRemove = eRoot2.Entity.Transform.Children.First(it => it.Entity.Name == "B");

            eRoot2.Entity.Transform.Children.Remove(entityToRemove);
            asset.Hierarchy.Entities.Remove(entityToRemove.Entity.Id);

            // Merge entities (NOTE: it is important to clone baseAsset/newBaseAsset)
            var entityMerge = asset.Merge(null, null, new List <AssetBase>()
            {
                new AssetBase("part", part2)
            });

            Assert.False(entityMerge.HasErrors);

            // EntityD must be now part of the new asset
            Assert.AreEqual(2, asset.Hierarchy.RootEntities.Count);
            Assert.AreEqual(9, asset.Hierarchy.Entities.Count);
            Assert.AreEqual(2, asset.Hierarchy.Entities.Count(it => it.Entity.Name == "D"));

            foreach (var entity in asset.Hierarchy.Entities.Where(it => it.Entity.Name == "D"))
            {
                // Check that we have the correct baesId and basePartInstanceId
                Assert.True(entity.Design.BasePartInstanceId.HasValue);
                Assert.True(entity.Design.BaseId.HasValue);
                Assert.AreEqual(entityD.Id, entity.Design.BaseId.Value);
            }

            var entityDesignD1 = asset.Hierarchy.Entities[asset.Hierarchy.Entities[asset.Hierarchy.RootEntities[0]].Entity.Transform.Children.Where(it => it.Entity.Name == "D").Select(it => it.Entity.Id).FirstOrDefault()];

            Assert.NotNull(entityDesignD1);
            Assert.AreEqual(eRoot1Asset.Id, entityDesignD1.Design.BasePartInstanceId);
            var testComponentD1 = entityDesignD1.Entity.Get <TestEntityComponent>();

            Assert.NotNull(testComponentD1);
            var entityB1 = asset.Hierarchy.Entities[asset.Hierarchy.RootEntities[0]].Entity.Transform.Children.Where(it => it.Entity.Name == "B").Select(it => it.Entity).First();

            Assert.AreEqual(entityB1, testComponentD1.EntityLink);

            var entityDesignD2 = asset.Hierarchy.Entities[asset.Hierarchy.Entities[asset.Hierarchy.RootEntities[1]].Entity.Transform.Children.Where(it => it.Entity.Name == "D").Select(it => it.Entity.Id).FirstOrDefault()];

            Assert.NotNull(entityDesignD2);
            Assert.AreEqual(eRoot2Asset.Id, entityDesignD2.Design.BasePartInstanceId);
            var testComponentD2 = entityDesignD2.Entity.Get <TestEntityComponent>();

            Assert.NotNull(testComponentD2);
            Assert.AreEqual(null, testComponentD2.EntityLink);
        }
示例#28
0
        public void TestListDiffWithIdsOrderChanged()
        {
            var baseAsset = new TestDiffAsset()
            {
                Name = "Red", Value = 1
            };

            baseAsset.List.Add(new DiffComponent()
            {
                Name = "Test1", Position = new Vector4(1, 0, 0, 0)
            });
            baseAsset.List.Add(new DiffComponent()
            {
                Name = "Test2", Position = new Vector4(1, 0, 0, 0)
            });
            baseAsset.List.Add(new DiffComponent()
            {
                Name = "Test3", Position = new Vector4(1, 0, 0, 0)
            });

            var newBaseAsset = (TestDiffAsset)AssetCloner.Clone(baseAsset);

            var baseItem = new AssetItem("/base", baseAsset);

            var childAsset = (TestDiffAsset)baseItem.CreateChildAsset();

            // Swap elements in child asset
            var temp = childAsset.List[0];

            childAsset.List[0]      = childAsset.List[1];
            childAsset.List[1]      = temp;
            childAsset.List[0].Name = "Test21";

            // Make New on Name value on first element
            var objDesc    = TypeDescriptorFactory.Default.Find(typeof(DiffComponent));
            var memberDesc = objDesc.Members.First(t => t.Name == "Name");

            childAsset.List[0].SetOverride(memberDesc, OverrideType.New);

            // Perform the diff
            var diff = new AssetDiff(baseAsset, childAsset, newBaseAsset)
            {
                UseOverrideMode = true
            };

            var diffResult = diff.Compute();

            var diffResultStripped = diffResult.FindLeafDifferences().ToList();

            // Expecting only one field to be merged from asset1 (the new on Name property)
            var mergeFromAsset1 = diffResultStripped.Where(item => item.ChangeType == Diff3ChangeType.MergeFromAsset1).ToList();

            Assert.AreEqual(1, mergeFromAsset1.Count);
            var nameMember = mergeFromAsset1[0].Asset1Node as DataVisitMember;

            Assert.NotNull(nameMember);
            Assert.AreEqual("Name", nameMember.MemberDescriptor.Name);

            // Check that DiffComponent are swapped for Asset1 but diff is able to recover this
            foreach (var node in diffResultStripped.Where(item => item.BaseNode.Parent.Instance is DiffComponent))
            {
                var base1  = (DiffComponent)node.BaseNode.Parent.Instance;
                var asset1 = (DiffComponent)node.Asset1Node.Parent.Instance;
                var asset2 = (DiffComponent)node.Asset2Node.Parent.Instance;

                var baseIndex   = baseAsset.List.IndexOf(base1);
                var asset1Index = childAsset.List.IndexOf(asset1);
                var asset2Index = newBaseAsset.List.IndexOf(asset2);

                Assert.AreEqual(baseIndex, asset2Index);
                switch (baseIndex)
                {
                // element 0 and 1 are swapped
                case 0:
                    Assert.AreEqual(1, asset1Index);
                    break;

                case 1:
                    Assert.AreEqual(0, asset1Index);
                    break;

                default:
                    Assert.AreEqual(baseIndex, asset1Index);
                    break;
                }
            }
        }
示例#29
0
        public void TestMergeSimpleHierarchy()
        {
            // Test merging a simple Entity Asset that has 3 entities
            //
            // base: EA, EB, EC
            // newBase: EA, EB, EC, ED
            // newAsset: EA, EB, EC
            //
            // Result Merge: EA, EB, EC, ED

            var entityA = new Entity()
            {
                Name = "A"
            };
            var entityB = new Entity()
            {
                Name = "B"
            };
            var entityC = new Entity()
            {
                Name = "C"
            };

            // Create Base Asset
            var baseAsset = new EntityGroupAsset();

            baseAsset.Hierarchy.Entities.Add(new EntityDesign(entityA, new EntityDesignData()));
            baseAsset.Hierarchy.Entities.Add(new EntityDesign(entityB, new EntityDesignData()));
            baseAsset.Hierarchy.Entities.Add(new EntityDesign(entityC, new EntityDesignData()));
            baseAsset.Hierarchy.RootEntities.Add(entityA.Id);
            baseAsset.Hierarchy.RootEntities.Add(entityB.Id);
            baseAsset.Hierarchy.RootEntities.Add(entityC.Id);

            var baseAssetItem = new AssetItem("base", baseAsset);

            // Create new Base Asset
            var entityD = new Entity()
            {
                Name = "D"
            };
            var newBaseAsset = (EntityGroupAsset)AssetCloner.Clone(baseAsset);

            newBaseAsset.Hierarchy.Entities.Add(new EntityDesign(entityD, new EntityDesignData()));
            newBaseAsset.Hierarchy.RootEntities.Add(entityD.Id);

            // Create new Asset (from base)
            var newAsset = (EntityGroupAsset)baseAssetItem.CreateChildAsset();

            // Merge entities (NOTE: it is important to clone baseAsset/newBaseAsset)
            var result = newAsset.Merge((EntityGroupAssetBase)AssetCloner.Clone(baseAsset), (EntityGroupAssetBase)AssetCloner.Clone(newBaseAsset), null);

            Assert.False(result.HasErrors);

            // Both root and entities must be the same
            Assert.AreEqual(4, newAsset.Hierarchy.RootEntities.Count);
            Assert.AreEqual(4, newAsset.Hierarchy.Entities.Count);

            // All entities must have a base value
            Assert.True(newAsset.Hierarchy.Entities.All(item => item.Design.BaseId.HasValue));

            var entityAInNewAsset = newAsset.Hierarchy.Entities.Where(item => item.Design.BaseId.Value == entityA.Id).Select(item => item.Entity).FirstOrDefault();

            Assert.NotNull(entityAInNewAsset);
            var entityBInNewAsset = newAsset.Hierarchy.Entities.Where(item => item.Design.BaseId.Value == entityB.Id).Select(item => item.Entity).FirstOrDefault();

            Assert.NotNull(entityBInNewAsset);
            var entityCInNewAsset = newAsset.Hierarchy.Entities.Where(item => item.Design.BaseId.Value == entityC.Id).Select(item => item.Entity).FirstOrDefault();

            Assert.NotNull(entityCInNewAsset);

            var entityDInNewAsset = newAsset.Hierarchy.Entities.Where(item => item.Design.BaseId.Value == entityD.Id).Select(item => item.Entity).FirstOrDefault();

            Assert.NotNull(entityDInNewAsset);

            // Hierarchy must be: EA, EB, EC, ED
            Assert.AreEqual(entityAInNewAsset.Id, newAsset.Hierarchy.RootEntities[0]);
            Assert.AreEqual(entityBInNewAsset.Id, newAsset.Hierarchy.RootEntities[1]);
            Assert.AreEqual(entityCInNewAsset.Id, newAsset.Hierarchy.RootEntities[2]);
            Assert.AreEqual(entityDInNewAsset.Id, newAsset.Hierarchy.RootEntities[3]);
        }
示例#30
0
        protected override void Compile(AssetCompilerContext context, AssetItem assetItem, string targetUrlInStorage, AssetCompilerResult result)
        {
            var   asset             = (SpriteFontAsset)assetItem.Asset;
            UFile assetAbsolutePath = assetItem.FullPath;
            var   colorSpace        = context.GetColorSpace();

            if (asset.FontType is SignedDistanceFieldSpriteFontType)
            {
                var fontTypeSDF = asset.FontType as SignedDistanceFieldSpriteFontType;

                // copy the asset and transform the source and character set file path to absolute paths
                var assetClone     = AssetCloner.Clone(asset);
                var assetDirectory = assetAbsolutePath.GetParent();
                assetClone.FontSource    = asset.FontSource;
                fontTypeSDF.CharacterSet = !string.IsNullOrEmpty(fontTypeSDF.CharacterSet) ? UPath.Combine(assetDirectory, fontTypeSDF.CharacterSet) : null;

                result.BuildSteps = new AssetBuildStep(assetItem)
                {
                    new SignedDistanceFieldFontCommand(targetUrlInStorage, assetClone)
                };
            }
            else
            if (asset.FontType is RuntimeRasterizedSpriteFontType)
            {
                UFile fontPathOnDisk = asset.FontSource.GetFontPath(result);
                if (fontPathOnDisk == null)
                {
                    result.Error($"Runtime rasterized font compilation failed. Font {asset.FontSource.GetFontName()} was not found on this machine.");
                    result.BuildSteps = new AssetBuildStep(assetItem)
                    {
                        new FailedFontCommand()
                    };
                    return;
                }

                var fontImportLocation = FontHelper.GetFontPath(asset.FontSource.GetFontName(), asset.FontSource.Style);

                result.BuildSteps = new AssetBuildStep(assetItem)
                {
                    new ImportStreamCommand {
                        SourcePath = fontPathOnDisk, Location = fontImportLocation
                    },
                    new RuntimeRasterizedFontCommand(targetUrlInStorage, asset)
                };
            }
            else
            {
                var fontTypeStatic = asset.FontType as OfflineRasterizedSpriteFontType;
                if (fontTypeStatic == null)
                {
                    throw new ArgumentException("Tried to compile a non-offline rasterized sprite font with the compiler for offline resterized fonts!");
                }

                // copy the asset and transform the source and character set file path to absolute paths
                var assetClone     = AssetCloner.Clone(asset);
                var assetDirectory = assetAbsolutePath.GetParent();
                assetClone.FontSource       = asset.FontSource;
                fontTypeStatic.CharacterSet = !string.IsNullOrEmpty(fontTypeStatic.CharacterSet) ? UPath.Combine(assetDirectory, fontTypeStatic.CharacterSet): null;

                result.BuildSteps = new AssetBuildStep(assetItem)
                {
                    new OfflineRasterizedFontCommand(targetUrlInStorage, assetClone, colorSpace)
                };
            }
        }