private static void CheckGenericAsset(PrefabAsset originAsset, PrefabAsset newAsset) { // Check that we have exactly the same root entities Assert.AreEqual(originAsset.Hierarchy.RootPartIds, newAsset.Hierarchy.RootPartIds); Assert.AreEqual(originAsset.Hierarchy.Parts.Count, newAsset.Hierarchy.Parts.Count); foreach (var entityDesign in originAsset.Hierarchy.Parts) { var newEntityDesign = newAsset.Hierarchy.Parts[entityDesign.Entity.Id]; Assert.NotNull(newEntityDesign); // Check properties Assert.AreEqual(entityDesign.Entity.Name, newEntityDesign.Entity.Name); Assert.AreEqual(entityDesign.Entity.Group, newEntityDesign.Entity.Group); // Check that we have the same amount of components Assert.AreEqual(entityDesign.Entity.Components.Count, newEntityDesign.Entity.Components.Count); // Check that we have the same children Assert.AreEqual(entityDesign.Entity.Transform.Children.Count, newEntityDesign.Entity.Transform.Children.Count); for (int i = 0; i < entityDesign.Entity.Transform.Children.Count; i++) { var children = entityDesign.Entity.Transform.Children[i]; var newChildren = newEntityDesign.Entity.Transform.Children[i]; // Make sure that it is the same entity id Assert.AreEqual(children.Entity.Id, newChildren.Entity.Id); // Make sure that we resolve to the global entity and not a copy Assert.True(newAsset.Hierarchy.Parts.ContainsKey(newChildren.Entity.Id)); Assert.AreEqual(newChildren.Entity, newAsset.Hierarchy.Parts[newChildren.Entity.Id].Entity); } } }
/// <inheritdoc/> protected override void ClearPartReferences(AssetCompositeHierarchyData <EntityDesign, Entity> clonedHierarchy) { // set to null reference outside of the sub-tree var tempAsset = new PrefabAsset { Hierarchy = clonedHierarchy }; tempAsset.FixupPartReferences(); }
public void TestSerializationWithBaseAndParts() { // Create an entity as in TestSerialization // Then create a derivedAsset from it // Then create a partAsset and add this partAsset as a composition to derivedAsset // Serialize and deserialize derivedAsset // Check that deserialized derivedAsset has all base/baseParts correctly serialized var originAsset = CreateOriginAsset(); var derivedAsset = (PrefabAsset)originAsset.CreateChildAsset("base"); var basePartAsset = new PrefabAsset(); var entityPart1 = new Entity() { Name = "EPart1" }; var entityPart2 = new Entity() { Name = "EPart2" }; basePartAsset.Hierarchy.Entities.Add(entityPart1); basePartAsset.Hierarchy.Entities.Add(entityPart2); basePartAsset.Hierarchy.RootEntities.Add(entityPart1.Id); basePartAsset.Hierarchy.RootEntities.Add(entityPart2.Id); // Add 2 asset parts from the same base var instance = basePartAsset.CreatePrefabInstance(derivedAsset, "part"); derivedAsset.Hierarchy.Entities.AddRange(instance.Entities); derivedAsset.Hierarchy.RootEntities.AddRange(instance.RootEntities); var instance2 = basePartAsset.CreatePrefabInstance(derivedAsset, "part"); derivedAsset.Hierarchy.Entities.AddRange(instance2.Entities); derivedAsset.Hierarchy.RootEntities.AddRange(instance2.RootEntities); using (var stream = new MemoryStream()) { AssetSerializer.Save(stream, derivedAsset); stream.Position = 0; var serializedVersion = Encoding.UTF8.GetString(stream.ToArray()); Console.WriteLine(serializedVersion); stream.Position = 0; var newAsset = (PrefabAsset)AssetSerializer.Load(stream, "xkentity"); Assert.NotNull(newAsset.Base); Assert.NotNull(newAsset.BaseParts); // We should have only 1 base part, as we created parts from the same base Assert.AreEqual(1, newAsset.BaseParts.Count); CheckAsset(derivedAsset, newAsset); CheckAsset(originAsset, (PrefabAsset)newAsset.Base.Asset); CheckGenericAsset(basePartAsset, (PrefabAsset)newAsset.BaseParts[0].Asset); } }
public void TestCreateChildAsset() { // Create an Entity child asset // base: EA, EB, EC // newAsset: EA'(base: EA), EB'(base: EB), EC'(base: EC) var entityA = new Entity() { Name = "A" }; var entityB = new Entity() { Name = "B" }; var entityC = new Entity() { Name = "C" }; // Create Base Asset var baseAsset = new PrefabAsset(); baseAsset.Hierarchy.Parts.Add(new EntityDesign(entityA)); baseAsset.Hierarchy.Parts.Add(new EntityDesign(entityB)); baseAsset.Hierarchy.Parts.Add(new EntityDesign(entityC)); baseAsset.Hierarchy.RootPartIds.Add(entityA.Id); baseAsset.Hierarchy.RootPartIds.Add(entityB.Id); baseAsset.Hierarchy.RootPartIds.Add(entityC.Id); var baseAssetItem = new AssetItem("base", baseAsset); // Create new Asset (from base) var newAsset = (PrefabAsset)baseAssetItem.CreateDerivedAsset(); // On a derive asset all entities must have a base value and base must come from baseAsset Assert.True(newAsset.Hierarchy.Parts.All(item => item.Base != null && baseAsset.Hierarchy.Parts.ContainsKey(item.Base.BasePartId))); // Verify that we have exactly the same number of entities Assert.AreEqual(baseAsset.Hierarchy.RootPartIds.Count, newAsset.Hierarchy.RootPartIds.Count); Assert.AreEqual(baseAsset.Hierarchy.Parts.Count, newAsset.Hierarchy.Parts.Count); // Verify that baseId and newId is correctly setup var entityAInNew = newAsset.Hierarchy.Parts.FirstOrDefault(item => item.Base.BasePartId == entityA.Id && item.Entity.Id != item.Base.BasePartId); Assert.NotNull(entityAInNew); var entityBInNew = newAsset.Hierarchy.Parts.FirstOrDefault(item => item.Base.BasePartId == entityB.Id && item.Entity.Id != item.Base.BasePartId); Assert.NotNull(entityBInNew); var entityCInNew = newAsset.Hierarchy.Parts.FirstOrDefault(item => item.Base.BasePartId == entityC.Id && item.Entity.Id != item.Base.BasePartId); Assert.NotNull(entityCInNew); // Verify that RootEntities are also correctly mapped Assert.AreEqual(entityAInNew.Entity.Id, newAsset.Hierarchy.RootPartIds[0]); Assert.AreEqual(entityBInNew.Entity.Id, newAsset.Hierarchy.RootPartIds[1]); Assert.AreEqual(entityCInNew.Entity.Id, newAsset.Hierarchy.RootPartIds[2]); }
private static PrefabAsset CreateOriginAsset() { // Basic test of entity serialization with links between entities (entity-entity, entity-component) // E1 // | E2 + link to E1 via TestEntityComponent // E3 // E4 + link to E3.Transform component via TestEntityComponent var originAsset = new PrefabAsset(); { var entity1 = new Entity() { Name = "E1" }; var entity2 = new Entity() { Name = "E2", Group = EntityGroup.Group1 }; // Use group property to make sure that it is properly serialized var entity3 = new Entity() { Name = "E3" }; var entity4 = new Entity() { Name = "E4", Group = EntityGroup.Group2 }; // TODO: Add script link entity1.Transform.Children.Add(entity2.Transform); // Test a link between entity1 and entity2 entity2.Add(new TestEntityComponent() { EntityLink = entity1 }); // Test a component link between entity4 and entity 3 entity4.Add(new TestEntityComponent() { EntityComponentLink = entity3.Transform }); originAsset.Hierarchy.Parts.Add(new EntityDesign(entity1)); originAsset.Hierarchy.Parts.Add(new EntityDesign(entity2)); originAsset.Hierarchy.Parts.Add(new EntityDesign(entity3)); originAsset.Hierarchy.Parts.Add(new EntityDesign(entity4)); originAsset.Hierarchy.RootPartIds.Add(entity1.Id); originAsset.Hierarchy.RootPartIds.Add(entity3.Id); originAsset.Hierarchy.RootPartIds.Add(entity4.Id); } return originAsset; }
public void TestMultiplePrefabsInheritanceAndChildren() { // The purpose of this test is to check that modifying a prefab base is correctly propagated through all // derived prefabs. We use the following scenario: // // a1: base asset // a2: inherit from a1 by composition with 2 instances (baseParts: a1 => 2 instances) // a3: inherit from a1 by composition with 1 instances (baseParts: a1 => 1 instances) // a4: inherit from a2 and a3 by composition with 1 instances for each (baseParts: a1 => 1 instance, a2 => 1 instance) // // Unlike TestMultiplePrefabsMixedInheritance, we use only inheritance by composition for this scenario to match current use cases var package = new Package(); var assetItems = package.Assets; // First we create assets with the following configuration: // a1: a2: (baseParts: a1, 2 instances) a3: (baseParts: a1) a4: (baseParts: a2 x 1, a3 x 1) // | er | er1 (base: er) | er1' (base: er) | eRoot // | ea | ea1 (base: ea) | ea1' (base: ea) | er1* (base: er) // | eb | eb1 (base: eb) | eb1' (base: eb) | ea1* (base: ea) // | ec | ec1 (base: ec) | ec1' (base: ec) | eb1* (base: eb) // | er2 (base: er) | ec1* (base: ec) // | ea2 (base: ea) | er2* (base: er) // | eb2 (base: eb) | ea2* (base: ea) // | ec2 (base: ec) | eb2* (base: eb) // | ec2* (base: ec) // | er1'* (base: er) // | ea1'* (base: ea) // | eb1'* (base: eb) // | ec1'* (base: ec) var a1 = new PrefabAsset(); var er = new Entity("er"); var ea = new Entity("ea"); var eb = new Entity("eb"); var ec = new Entity("ec"); a1.Hierarchy.Parts.Add(new EntityDesign(er)); a1.Hierarchy.Parts.Add(new EntityDesign(ea)); a1.Hierarchy.Parts.Add(new EntityDesign(eb)); a1.Hierarchy.Parts.Add(new EntityDesign(ec)); a1.Hierarchy.RootPartIds.Add(er.Id); er.AddChild(ea); er.AddChild(eb); er.AddChild(ec); assetItems.Add(new AssetItem("a1", a1)); var member = (IMemberDescriptor)TypeDescriptorFactory.Default.Find(typeof(Entity))[nameof(Entity.Name)]; var a2 = new PrefabAsset(); var a2PartInstance1 = a1.CreatePrefabInstance(a2, "a1"); foreach (var entity in a2PartInstance1.Parts) { entity.Entity.Name += "1"; } var a2PartInstance2 = a1.CreatePrefabInstance(a2, "a1"); foreach (var entity in a2PartInstance2.Parts) { entity.Entity.Name += "2"; } a2.Hierarchy.Parts.AddRange(a2PartInstance1.Parts); a2.Hierarchy.Parts.AddRange(a2PartInstance2.Parts); a2.Hierarchy.RootPartIds.AddRange(a2PartInstance1.RootPartIds); a2.Hierarchy.RootPartIds.AddRange(a2PartInstance2.RootPartIds); Assert.AreEqual(8, a2.Hierarchy.Parts.Count); Assert.AreEqual(2, a2.Hierarchy.RootPartIds.Count); assetItems.Add(new AssetItem("a2", a2)); var a3 = new PrefabAsset(); var a3PartInstance1 = a1.CreatePrefabInstance(a3, "a1"); foreach (var entity in a3PartInstance1.Parts) { entity.Entity.Name += "1'"; } a3.Hierarchy.Parts.AddRange(a3PartInstance1.Parts); a3.Hierarchy.RootPartIds.AddRange(a3PartInstance1.RootPartIds); Assert.AreEqual(4, a3.Hierarchy.Parts.Count); Assert.AreEqual(1, a3.Hierarchy.RootPartIds.Count); assetItems.Add(new AssetItem("a3", a3)); var a4 = new PrefabAsset(); var eRoot = new Entity("eRoot"); var a2PartInstance3 = a2.CreatePrefabInstance(a4, "a2"); foreach (var entity in a2PartInstance3.Parts) { entity.Entity.Name += "*"; } foreach (var entity in a2PartInstance3.Parts.Where(t => a2PartInstance3.RootPartIds.Contains(t.Entity.Id))) { eRoot.AddChild(entity.Entity); } var a3PartInstance2 = a3.CreatePrefabInstance(a4, "a3"); foreach (var entity in a3PartInstance2.Parts) { entity.Entity.Name += "*"; } a4.Hierarchy.Parts.Add(new EntityDesign(eRoot)); a4.Hierarchy.Parts.AddRange(a2PartInstance3.Parts); a4.Hierarchy.Parts.AddRange(a3PartInstance2.Parts); a4.Hierarchy.RootPartIds.Add(eRoot.Id); a4.Hierarchy.RootPartIds.AddRange(a3PartInstance2.RootPartIds); Assert.AreEqual(13, a4.Hierarchy.Parts.Count); Assert.AreEqual(2, a4.Hierarchy.RootPartIds.Count); assetItems.Add(new AssetItem("a4", a4)); Assert.True(a1.DumpTo(Console.Out, "a1 BEFORE PrefabMergeAsset")); Assert.True(a2.DumpTo(Console.Out, "a2 BEFORE PrefabMergeAsset")); Assert.True(a3.DumpTo(Console.Out, "a3 BEFORE PrefabMergeAsset")); Assert.True(a4.DumpTo(Console.Out, "a4 BEFORE PrefabMergeAsset")); // Then we simulate a concurrent change to a1 by someone that didn't have a2/a3/a4 // - Add one component to a1, linking to an existing entity ea // - Add a root entity to a1 with a link to an existing entity eb // // a1: a2: (baseParts: a1, 2 instances) a3: (baseParts: a1) a4: (baseParts: a2 x 1, a3 x 1) // | er | er1 (base: er) | er1' (base: er) | eRoot // | ea | ea1 (base: ea) | ea1' (base: ea) | er1* (base: er) // | eb | eb1 (base: eb) | eb1' (base: eb) | ea1* (base: ea) // | ec + link ea | ec1 + link ea1 (base: ec) | ec1' + link ea1' (base: ec) | eb1* (base: eb) // | ex | er2 (base: er) | ex(1') (base: ex) | ec1* + link ea1* (base: ec) // | ey + link eb | ea2 (base: ea) | ey(1') + link eb1' | er2* (base: er) // | eb2 (base: eb) | ea2* (base: ea) // | ec2 + link ea2 (base: ec) | eb2* (base: eb) // | ex(1) | ec2* + link ea2* (base: ec) // | ey(1) + link eb1 | er1'* (base: er) // | ex(2) | ea1'* (base: ea) // | ey(2) + link eb2 | eb1'* (base: eb) // | ec1'* + link ea1'* (base: ec) // | ex(1*) // | ey(1*) + link eb1* // | ex(2*) // | ey(2*) + link eb2* // | ex(1') (base: ex) // | ey(1') + link eb1'* ec.Components.Add(new TestEntityComponent() { EntityLink = ea }); var ex = new Entity("ex"); var ey = new Entity("ey"); ey.Components.Add(new TestEntityComponent() { EntityLink = eb }); ex.AddChild(ey); a1.Hierarchy.Parts.Add(new EntityDesign(ex)); a1.Hierarchy.Parts.Add(new EntityDesign(ey)); a1.Hierarchy.RootPartIds.Add(ex.Id); Assert.AreEqual(6, a1.Hierarchy.Parts.Count); Assert.AreEqual(2, a1.Hierarchy.RootPartIds.Count); // Simulates the loading of this package using (var session = new PackageSession()) { var logger = new LoggerResult(); session.AddExistingPackage(package, logger); Assert.False(logger.HasErrors); Assert.True(a1.DumpTo(Console.Out, "a1 AFTER PrefabMergeAsset")); // ------------------------------------------------ // Check for a2 // ------------------------------------------------ // a2: (baseParts: a1, 2 instances) // | er1 (base: er) // | ea1 (base: ea) // | eb1 (base: eb) // | ec1 + link ea1 (base: ec) // | er2 (base: er) // | ea2 (base: ea) // | eb2 (base: eb) // | ec2 + link ea2 (base: ec) // | ex(1) // | ey(1) + link eb1 // | ex(2) // | ey(2) + link eb2 { Assert.True(a2.DumpTo(Console.Out, "a2 AFTER PrefabMergeAsset")); Assert.AreEqual(4, a2.Hierarchy.RootPartIds.Count); Assert.True(a2.Hierarchy.Parts.All(it => it.Base != null)); // Check that we have all expected entities Assert.AreEqual(12, a2.Hierarchy.Parts.Count); var eb1 = a2.Hierarchy.Parts.FirstOrDefault(it => it.Entity.Name == "eb1")?.Entity; var eb2 = a2.Hierarchy.Parts.FirstOrDefault(it => it.Entity.Name == "eb2")?.Entity; Assert.NotNull(eb1); Assert.NotNull(eb2); // Check that we have ex and ey var exList = a2.Hierarchy.Parts.Where(it => it.Entity.Name == ex.Name).ToList(); Assert.AreEqual(2, exList.Count); // Check that both [ex] have both 1 element [ey] and the links to eb1/eb2 are correct { var expecting = new List<Entity>() { eb1, eb2 }; for (int i = 0; i < exList.Count; i++) { var ex1 = exList[i].Entity; Assert.AreEqual(1, ex1.Transform.Children.Count); var ey1 = ex1.Transform.Children[0].Entity; Assert.AreEqual(ey.Name, ey1.Name); Assert.NotNull(ey1.Get<TestEntityComponent>()); var entityLink = ey1.Get<TestEntityComponent>().EntityLink; Assert.True(expecting.Contains(entityLink)); expecting.Remove(entityLink); } } // Check link from ec1 to ea1 { var ec1 = a2.Hierarchy.Parts.FirstOrDefault(it => it.Entity.Name == "ec1")?.Entity; Assert.NotNull(ec1); var ea1 = a2.Hierarchy.Parts.FirstOrDefault(it => it.Entity.Name == "ea1")?.Entity; Assert.NotNull(ea1); Assert.NotNull(ec1.Get<TestEntityComponent>()); Assert.AreEqual(ea1, ec1.Get<TestEntityComponent>().EntityLink); } // Check link from ec2 to ea2 { var ec2 = a2.Hierarchy.Parts.FirstOrDefault(it => it.Entity.Name == "ec2")?.Entity; Assert.NotNull(ec2); var ea2 = a2.Hierarchy.Parts.FirstOrDefault(it => it.Entity.Name == "ea2")?.Entity; Assert.NotNull(ea2); Assert.NotNull(ec2.Get<TestEntityComponent>()); Assert.AreEqual(ea2, ec2.Get<TestEntityComponent>().EntityLink); } } // ------------------------------------------------ // Check for a3 // ------------------------------------------------ // a3: (baseParts: a1) // | er1' (base: er) // | ea1' (base: ea) // | eb1' (base: eb) // | ec1' + link ea1' (base: ec) // | ex1' (base: ex) // | ey1' + link eb1' { Assert.True(a3.DumpTo(Console.Out, "a3 AFTER PrefabMergeAsset")); Assert.AreEqual(2, a3.Hierarchy.RootPartIds.Count); Assert.True(a3.Hierarchy.Parts.All(it => it.Base != null)); // Check that we have all expected entities Assert.AreEqual(6, a3.Hierarchy.Parts.Count); var eb1 = a3.Hierarchy.Parts.FirstOrDefault(it => it.Entity.Name == "eb1'")?.Entity; Assert.NotNull(eb1); // Check that we have ex and ey var exList = a3.Hierarchy.Parts.Where(it => it.Entity.Name == ex.Name).ToList(); Assert.AreEqual(1, exList.Count); // Check that [ex] have 1 element [ey] and the link to eb1 is correct { var ex1 = exList[0].Entity; Assert.AreEqual(1, ex1.Transform.Children.Count); var ey1 = ex1.Transform.Children[0].Entity; Assert.AreEqual(ey.Name, ey1.Name); Assert.NotNull(ey1.Get<TestEntityComponent>()); Assert.AreEqual(eb1, ey1.Get<TestEntityComponent>().EntityLink); } { var ec1 = a3.Hierarchy.Parts.FirstOrDefault(it => it.Entity.Name == "ec1'")?.Entity; Assert.NotNull(ec1); var ea1 = a3.Hierarchy.Parts.FirstOrDefault(it => it.Entity.Name == "ea1'")?.Entity; Assert.NotNull(ea1); Assert.NotNull(ec1.Get<TestEntityComponent>()); Assert.AreEqual(ea1, ec1.Get<TestEntityComponent>().EntityLink); } } // ------------------------------------------------ // Check for a4 // ------------------------------------------------ // a4: (baseParts: a2 x 1, a3 x 1) // | eNewRoot // | er1* (base: er) // | ea1* (base: ea) // | eb1* (base: eb) // | ec1* + link ea1* (base: ec) // | er2* (base: er) // | ea2* (base: ea) // | eb2* (base: eb) // | ec2* + link ea2* (base: ec) // | er1'* (base: er) // | ea1'* (base: ea) // | eb1'* (base: eb) // | ec1'* + link ea1'* (base: ec) // | ex(1*) // | ey(1*) + link eb1* // | ex(2*) // | ey(2*) + link eb2* // | ex(1') (base: ex) // | ey(1') + link eb1'* { Assert.True(a4.DumpTo(Console.Out, "a4 AFTER PrefabMergeAsset")); Assert.AreEqual(5, a4.Hierarchy.RootPartIds.Count); Assert.True(a4.Hierarchy.Parts.Where(it => it.Entity.Name != "eRoot").All(it => it.Entity.Name != "eRoot" && it.Base != null)); // Check that we have all expected entities Assert.AreEqual(19, a4.Hierarchy.Parts.Count); var eb1 = a4.Hierarchy.Parts.FirstOrDefault(it => it.Entity.Name == "eb1*")?.Entity; var eb1_2 = a4.Hierarchy.Parts.FirstOrDefault(it => it.Entity.Name == "eb1'*")?.Entity; var eb2 = a4.Hierarchy.Parts.FirstOrDefault(it => it.Entity.Name == "eb2*")?.Entity; Assert.NotNull(eb1); Assert.NotNull(eb1_2); Assert.NotNull(eb2); // Check that we have ex and ey var exList = a4.Hierarchy.Parts.Where(it => it.Entity.Name == ex.Name).ToList(); Assert.AreEqual(3, exList.Count); // Check that both [ex] have both 1 element [ey] and the links to eb1/eb2 are correct { var expecting = new List<Entity>() { eb1, eb1_2, eb2 }; for (int i = 0; i < exList.Count; i++) { var ex1 = exList[i].Entity; Assert.AreEqual(1, ex1.Transform.Children.Count); var ey1 = ex1.Transform.Children[0].Entity; Assert.AreEqual(ey.Name, ey1.Name); Assert.NotNull(ey1.Get<TestEntityComponent>()); var entityLink = ey1.Get<TestEntityComponent>().EntityLink; Assert.True(expecting.Contains(entityLink)); expecting.Remove(entityLink); } } // Check all [er] entities Action<string> checkErX = (erName) => { var er1 = a4.Hierarchy.Parts.FirstOrDefault(it => it.Entity.Name == erName)?.Entity; Assert.NotNull(er1); Assert.AreEqual(3, er1.Transform.Children.Count); var ec1 = er1.Transform.Children.FirstOrDefault(it => it.Entity.Name.StartsWith("ec"))?.Entity; Assert.NotNull(ec1); var ea1 = er1.Transform.Children.FirstOrDefault(it => it.Entity.Name.StartsWith("ea"))?.Entity; Assert.NotNull(ea1); Assert.NotNull(ec1.Get<TestEntityComponent>()); Assert.AreEqual(ea1, ec1.Get<TestEntityComponent>().EntityLink); }; checkErX("er1*"); checkErX("er2*"); checkErX("er1'*"); } } }
public void TestMultiplePrefabsMixedInheritance() { // The purpose of this test is to check that modifying a prefab base is correctly propagated through all // derived prefabs. We use the following scenario: // a1: base asset) // a2: inherit from a1 by composition with 2 instances (baseParts: a1, 2 instances) // a3: direct inheritance from a2 (base: a2) // This scenario doesn't happen in practice, as we have restricted only to inheritance by composition for prefabs // but we verify that the code is actually working for this scenario var package = new Package(); var assetItems = package.Assets; // Before Adding Package // 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 adding the package to the session // 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 PrefabAsset(); var ea = new Entity("ea"); var eb = new Entity("eb"); a1.Hierarchy.Parts.Add(new EntityDesign(ea)); a1.Hierarchy.Parts.Add(new EntityDesign(eb)); a1.Hierarchy.RootPartIds.Add(ea.Id); a1.Hierarchy.RootPartIds.Add(eb.Id); assetItems.Add(new AssetItem("a1", a1)); var a2 = new PrefabAsset(); var aPartInstance1 = a1.CreatePrefabInstance(a2, "a1"); var aPartInstance2 = a1.CreatePrefabInstance(a2, "a1"); a2.Hierarchy.Parts.AddRange(aPartInstance1.Parts); a2.Hierarchy.Parts.AddRange(aPartInstance2.Parts); a2.Hierarchy.RootPartIds.AddRange(aPartInstance1.RootPartIds); a2.Hierarchy.RootPartIds.AddRange(aPartInstance2.RootPartIds); assetItems.Add(new AssetItem("a2", a2)); // Modify a1 to add entity ec var ec = new Entity("ec"); a1.Hierarchy.Parts.Add(new EntityDesign(ec)); a1.Hierarchy.RootPartIds.Add(ec.Id); var a3 = (PrefabAsset)a2.CreateDerivedAsset("a2"); assetItems.Add(new AssetItem("a3", a3)); // Create a session with this project using (var session = new PackageSession()) { var logger = new LoggerResult(); session.AddExistingPackage(package, logger); Assert.False(logger.HasErrors); Assert.AreEqual(6, a2.Hierarchy.RootPartIds.Count); Assert.True(a2.Hierarchy.Parts.All(it => it.Base != null)); Assert.AreEqual(6, a3.Hierarchy.RootPartIds.Count); Assert.True(a3.Hierarchy.Parts.All(it => it.Base != null && a2.Hierarchy.Parts.ContainsKey(it.Base.BasePartId))); } }
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 PrefabAsset(); part1.Hierarchy.Parts.Add(new EntityDesign(eRoot)); part1.Hierarchy.Parts.Add(new EntityDesign(entityA)); part1.Hierarchy.Parts.Add(new EntityDesign(entityB)); part1.Hierarchy.Parts.Add(new EntityDesign(entityC)); part1.Hierarchy.RootPartIds.Add(eRoot.Id); // part2 Asset var part2 = AssetCloner.Clone(part1); var eRootPart2 = part2.Hierarchy.Parts.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.Parts.Where(it => it.Entity.Name == "B").Select(it => it.Entity).First(); entityD.Add(new TestEntityComponent() { EntityLink = entityBFrom2 }); part2.Hierarchy.Parts.Add(new EntityDesign(entityD)); // originalAsset: Add a new instanceId for this part var asset = new PrefabAsset(); // Create derived parts //var eRoot1Asset = (PrefabAsset)part1.CreateDerivedAsset("part"); //var eRoot2Asset = (PrefabAsset)part1.CreateDerivedAsset("part"); //asset.AddPart(eRoot1Asset); //asset.AddPart(eRoot2Asset); Guid eRoot1Id; Guid eRoot2Id; var eRoot1Asset = part1.CreatePrefabInstance(asset, "part", out eRoot1Id); var eRoot2Asset = part1.CreatePrefabInstance(asset, "part", out eRoot2Id); asset.Hierarchy.Parts.AddRange(eRoot1Asset.Parts); asset.Hierarchy.Parts.AddRange(eRoot2Asset.Parts); asset.Hierarchy.RootPartIds.AddRange(eRoot1Asset.RootPartIds); asset.Hierarchy.RootPartIds.AddRange(eRoot2Asset.RootPartIds); //var eRoot2 = asset.Hierarchy.Entities[eRoot2Asset.Hierarchy.RootEntities[0]]; var eRoot2 = asset.Hierarchy.Parts[eRoot2Asset.RootPartIds[0]]; var entityToRemove = eRoot2.Entity.Transform.Children.First(it => it.Entity.Name == "B"); eRoot2.Entity.Transform.Children.Remove(entityToRemove); asset.Hierarchy.Parts.Remove(entityToRemove.Entity.Id); // EntityD must be now part of the new asset Assert.AreEqual(2, asset.Hierarchy.RootPartIds.Count); Assert.AreEqual(9, asset.Hierarchy.Parts.Count); Assert.AreEqual(2, asset.Hierarchy.Parts.Count(it => it.Entity.Name == "D")); foreach (var entity in asset.Hierarchy.Parts.Where(it => it.Entity.Name == "D")) { // Check that we have the correct baesId and basePartInstanceId Assert.True(entity.Base != null); Assert.AreEqual(entityD.Id, entity.Base.BasePartId); } var entityDesignD1 = asset.Hierarchy.Parts[asset.Hierarchy.Parts[asset.Hierarchy.RootPartIds[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); Assert.AreEqual(eRoot1Id, entityDesignD1.Base.InstanceId); var testComponentD1 = entityDesignD1.Entity.Get<TestEntityComponent>(); Assert.NotNull(testComponentD1); var entityB1 = asset.Hierarchy.Parts[asset.Hierarchy.RootPartIds[0]].Entity.Transform.Children.Where(it => it.Entity.Name == "B").Select(it => it.Entity).First(); Assert.AreEqual(entityB1, testComponentD1.EntityLink); var entityDesignD2 = asset.Hierarchy.Parts[asset.Hierarchy.Parts[asset.Hierarchy.RootPartIds[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); Assert.AreEqual(eRoot2Id, entityDesignD2.Base.InstanceId); var testComponentD2 = entityDesignD2.Entity.Get<TestEntityComponent>(); Assert.NotNull(testComponentD2); Assert.AreEqual(null, testComponentD2.EntityLink); }
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 PrefabAsset(); basePart.Hierarchy.Parts.Add(new EntityDesign(entityA)); basePart.Hierarchy.Parts.Add(new EntityDesign(entityB)); basePart.Hierarchy.Parts.Add(new EntityDesign(entityC)); basePart.Hierarchy.RootPartIds.Add(entityA.Id); basePart.Hierarchy.RootPartIds.Add(entityB.Id); basePart.Hierarchy.RootPartIds.Add(entityC.Id); // originalAsset: Add a new instanceId for this part var asset = new PrefabAsset(); // Create part1 asset Guid part1InstanceId; Guid part12InstanceId; var part1 = basePart.CreatePrefabInstance(asset, "part", out part1InstanceId); var entityB1 = part1.Parts.First(it => it.Entity.Name == "B").Entity; var part12 = basePart.CreatePrefabInstance(asset, "part", out part12InstanceId); var entityB2 = part12.Parts.First(it => it.Entity.Name == "B").Entity; // create part2 assset var entityD = new Entity() { Name = "D" }; basePart.Hierarchy.Parts.Add(new EntityDesign(entityD)); basePart.Hierarchy.RootPartIds.Add(entityD.Id); // ED + link: EB var entityBFrom2 = basePart.Hierarchy.Parts.Where(it => it.Entity.Name == "B").Select(it => it.Entity).First(); entityD.Add(new TestEntityComponent() { EntityLink = entityBFrom2 }); asset.Hierarchy.Parts.AddRange(part1.Parts); asset.Hierarchy.Parts.AddRange(part12.Parts); asset.Hierarchy.RootPartIds.AddRange(part1.RootPartIds); asset.Hierarchy.RootPartIds.AddRange(part12.RootPartIds); // EntityD must be now part of the new asset Assert.AreEqual(8, asset.Hierarchy.RootPartIds.Count); Assert.AreEqual(8, asset.Hierarchy.Parts.Count); Assert.AreEqual(2, asset.Hierarchy.Parts.Count(it => it.Entity.Name == "D")); foreach (var entity in asset.Hierarchy.Parts.Where(it => it.Entity.Name == "D")) { // Check that we have the correct baesId and basePartInstanceId Assert.True(entity.Base != null); Assert.AreEqual(entityD.Id, entity.Base.BasePartId); // Make sure that the entity is in the RootEntities Assert.True(asset.Hierarchy.RootPartIds.Contains(entity.Entity.Id)); } var entityDesignD1 = asset.Hierarchy.Parts.FirstOrDefault(it => it.Entity.Name == "D" && it.Base.InstanceId == part1InstanceId); Assert.NotNull(entityDesignD1); var entityDesignD2 = asset.Hierarchy.Parts.FirstOrDefault(it => it.Entity.Name == "D" && it.Base.InstanceId == part12InstanceId); 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); }
public void TestMergeAddEntityWithLinks2() { // Test merging an PrefabAsset 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 PrefabAsset(); baseAsset.Hierarchy.Parts.Add(new EntityDesign(eA)); baseAsset.Hierarchy.Parts.Add(new EntityDesign(eA1)); baseAsset.Hierarchy.Parts.Add(new EntityDesign(eA2)); baseAsset.Hierarchy.Parts.Add(new EntityDesign(eA3)); baseAsset.Hierarchy.RootPartIds.Add(eA.Id); var baseAssetItem = new AssetItem("base", baseAsset); // Create new Base Asset var newBaseAsset = AssetCloner.Clone(baseAsset); var eA4 = new Entity() { Name = "A4" }; var rootInNewBase = newBaseAsset.Hierarchy.Parts[newBaseAsset.Hierarchy.RootPartIds.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.Parts.Add(new EntityDesign(eA4)); rootInNewBase.Entity.Transform.Children.Add(eA4.Transform); // Create new Asset (from base) var newAsset = (PrefabAsset)baseAssetItem.CreateDerivedAsset(); Assert.AreEqual(1, newAsset.Hierarchy.RootPartIds.Count); Assert.AreEqual(5, newAsset.Hierarchy.Parts.Count); // EA, EA1', EA2', EA3', EA4' var rootEntity = newAsset.Hierarchy.Parts[newAsset.Hierarchy.RootPartIds.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); }
public void TestMergeEntityWithChildren() { // Test merging an PrefabAsset 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 PrefabAsset(); 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 = (PrefabAsset)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 = (PrefabAsset)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((EntityHierarchyAssetBase)AssetCloner.Clone(baseAsset), (EntityHierarchyAssetBase)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); }
public PrefabCommand(string url, PrefabAsset parameters) : base(url, parameters) { }
private static void CheckAsset(PrefabAsset originAsset, PrefabAsset newAsset) { CheckGenericAsset(originAsset, newAsset); var entity1 = originAsset.Hierarchy.Parts.First(it => it.Entity.Name == "E1").Entity; var entity2 = originAsset.Hierarchy.Parts.First(it => it.Entity.Name == "E2").Entity; var entity3 = originAsset.Hierarchy.Parts.First(it => it.Entity.Name == "E3").Entity; var entity4 = originAsset.Hierarchy.Parts.First(it => it.Entity.Name == "E4").Entity; // Check that we have exactly the same root entities var newEntityDesign1 = newAsset.Hierarchy.Parts[entity1.Id]; var newEntityDesign2 = newAsset.Hierarchy.Parts[entity2.Id]; var newEntityDesign3 = newAsset.Hierarchy.Parts[entity3.Id]; var newEntityDesign4 = newAsset.Hierarchy.Parts[entity4.Id]; // Check that Transform.Children is correctly setup Assert.AreEqual(newEntityDesign2.Entity.Transform, newEntityDesign1.Entity.Transform.Children.FirstOrDefault()); // Test entity-entity link from E2 to E1 { var component = newEntityDesign2.Entity.Get<TestEntityComponent>(); Assert.NotNull(component); Assert.AreEqual(newEntityDesign1.Entity, component.EntityLink); } // Test entity-component link from E4 to E3 { var component = newEntityDesign4.Entity.Get<TestEntityComponent>(); Assert.NotNull(component); Assert.AreEqual(newEntityDesign3.Entity.Transform, component.EntityComponentLink); } }
public void Test() { var prefab = new PrefabAsset(); var modelComponent = new ModelComponent(); var entity = new Entity() { modelComponent }; prefab.Hierarchy.Entities.Add(entity); prefab.Hierarchy.RootEntities.Add(entity.Id); var material1 = new MaterialNull(); IdentifiableHelper.SetId(material1, new Guid("39E2B226-8752-4678-8E93-76FFBFBA337B")); var material2 = new MaterialNull(); IdentifiableHelper.SetId(material2, new Guid("CC4F1B31-FBB7-4360-A3E7-060BDFDA0695")); modelComponent.Materials.Add(material1); modelComponent.Materials.Add(material2); Action<PrefabAsset> checkPrefab = (newPrefab) => { var previousEntityDesign = newPrefab.Hierarchy.Entities.FirstOrDefault(); Assert.NotNull(previousEntityDesign); var previousEntity = previousEntityDesign.Entity; var component = previousEntity.Get<ModelComponent>(); Assert.NotNull(component); Assert.AreEqual(2, component.Materials.Count); var newMaterial1 = component.Materials[0]; Assert.AreEqual(IdentifiableHelper.GetId(material1), IdentifiableHelper.GetId(newMaterial1)); var newMaterial2 = component.Materials[1]; Assert.AreEqual(IdentifiableHelper.GetId(material2), IdentifiableHelper.GetId(newMaterial2)); }; // Test yaml serialization { using (var stream = new MemoryStream()) { AssetSerializer.Save(stream, prefab); stream.Position = 0; var serializedVersion = Encoding.UTF8.GetString(stream.ToArray()); Console.WriteLine(serializedVersion); stream.Position = 0; var newPrefab = (PrefabAsset)AssetSerializer.Load(stream, "myentity"); checkPrefab(newPrefab); } } // Test cloning var newPrefabClone = (PrefabAsset)AssetCloner.Clone(prefab); checkPrefab(newPrefabClone); // Test runtime serialization (runtime serialization is removing MaterialNull and replacing it by a null) { var stream = new MemoryStream(); var writer = new BinarySerializationWriter(stream) { Context = { SerializerSelector = SerializerSelector.AssetWithReuse } }; writer.SerializeExtended(entity, ArchiveMode.Serialize); writer.Flush(); stream.Position = 0; var reader = new BinarySerializationReader(stream) { Context = { SerializerSelector = SerializerSelector.AssetWithReuse } }; Entity newEntity = null; reader.SerializeExtended(ref newEntity, ArchiveMode.Deserialize); Assert.NotNull(newEntity); var component = newEntity.Get<ModelComponent>(); Assert.NotNull(component); Assert.AreEqual(2, component.Materials.Count); Assert.Null(component.Materials[0]); Assert.Null(component.Materials[1]); } }
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 PrefabAsset(); 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 = (PrefabAsset)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 = (PrefabAsset)baseAssetItem.CreateChildAsset(); // Merge entities (NOTE: it is important to clone baseAsset/newBaseAsset) var result = newAsset.Merge((EntityHierarchyAssetBase)AssetCloner.Clone(baseAsset), (EntityHierarchyAssetBase)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]); }
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 PrefabAsset(); 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 PrefabAsset(); var aPartInstance1 = a1.CreatePrefabInstance(a2, "a1"); var aPartInstance2 = a1.CreatePrefabInstance(a2, "a1"); a2.Hierarchy.Entities.AddRange(aPartInstance1.Entities); a2.Hierarchy.Entities.AddRange(aPartInstance2.Entities); a2.Hierarchy.RootEntities.AddRange(aPartInstance1.RootEntities); a2.Hierarchy.RootEntities.AddRange(aPartInstance2.RootEntities); // Modify a1 to add entity ec var ec = new Entity("ec"); a1.Hierarchy.Entities.Add(ec); a1.Hierarchy.RootEntities.Add(ec.Id); var a3 = (PrefabAsset)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))); }
public void TestMergeRemoveEntityWithLinks() { // Test merging an PrefabAsset with a root entity EA, and 3 child entities // - Remove a child entity from NewBase (EA2) // - Add a child entity (EA4) to NewBase that has a link to the EA2 entity // // Base NewBase NewAsset NewAsset (Merged) // // EA EA EA'(base: EA) EA'(base: EA) // |-EA1 |-EA1 |-EA1'(base: EA1) |-EA1'(base: EA1) // |-EA2 | |-EA2'(base: EA2) | // |-EA3 |-EA3 |-EA3'(base: EA3) |-EA3'(base: EA3) // |-EA4' + link EA2' |-EA4'(base: EA4) + no more links // 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 PrefabAsset(); 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 = (PrefabAsset)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 = (PrefabAsset)baseAssetItem.CreateChildAsset(); var eA4 = new Entity() { Name = "A4" }; var rootInNew = newAsset.Hierarchy.Entities[newAsset.Hierarchy.RootEntities.First()]; var eA2InNewTransform = rootInNew.Entity.Transform.Children.FirstOrDefault(item => item.Entity.Name == "A2"); Assert.NotNull(eA2InNewTransform); // Add EA4 with link to EA1 entity and EA2 component var testComponent = new TestEntityComponent { EntityLink = eA2InNewTransform.Entity, }; eA4.Add(testComponent); newAsset.Hierarchy.Entities.Add(new EntityDesign(eA4, new EntityDesignData())); rootInNew.Entity.Transform.Children.Add(eA4.Transform); // Merge entities (NOTE: it is important to clone baseAsset/newBaseAsset) var result = newAsset.Merge((EntityHierarchyAssetBase)AssetCloner.Clone(baseAsset), (EntityHierarchyAssetBase)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); var eA4Merged = rootEntity.Entity.Transform.Children[2].Entity; Assert.AreEqual("A1", rootEntity.Entity.Transform.Children[0].Entity.Name); Assert.AreEqual("A3", rootEntity.Entity.Transform.Children[1].Entity.Name); Assert.AreEqual("A4", eA4Merged.Name); var testComponentMerged = eA4Merged.Get<TestEntityComponent>(); Assert.NotNull(testComponentMerged); Assert.Null(testComponentMerged.EntityLink); }
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 PrefabAsset(); baseAsset.Hierarchy.Parts.Add(new EntityDesign(entityA)); baseAsset.Hierarchy.Parts.Add(new EntityDesign(entityB)); baseAsset.Hierarchy.Parts.Add(new EntityDesign(entityC)); baseAsset.Hierarchy.RootPartIds.Add(entityA.Id); baseAsset.Hierarchy.RootPartIds.Add(entityB.Id); baseAsset.Hierarchy.RootPartIds.Add(entityC.Id); var baseAssetItem = new AssetItem("base", baseAsset); // Create new Base Asset var entityD = new Entity() { Name = "D" }; var newBaseAsset = AssetCloner.Clone(baseAsset); newBaseAsset.Hierarchy.Parts.Add(new EntityDesign(entityD)); newBaseAsset.Hierarchy.RootPartIds.Add(entityD.Id); // Create new Asset (from base) var newAsset = (PrefabAsset)baseAssetItem.CreateDerivedAsset(); // Both root and entities must be the same Assert.AreEqual(4, newAsset.Hierarchy.RootPartIds.Count); Assert.AreEqual(4, newAsset.Hierarchy.Parts.Count); // All entities must have a base value Assert.True(newAsset.Hierarchy.Parts.All(item => item.Base != null)); var entityAInNewAsset = newAsset.Hierarchy.Parts.Where(item => item.Base.BasePartId == entityA.Id).Select(item => item.Entity).FirstOrDefault(); Assert.NotNull(entityAInNewAsset); var entityBInNewAsset = newAsset.Hierarchy.Parts.Where(item => item.Base.BasePartId == entityB.Id).Select(item => item.Entity).FirstOrDefault(); Assert.NotNull(entityBInNewAsset); var entityCInNewAsset = newAsset.Hierarchy.Parts.Where(item => item.Base.BasePartId == entityC.Id).Select(item => item.Entity).FirstOrDefault(); Assert.NotNull(entityCInNewAsset); var entityDInNewAsset = newAsset.Hierarchy.Parts.Where(item => item.Base.BasePartId == entityD.Id).Select(item => item.Entity).FirstOrDefault(); Assert.NotNull(entityDInNewAsset); // Hierarchy must be: EA, EB, EC, ED Assert.AreEqual(entityAInNewAsset.Id, newAsset.Hierarchy.RootPartIds[0]); Assert.AreEqual(entityBInNewAsset.Id, newAsset.Hierarchy.RootPartIds[1]); Assert.AreEqual(entityCInNewAsset.Id, newAsset.Hierarchy.RootPartIds[2]); Assert.AreEqual(entityDInNewAsset.Id, newAsset.Hierarchy.RootPartIds[3]); }
/// <summary> /// Clones a sub-hierarchy of this asset. /// </summary> /// <param name="sourceRootEntity">The entity that is the root of the sub-hierarchy to clone</param> /// <param name="cleanReference">If true, any reference to an entity external to the cloned hierarchy will be set to null.</param> /// <param name="entityMapping">A dictionary containing the mapping of ids from the source entites to the new entities.</param> /// <returns>A <see cref="AssetCompositeHierarchyData{EntityDesign, Entity}"/> corresponding to the cloned entities.</returns> public AssetCompositeHierarchyData <EntityDesign, Entity> CloneSubHierarchy(Guid sourceRootEntity, bool cleanReference, out Dictionary <Guid, Guid> entityMapping) { if (!Hierarchy.Parts.ContainsKey(sourceRootEntity)) { throw new ArgumentException(@"The source root entity must be an entity of this asset.", nameof(sourceRootEntity)); } // 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. var subTreeRoot = Hierarchy.Parts[sourceRootEntity]; var subTreeHierarchy = new AssetCompositeHierarchyData <EntityDesign, Entity> { Parts = { subTreeRoot }, RootPartIds = { sourceRootEntity } }; foreach (var subTreeEntity in EnumerateChildParts(subTreeRoot, true)) { subTreeHierarchy.Parts.Add(Hierarchy.Parts[subTreeEntity.Entity.Id]); } // clone the entities of the sub-tree var clonedHierarchy = (AssetCompositeHierarchyData <EntityDesign, Entity>)AssetCloner.Clone(subTreeHierarchy); clonedHierarchy.Parts[sourceRootEntity].Entity.Transform.Parent = null; if (cleanReference) { // set to null reference outside of the sub-tree var tempAsset = new PrefabAsset { Hierarchy = clonedHierarchy }; tempAsset.FixupPartReferences(); } // temporary nullify the hierarchy to avoid to clone it var sourceHierarchy = Hierarchy; Hierarchy = null; // revert the source hierarchy Hierarchy = sourceHierarchy; // Generate entity mapping entityMapping = new Dictionary <Guid, Guid>(); foreach (var entityDesign in clonedHierarchy.Parts) { // Generate new Id var newEntityId = Guid.NewGuid(); // Update mappings entityMapping.Add(entityDesign.Entity.Id, newEntityId); // Update entity with new id entityDesign.Entity.Id = newEntityId; } // Rewrite entity references // Should we nullify invalid references? EntityAnalysis.RemapEntitiesId(clonedHierarchy, entityMapping); return(clonedHierarchy); }
public PrefabCommand(string url, Package package, AssetCompilerContext context, PrefabAsset assetParameters) : base(url, package, context, assetParameters) { }
protected override PrefabBase Create(PrefabAsset prefabAsset) { return(new Prefab()); }
public void TestMergeEntityWithChildren() { // Test merging an PrefabAsset 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 PrefabAsset(); baseAsset.Hierarchy.Parts.Add(new EntityDesign(eA)); baseAsset.Hierarchy.Parts.Add(new EntityDesign(eA1)); baseAsset.Hierarchy.Parts.Add(new EntityDesign(eA2)); baseAsset.Hierarchy.Parts.Add(new EntityDesign(eA3)); baseAsset.Hierarchy.RootPartIds.Add(eA.Id); var baseAssetItem = new AssetItem("base", baseAsset); // Create new Base Asset var newBaseAsset = AssetCloner.Clone(baseAsset); var eA2FromNewBase = newBaseAsset.Hierarchy.Parts.First(item => item.Entity.Id == eA2.Id); newBaseAsset.Hierarchy.Parts[eA.Id].Entity.Transform.Children.Remove(eA2FromNewBase.Entity.Transform); // Create new Asset (from base) var newAsset = (PrefabAsset)baseAssetItem.CreateDerivedAsset(); var eA4 = new Entity() { Name = "A4" }; newAsset.Hierarchy.Parts.Add(new EntityDesign(eA4)); newAsset.Hierarchy.Parts[newAsset.Hierarchy.RootPartIds.First()].Entity.Transform.Children.Add(eA4.Transform); Assert.AreEqual(1, newAsset.Hierarchy.RootPartIds.Count); Assert.AreEqual(4, newAsset.Hierarchy.Parts.Count); // EA, EA1', EA3', EA4' var rootEntity = newAsset.Hierarchy.Parts[newAsset.Hierarchy.RootPartIds.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); }