/// <summary> /// Initializes a new instance of the <see cref="AssetToImportMerge"/> class. /// </summary> /// <param name="previousItem">The previous item.</param> /// <param name="diff">The difference.</param> /// <param name="mergePreviewResult">The merge preview result.</param> internal AssetToImportMerge(AssetItem previousItem, AssetDiff diff, MergeResult mergePreviewResult) { PreviousItem = previousItem; this.Diff = diff; this.MergePreviewResult = mergePreviewResult; DependencyGroups = new List<AssetToImportMergeGroup>(); }
/// <summary> /// Initializes a new instance of the <see cref="AssetToImportMerge"/> class. /// </summary> /// <param name="previousItem">The previous item.</param> /// <param name="diff">The difference.</param> /// <param name="mergePreviewResult">The merge preview result.</param> internal AssetToImportMerge(AssetItem previousItem, AssetDiff diff, MergeResult mergePreviewResult) { PreviousItem = previousItem; this.Diff = diff; this.MergePreviewResult = mergePreviewResult; DependencyGroups = new List <AssetToImportMergeGroup>(); }
public void TestNoChanges() { 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(); var diff = new AssetDiff(baseAsset, childAsset, newBaseAsset) { UseOverrideMode = true }; var diffResult = diff.Compute(); var diffResultStripped = diffResult.FindLeafDifferences().ToList(); // 6: BuildOrder+Name+Value+(Dynamic: Text+Text2+Text3) Assert.AreEqual(6, diffResultStripped.Count); // Check that everything is merging from asset2 Assert.True(diffResultStripped.All(node => node.ChangeType == Diff3ChangeType.MergeFromAsset2)); }
public void TestChangeOverrideToBaseSealed() { var baseAsset = new TestDiffAsset() { Name = "Red", Value = 1 }; var newBaseAsset = (TestDiffAsset)AssetCloner.Clone(baseAsset); newBaseAsset.Value = 3; var baseItem = new AssetItem("/base", baseAsset); var childAsset = (TestDiffAsset)baseItem.CreateChildAsset(); // Change base: Name to Base|Sealed // This should result into a reset of the value overriden in child // Make New on Name value on first element var objDesc = TypeDescriptorFactory.Default.Find(typeof(TestDiffAsset)); var memberDesc = objDesc.Members.First(t => t.Name == "Value"); newBaseAsset.SetOverride(memberDesc, OverrideType.Base | OverrideType.Sealed); var diff = new AssetDiff(baseAsset, childAsset, newBaseAsset) { UseOverrideMode = true }; var diffResult = diff.Compute(); // Check that merged result on Dynamic property is instance from asset2 var mergeResult = AssetMerge.Merge(diff, AssetMergePolicies.MergePolicyAsset2AsNewBaseOfAsset1); Assert.AreEqual(3, childAsset.Value); // Value is coming from base Assert.AreEqual(OverrideType.Base | OverrideType.Sealed, childAsset.GetOverride(memberDesc)); // Value is coming from base }
public void TestMergePropertyContainer() { var baseDic = new ObjectWithPropertyContainer(); var newDic = new ObjectWithPropertyContainer(); var newBaseDic = new ObjectWithPropertyContainer() { Items = new PropertyContainer() { { DiffComponent.Key, new DiffComponent() { Name = "NewComponent" } }, } }; 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(1, newDic.Items.Count); }
/// <summary> /// This method is responsible for merging the hierarchy. /// </summary> private void MergeHierarchy() { if (baseAsset != null && newBaseAsset != null) { var diff = new AssetDiff(baseAsset.Hierarchy.RootEntities, newAsset.Hierarchy.RootEntities, newBaseAsset.Hierarchy.RootEntities) { UseOverrideMode = true, }; // Merge collections var localResult = AssetMerge.Merge(diff, AssetMergePolicies.MergePolicyAsset2AsNewBaseOfAsset1); localResult.CopyTo(result); } // Add known entities in hierarchy var newHierarchy = newAsset.Hierarchy; // Add entities coming from parts that are roots newHierarchy.RootEntities.AddRange(rootEntitiesToAdd); foreach (var rootEntity in newHierarchy.RootEntities) { entitiesInHierarchy.Add(rootEntity); } // Process hierarchy level by level // This way, we give higher importance to top levels var entityIdsToProcess = new List <Guid>(newHierarchy.RootEntities); while (entityIdsToProcess.Count > 0) { entityIdsToProcess = MergeHierarchyByLevel(entityIdsToProcess); } }
public void TestListWithIdsNoConflicts() { 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(); var diff = new AssetDiff(baseAsset, childAsset, newBaseAsset) { UseOverrideMode = true }; var diffResult = diff.Compute(); var diffResultStripped = diffResult.FindLeafDifferences().ToList(); // Expecting only 2 diff from TestDiffAsset (3 properties + BuildOrder) Assert.AreEqual(4, diffResultStripped.Where(item => item.BaseNode.Parent?.Instance is TestDiffAsset).Count()); // Expecting 6 diffs for DiffComponent (3 elements, 5 properties (Name + Vector4)) Assert.AreEqual(3 * 5, diffResultStripped.Where(item => item.BaseNode.Parent?.Instance is DiffComponent || item.BaseNode.Parent?.Parent?.Instance is DiffComponent).Count()); // All changes must be from asset2 (considered as new base), as everything is setting base Assert.True(diffResultStripped.All(item => item.ChangeType == Diff3ChangeType.MergeFromAsset2)); 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, asset1Index); Assert.AreEqual(baseIndex, asset2Index); } }
/// <summary> /// Merge an asset with its base, and new base and parts into this instance. /// </summary> /// <param name="baseAsset">A copy of the base asset. Can be null if no base asset for newAsset</param> /// <param name="newBase">A copy of the next base asset. Can be null if no base asset for newAsset.</param> /// <param name="newBaseParts">A copy of the new base parts</param> /// <param name="debugLocation">The location of the asset being merged, used only for debug/log purpose</param> /// <returns>The result of the merge</returns> /// <remarks>The this instance is not used by this method.</remarks> public virtual MergeResult Merge(Asset baseAsset, Asset newBase, List <AssetBase> newBaseParts, UFile debugLocation = null) { var diff = new AssetDiff(baseAsset, this, newBase) { UseOverrideMode = true }; return(AssetMerge.Merge(diff, AssetMergePolicies.MergePolicyAsset2AsNewBaseOfAsset1)); }
public void TestListWithIdsChangeType() { 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) }); // Change type of 2nd element in newBase list var newBaseAsset = (TestDiffAsset)AssetCloner.Clone(baseAsset); newBaseAsset.List[1] = new DiffComponentSub() { 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 diffList = diffResult.Members.First(node => ((DataVisitMember)node.Asset1Node).MemberDescriptor.Name == "List"); // Check that we have only 3 items Assert.AreEqual(3, diffList.Items.Count); Assert.AreEqual(Diff3ChangeType.MergeFromAsset2, diffList.Items[1].ChangeType); var mergeResult = AssetMerge.Merge(diff, AssetMergePolicies.MergePolicyAsset2AsNewBaseOfAsset1); Assert.False(mergeResult.HasErrors); Assert.AreEqual(3, childAsset.List.Count); Assert.AreEqual("Test1", childAsset.List[0].Name); Assert.True(childAsset.List[1] is DiffComponentSub); Assert.AreEqual("Test3", childAsset.List[2].Name); }
private List <Guid> MergeHierarchyByLevel(List <Guid> entityIds) { var nextEntityIds = new List <Guid>(); foreach (var entityId in entityIds) { var remap = newEntities[new GroupPartKey(null, entityId)]; var entity = remap.EntityDesign.Entity; // If we have a base/newbase, we can 3-ways merge lists if (remap.Base != null && remap.NewBase != null) { var diff = new AssetDiff(remap.Base.Children, remap.Children, remap.NewBase.Children) { UseOverrideMode = true, }; // Perform a diff only on the list order but not on the components themselves diff.CustomVisitorsBase.Add(new SingleLevelVisitor(typeof(TransformComponent), false, -1)); diff.CustomVisitorsAsset1.Add(new SingleLevelVisitor(typeof(TransformComponent), false, -1)); diff.CustomVisitorsAsset2.Add(new SingleLevelVisitor(typeof(TransformComponent), false, -1)); // Merge assets var localResult = AssetMerge.Merge(diff, AssetMergePolicies.MergePolicyAsset2AsNewBaseOfAsset1); localResult.CopyTo(result); } // Popup the children remap.PopChildren(); // For each child, add them to the list of entities in hierarchy and that we will // process them in the next round for (int i = 0; i < entity.Transform.Children.Count; i++) { var transformChild = entity.Transform.Children[i]; var subEntityId = transformChild.Entity.Id; if (entitiesInHierarchy.Add(subEntityId)) { nextEntityIds.Add(subEntityId); } else { // The entity was already in the hierarchy, so we remove them from this one. entity.Transform.Children.RemoveAt(i); i--; } } } return(nextEntityIds); }
public void TestMergeListGuidsWithSwapItems() { var item0 = new Guid("9a656db2-d387-4805-a18d-7727d26c0a7a"); var item1 = new Guid("3d22a49d-d891-451f-8e2d-f7cabb11a602"); var item2 = new Guid("3a0c78e7-a961-48ac-870f-3a8cdc6b2c4b"); var newItem = new Guid("481331cc-b3ea-4d48-bdb6-f7741d853eaf"); var baseList = new List <Guid>() { item0, item1, item2, }; var asset1List = new List <Guid>() { item0, item1, item2, newItem, // new Item from 1 }; var asset2List = new List <Guid>() { // new Guid("9a656db2-d387-4805-a18d-7727d26c0a7a"), Item deleted item2, // Item[2] -> Item[0] item1, // Item[1] -> Item[1] }; // Final list must be: item2, item1, newItem var diff = new AssetDiff(AssetCloner.Clone(baseList), asset1List, AssetCloner.Clone(asset2List)) { UseOverrideMode = true }; var result = AssetMerge.Merge(diff, AssetMergePolicies.MergePolicyAsset2AsNewBaseOfAsset1); Assert.False(result.HasErrors); Assert.AreEqual(3, asset1List.Count); Assert.AreEqual(item2, asset1List[0]); Assert.AreEqual(item1, asset1List[1]); Assert.AreEqual(newItem, asset1List[2]); }
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); }
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); }
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); }
public void TestChangeOverrideToBaseSealed() { var baseAsset = new TestDiffAsset() { Name = "Red", Value = 1 }; var newBaseAsset = (TestDiffAsset)AssetCloner.Clone(baseAsset); newBaseAsset.Value = 3; var baseItem = new AssetItem("/base", baseAsset); var childAsset = (TestDiffAsset)baseItem.CreateChildAsset(); // Change base: Name to Base|Sealed // This should result into a reset of the value overriden in child // Make New on Name value on first element var objDesc = TypeDescriptorFactory.Default.Find(typeof(TestDiffAsset)); var memberDesc = objDesc.Members.First(t => t.Name == "Value"); newBaseAsset.SetOverride(memberDesc, OverrideType.Base|OverrideType.Sealed); var diff = new AssetDiff(baseAsset, childAsset, newBaseAsset) { UseOverrideMode = true }; var diffResult = diff.Compute(); // Check that merged result on Dynamic property is instance from asset2 var mergeResult = AssetMerge.Merge(diff, AssetMergePolicies.MergePolicyAsset2AsNewBaseOfAsset1); Assert.AreEqual(3, childAsset.Value); // Value is coming from base Assert.AreEqual(OverrideType.Base|OverrideType.Sealed, childAsset.GetOverride(memberDesc)); // Value is coming from base }
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; } } }
public void TestListWithIdsNoConflicts() { 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(); var diff = new AssetDiff(baseAsset, childAsset, newBaseAsset) { UseOverrideMode = true }; var diffResult = diff.Compute(); var diffResultStripped = diffResult.FindLeafDifferences().ToList(); // Expecting only 2 diff from TestDiffAsset (3 properties + BuildOrder) Assert.AreEqual(4, diffResultStripped.Where(item => item.BaseNode.Parent?.Instance is TestDiffAsset).Count()); // Expecting 6 diffs for DiffComponent (3 elements, 5 properties (Name + Vector4)) Assert.AreEqual(3 * 5, diffResultStripped.Where(item => item.BaseNode.Parent?.Instance is DiffComponent || item.BaseNode.Parent?.Parent?.Instance is DiffComponent).Count()); // All changes must be from asset2 (considered as new base), as everything is setting base Assert.True(diffResultStripped.All(item => item.ChangeType == Diff3ChangeType.MergeFromAsset2)); 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, asset1Index); Assert.AreEqual(baseIndex, asset2Index); } }
public void TestMergeListGuids2() { var item0 = new Guid("9a656db2-d387-4805-a18d-7727d26c0a7a"); var item1 = new Guid("3d22a49d-d891-451f-8e2d-f7cabb11a602"); var item2 = new Guid("3a0c78e7-a961-48ac-870f-3a8cdc6b2c4b"); var newItem = new Guid("481331cc-b3ea-4d48-bdb6-f7741d853eaf"); var baseList = new List<Guid>() { item0, item1, item2, }; var asset1List = new List<Guid>() { item0, item1, item2, newItem, }; var asset2List = new List<Guid>() { item0, item2, }; // Final list must be: item0, item2, newItem var diff = new AssetDiff(AssetCloner.Clone(baseList), asset1List, AssetCloner.Clone(asset2List)) { UseOverrideMode = true }; var result = AssetMerge.Merge(diff, AssetMergePolicies.MergePolicyAsset2AsNewBaseOfAsset1); Assert.False(result.HasErrors); Assert.AreEqual(3, asset1List.Count); Assert.AreEqual(item0, asset1List[0]); Assert.AreEqual(item2, asset1List[1]); Assert.AreEqual(newItem, asset1List[2]); }
public void TestMergePropertyContainer() { var baseDic = new ObjectWithPropertyContainer(); var newDic = new ObjectWithPropertyContainer(); var newBaseDic = new ObjectWithPropertyContainer() { Items = new PropertyContainer() { { DiffComponent.Key, new DiffComponent() { Name = "NewComponent"} }, } }; 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(1, newDic.Items.Count); }
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); }
/// <summary> /// Merges the specified assets from <c>base</c> and <c>from2</c> into <c>from1</c>. /// </summary> /// <param name="assetDiff">A precomputed asset difference.</param> /// <param name="mergePolicy">The merge policy.</param> /// <param name="previewOnly">if set to <c>true</c> then the merge will not change the object.</param> /// <returns>MergePreviewResult.</returns> /// <exception cref="System.ArgumentNullException">assetDiff /// or /// mergePolicy</exception> public static MergeResult Merge(AssetDiff assetDiff, MergePolicyDelegate mergePolicy, bool previewOnly = false) { if (assetDiff == null) throw new ArgumentNullException("assetDiff"); if (mergePolicy == null) throw new ArgumentNullException("mergePolicy"); var allDiffs = assetDiff.Compute(); var diff3 = allDiffs.FindDifferences().ToList(); var result = new MergeResult(assetDiff.Asset1); // Try to merge foreach (var diff3Node in diff3) { Diff3ChangeType changeType; try { changeType = mergePolicy(diff3Node); if (changeType >= Diff3ChangeType.Conflict) { result.Error("Unresolved conflict [{0}] on node [{1}/{2}/{3}]", diff3Node.ChangeType, diff3Node.BaseNode, diff3Node.Asset1Node, diff3Node.Asset2Node); continue; } // If we are in preview only mode, just skip the update if (previewOnly) { continue; } object dataInstance; bool replaceValue; switch (changeType) { case Diff3ChangeType.MergeFromAsset2: // As we are merging into asset1, the only relevant changes can only come from asset2 dataInstance = diff3Node.Asset2Node != null ? diff3Node.Asset2Node.Instance : null; replaceValue = true; break; case Diff3ChangeType.Children: MergeContainer(diff3Node, out dataInstance); replaceValue = dataInstance != null; break; default: continue; } // Sets the value on the node if (replaceValue) diff3Node.ReplaceValue(dataInstance, node => node.Asset1Node); } catch (Exception ex) { result.Error("Unexpected error while merging [{0}] on node [{1}]", ex, diff3Node.ChangeType, diff3Node.InstanceType); break; } } if (!previewOnly) { foreach (var node in allDiffs.Asset1Node.Children(node => true)) { if (node.Instance is IDiffProxy) { ((IDiffProxy)node.Instance).ApplyChanges(); } } } return result; }
/// <summary> /// Merges the specified assets from <c>base</c> and <c>from2</c> into <c>from1</c>. /// </summary> /// <param name="assetDiff">A precomputed asset difference.</param> /// <param name="mergePolicy">The merge policy.</param> /// <param name="previewOnly">if set to <c>true</c> then the merge will not change the object.</param> /// <returns>MergePreviewResult.</returns> /// <exception cref="System.ArgumentNullException">assetDiff /// or /// mergePolicy</exception> public static MergeResult Merge(AssetDiff assetDiff, MergePolicyDelegate mergePolicy, bool previewOnly = false) { if (assetDiff == null) throw new ArgumentNullException("assetDiff"); if (mergePolicy == null) throw new ArgumentNullException("mergePolicy"); var allDiffs = assetDiff.Compute(); var diff3 = allDiffs.FindDifferences().ToList(); var result = new MergeResult(assetDiff.Asset1); // Try to merge foreach (var diff3Node in diff3) { Diff3ChangeType changeType; try { changeType = mergePolicy(diff3Node); if (changeType >= Diff3ChangeType.Conflict) { result.Error("Unresolved conflict [{0}] on node [{1}/{2}/{3}]", diff3Node.ChangeType, diff3Node.BaseNode, diff3Node.Asset1Node, diff3Node.Asset2Node); continue; } // If we are in preview only mode, just skip the update if (previewOnly) { continue; } object dataInstance = null; bool replaceValue = false; switch (changeType) { case Diff3ChangeType.MergeFromAsset2: // Because for collection, the merge is performed by the MergeContainer // Skip any merge for individual items, as they should have been merged by MergeContainer // TODO: This is a workaround as FindDifferences().ToList() is giving changes inside collection while we rebuild collection with MergeContainer if (diff3Node.Parent == null || diff3Node.Parent.Type != Diff3NodeType.Collection) { // As we are merging into asset1, the only relevant changes can only come from asset2 dataInstance = diff3Node.Asset2Node?.Instance; replaceValue = true; } break; case Diff3ChangeType.Children: MergeContainer(diff3Node, out dataInstance); replaceValue = dataInstance != null; break; default: continue; } // Sets the value on the node if (replaceValue) diff3Node.ReplaceValue(dataInstance, node => node.Asset1Node); // Applies the override for this node diff3Node.ApplyOverride(); } catch (Exception ex) { result.Error("Unexpected error while merging [{0}] on node [{1}]", ex, diff3Node.ChangeType, diff3Node.InstanceType); break; } } if (!previewOnly) { foreach (var node in allDiffs.Asset1Node.Children(node => true)) { if (node.Instance is IDiffProxy) { ((IDiffProxy)node.Instance).ApplyChanges(); } } } return result; }
private List <Guid> MergeHierarchyByLevel(List <Guid> entityIds) { var nextEntityIds = new List <Guid>(); foreach (var entityId in entityIds) { var remap = newEntities[new GroupPartKey(null, entityId)]; var entity = remap.EntityDesign.Entity; // If we have a base/newbase, we can 3-ways merge lists if (remap.Base != null) { // Build a list of Entities Ids for the BaseEntity.Transform.Children remapped to the new entities (using the BasePartInstanceId of the entity being processed) var baseChildrenId = new List <Guid>(); var basePartInstanceId = remap.EntityDesign.BasePartInstanceId; if (remap.Base.Children != null) { foreach (var transformComponent in remap.Base.Children) { BaseEntityEntry baseEntry; if (baseEntities.TryGetValue(new GroupPartKey(basePartInstanceId, transformComponent.Entity.Id), out baseEntry) && baseEntry.NewEntity != null) { baseChildrenId.Add(baseEntry.NewEntity.EntityDesign.Entity.Id); } } } // List of Entity ids of the NewEntity.Transform.Children var currentChildrenIds = new List <Guid>(); if (remap.Children != null) { foreach (var transformComponent in remap.Children) { currentChildrenIds.Add(transformComponent.Entity.Id); } } // Build a list of Entities Ids for the NewBaseEntity.Transform.Children remapped to the new entities (using the BasePartInstanceId of the entity being processed) var newBaseChildrenIds = new List <Guid>(); if (remap.NewBase?.Children != null) { foreach (var transformComponent in remap.NewBase.Children) { BaseEntityEntry baseEntry = null; if (newBaseEntities.TryGetValue(new GroupPartKey(basePartInstanceId, transformComponent.Entity.Id), out baseEntry) && baseEntry.NewEntity != null) { newBaseChildrenIds.Add(baseEntry.NewEntity.EntityDesign.Entity.Id); } } } // Perform a merge only if it is needed if (currentChildrenIds.Count > 0 && (baseChildrenId.Count > 0 || newBaseChildrenIds.Count > 0)) { // Perform a merge of a IDs list var diff = new AssetDiff(baseChildrenId, currentChildrenIds, newBaseChildrenIds) { UseOverrideMode = true, }; var localResult = AssetMerge.Merge(diff, AssetMergePolicies.MergePolicyAsset2AsNewBaseOfAsset1); localResult.CopyTo(result); } if (remap.Children != null) { remap.Children.Clear(); } foreach (var childId in currentChildrenIds) { NewEntityEntry newChildRemap; if (newEntities.TryGetValue(new GroupPartKey(null, childId), out newChildRemap)) { if (remap.Children == null) { remap.Children = new List <TransformComponent>(); } remap.Children.Add(newChildRemap.EntityDesign.Entity.Transform); } } } else if (remap.IsNewBase && remap.Children != null) { // If the entity is coming from NewBase, we need to transform the previous children // to the new one mapped var children = new List <TransformComponent>(remap.Children); remap.Children.Clear(); var basePartInstanceId = remap.EntityDesign.BasePartInstanceId; foreach (var transformComponent in children) { BaseEntityEntry baseToNew = null; if (newBaseEntities.TryGetValue(new GroupPartKey(basePartInstanceId, transformComponent.Entity.Id), out baseToNew) && baseToNew.NewEntity != null) { remap.Children.Add(baseToNew.NewEntity.EntityDesign.Entity.Transform); } } } // Popup the children remap.PopChildren(); // For each child, add them to the list of entities in hierarchy and that we will // process them in the next round for (int i = 0; i < entity.Transform.Children.Count; i++) { var transformChild = entity.Transform.Children[i]; var subEntityId = transformChild.Entity.Id; if (entitiesInHierarchy.Add(subEntityId)) { nextEntityIds.Add(subEntityId); } else { // The entity was already in the hierarchy, so we remove them from this one. entity.Transform.Children.RemoveAt(i); i--; } } } return(nextEntityIds); }
/// <summary> /// Merge an asset with its base, and new base and parts into this instance. /// </summary> /// <param name="baseAsset">A copy of the base asset. Can be null if no base asset for newAsset</param> /// <param name="newBase">A copy of the next base asset. Can be null if no base asset for newAsset.</param> /// <param name="newBaseParts">A copy of the new base parts</param> /// <returns>The result of the merge</returns> /// <remarks>The this instance is not used by this method.</remarks> public virtual MergeResult Merge(Asset baseAsset, Asset newBase, List<AssetBasePart> newBaseParts) { var diff = new AssetDiff(baseAsset, this, newBase) { UseOverrideMode = true }; return AssetMerge.Merge(diff, AssetMergePolicies.MergePolicyAsset2AsNewBaseOfAsset1); }
/// <summary> /// This method will merge all entities without taking into account hierarchy that will be handled by <see cref="MergeHierarchy"/> /// </summary> private void MergeEntities() { // Clear all entities newAsset.Hierarchy.Entities.Clear(); // Visit all existing entities, coming both from newAsset and new entities from newBase foreach (var entityEntry in newEntities) { var entityDesign = entityEntry.Value.EntityDesign; var newEntity = entityDesign.Entity; if (entityEntry.Value.Base != null && entityEntry.Value.NewBase != null) { var baseRemap = entityEntry.Value.Base; var newBaseRemap = entityEntry.Value.NewBase; var baseEntity = baseRemap.EntityDesign.Entity; var newBaseEntity = newBaseRemap.EntityDesign.Entity; var diff = new AssetDiff(baseEntity, newEntity, newBaseEntity) { UseOverrideMode = true, }; var previousBaseId = baseEntity.Id; var previousNewBaseId = newBaseEntity.Id; // Remap ids to new entity baseEntity.Id = newEntity.Id; newBaseEntity.Id = newEntity.Id; // For entities and components, we will visit only the members of the first level (first entity, or first component) // but not recursive one (in case a component reference another entity or component) diff.CustomVisitorsBase.Add(new SingleLevelVisitor(typeof(Entity), false)); diff.CustomVisitorsBase.Add(new SingleLevelVisitor(typeof(EntityComponent), false)); diff.CustomVisitorsAsset1.Add(new SingleLevelVisitor(typeof(Entity), false)); diff.CustomVisitorsAsset1.Add(new SingleLevelVisitor(typeof(EntityComponent), false)); diff.CustomVisitorsAsset2.Add(new SingleLevelVisitor(typeof(Entity), false)); diff.CustomVisitorsAsset2.Add(new SingleLevelVisitor(typeof(EntityComponent), false)); // Merge assets var localResult = AssetMerge.Merge(diff, AssetMergePolicies.MergePolicyAsset2AsNewBaseOfAsset1); localResult.CopyTo(result); // Merge folder // If folder was not changed compare to the base, always take the version coming from the new base, otherwise leave the modified version if (baseRemap.EntityDesign.Design.Folder == entityDesign.Design.Folder) { entityDesign.Design.Folder = newBaseRemap.EntityDesign.Design.Folder; } // Restore Ids baseEntity.Id = previousBaseId; newBaseEntity.Id = previousNewBaseId; } // Add the entity newAsset.Hierarchy.Entities.Add(entityDesign); } }
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); }