Example #1
0
        /// <summary>
        /// Updates the paths in the given <see cref="YamlAssetMetadata{T}"/> instance to reflect that new <see cref="Guid"/> have been generated after cloning,
        /// when <see cref="AssetClonerFlags.GenerateNewIdsForIdentifiableObjects"/> has been used.
        /// </summary>
        /// <typeparam name="T">The type of content in the metadata.</typeparam>
        /// <param name="metadata">The metadata to update.</param>
        /// <param name="idRemapping">A dictionary representing the mapping between initial ids and their corresponding id in the cloned object.</param>
        /// <param name="basePath">If not null, this method will apply the remapping only for paths that are contained in the given base path.</param>
        public static void RemapIdentifiablePaths <T>(YamlAssetMetadata <T> metadata, Dictionary <Guid, Guid> idRemapping, YamlAssetPath basePath = null)
        {
            // Early exit if nothing to remap
            if (metadata == null || idRemapping == null)
            {
                return;
            }

            var replacements = new List <Tuple <YamlAssetPath, YamlAssetPath, T> >();

            foreach (var entry in metadata)
            {
                // Skip paths that doesn't start with the given base path.
                if (basePath != null && !entry.Key.StartsWith(basePath))
                {
                    continue;
                }

                var newPath = new YamlAssetPath(entry.Key.Elements.Select(x => FixupIdentifier(x, idRemapping)));
                replacements.Add(Tuple.Create(entry.Key, newPath, entry.Value));
            }

            // First remove everything, then re-add everything, in case we have a collision between an old path and a new path
            foreach (var replacement in replacements)
            {
                metadata.Remove(replacement.Item1);
            }
            foreach (var replacement in replacements)
            {
                metadata.Set(replacement.Item2, replacement.Item3);
            }
        }
Example #2
0
        public AssetNode ResolveObjectPath(YamlAssetPath path, out Index index, out bool overrideOnKey)
        {
            var currentNode = this;

            index         = Index.Empty;
            overrideOnKey = false;
            for (var i = 0; i < path.Items.Count; i++)
            {
                var item = path.Items[i];
                switch (item.Type)
                {
                case YamlAssetPath.ItemType.Member:
                    index         = Index.Empty;
                    overrideOnKey = false;
                    if (currentNode.Content.IsReference)
                    {
                        currentNode = (AssetNode)((IGraphNode)currentNode).Target;
                    }
                    string name = item.AsMember();
                    currentNode = (AssetNode)((IGraphNode)currentNode).TryGetChild(name);
                    break;

                case YamlAssetPath.ItemType.Index:
                    index         = new Index(item.Value);
                    overrideOnKey = true;
                    if (currentNode.Content.IsReference && i < path.Items.Count - 1)
                    {
                        Index index1 = new Index(item.Value);
                        currentNode = (AssetNode)((IGraphNode)currentNode).IndexedTarget(index1);
                    }
                    break;

                case YamlAssetPath.ItemType.ItemId:
                    var ids = CollectionItemIdHelper.GetCollectionItemIds(currentNode.Content.Retrieve());
                    var key = ids.GetKey(item.AsItemId());
                    index         = new Index(key);
                    overrideOnKey = false;
                    if (currentNode.Content.IsReference && i < path.Items.Count - 1)
                    {
                        Index index1 = new Index(key);
                        currentNode = (AssetNode)((IGraphNode)currentNode).IndexedTarget(index1);
                    }
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }

                // Something wrong happen, the node is unreachable.
                if (currentNode == null)
                {
                    return(null);
                }
            }

            return(currentNode);
        }
        public override object ReadDictionaryKey(ref ObjectContext objectContext, Type keyType)
        {
            var key = objectContext.Reader.Peek <Scalar>();

            OverrideType[] overrideTypes;
            var            keyName = TrimAndParseOverride(key.Value, out overrideTypes);

            key.Value = keyName;

            var keyValue = base.ReadDictionaryKey(ref objectContext, keyType);

            if (overrideTypes[0] != OverrideType.Base)
            {
                YamlAssetMetadata <OverrideType> overrides;
                if (!objectContext.SerializerContext.Properties.TryGetValue(OverrideDictionaryKey, out overrides))
                {
                    overrides = new YamlAssetMetadata <OverrideType>();
                    objectContext.SerializerContext.Properties.Add(OverrideDictionaryKey, overrides);
                }

                var    path = GetCurrentPath(ref objectContext, true);
                ItemId id;
                object actualKey;
                if (YamlAssetPath.IsCollectionWithIdType(objectContext.Descriptor.Type, keyValue, out id, out actualKey))
                {
                    path.PushItemId(id);
                }
                else
                {
                    path.PushIndex(key);
                }
                overrides.Set(path, overrideTypes[0]);
            }

            if (overrideTypes.Length > 1 && overrideTypes[1] != OverrideType.Base)
            {
                ItemId id;
                object actualKey;
                if (YamlAssetPath.IsCollectionWithIdType(objectContext.Descriptor.Type, keyValue, out id, out actualKey))
                {
                    YamlAssetMetadata <OverrideType> overrides;
                    if (!objectContext.SerializerContext.Properties.TryGetValue(OverrideDictionaryKey, out overrides))
                    {
                        overrides = new YamlAssetMetadata <OverrideType>();
                        objectContext.SerializerContext.Properties.Add(OverrideDictionaryKey, overrides);
                    }

                    var path = GetCurrentPath(ref objectContext, true);
                    path.PushIndex(actualKey);
                    overrides.Set(path, overrideTypes[1]);
                }
            }

            return(keyValue);
        }
        public static YamlAssetPath ConvertPath(GraphNodePath path, int inNonIdentifiableType)
        {
            var currentNode = (AssetNode)path.RootNode;
            var result      = new YamlAssetPath();
            var i           = 0;

            foreach (var item in path.Path)
            {
                switch (item.Type)
                {
                case GraphNodePath.ElementType.Member:
                    var member = (string)item.Value;
                    result.PushMember(member);
                    currentNode = (AssetNode)((IGraphNode)currentNode).TryGetChild(member);
                    break;

                case GraphNodePath.ElementType.Target:
                    if (i < path.Path.Count - 1)
                    {
                        currentNode = (AssetNode)((IGraphNode)currentNode).Target;
                    }
                    break;

                case GraphNodePath.ElementType.Index:
                    var index = (Index)item.Value;
                    if (inNonIdentifiableType > 0 || currentNode.IsNonIdentifiableCollectionContent)
                    {
                        result.PushIndex(index.Value);
                    }
                    else
                    {
                        var id = currentNode.IndexToId(index);
                        // Create a new id if we don't have any so far
                        if (id == ItemId.Empty)
                        {
                            id = ItemId.New();
                        }
                        result.PushItemId(id);
                    }
                    if (i < path.Path.Count - 1)
                    {
                        currentNode = (AssetNode)((IGraphNode)currentNode).IndexedTarget(index);
                    }
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }
                ++i;
            }
            return(result);
        }
            protected override bool ProcessObject(object obj, Type expectedType)
            {
                foreach (var unloadedObject in ItemsToReload)
                {
                    // If a collection, stop at parent path level (since index will be already removed, we will never visit the target slot)
                    // TODO: Check if the fact we didn't enter in an item with index affect visitor states
                    // Other case, stop on the actual member (since we'll just visit null)
                    var expectedPath = unloadedObject.Path.Decompose().Last().GetIndex() != null ? unloadedObject.ParentPath : unloadedObject.Path;

                    if (CurrentPath.Match(expectedPath))
                    {
                        var eventReader = new EventReader(new MemoryParser(unloadedObject.ParsingEvents));
                        var settings    = Log != null ? new SerializerContextSettings {
                            Logger = Log
                        } : null;
                        PropertyContainer properties;
                        unloadedObject.UpdatedObject = AssetYamlSerializer.Default.Deserialize(eventReader, null, unloadedObject.ExpectedType, out properties, settings);
                        // We will have broken references here because we are deserializing objects individually, so we don't pass any logger to discard warnings
                        var metadata = YamlAssetSerializer.CreateAndProcessMetadata(properties, unloadedObject.UpdatedObject, false);

                        var overrides = metadata.RetrieveMetadata(AssetObjectSerializerBackend.OverrideDictionaryKey);
                        unloadedObject.Overrides = overrides;

                        var references = metadata.RetrieveMetadata(AssetObjectSerializerBackend.ObjectReferencesKey);
                        if (references != null)
                        {
                            var basePath = YamlAssetPath.FromMemberPath(CurrentPath, root);
                            foreach (var reference in references)
                            {
                                var basePathWithIndex = basePath.Clone();
                                if (unloadedObject.GraphPathIndex != NodeIndex.Empty)
                                {
                                    if (unloadedObject.ItemId == ItemId.Empty)
                                    {
                                        basePathWithIndex.PushIndex(unloadedObject.GraphPathIndex.Value);
                                    }
                                    else
                                    {
                                        basePathWithIndex.PushItemId(unloadedObject.ItemId);
                                    }
                                }
                                var actualPath = basePathWithIndex.Append(reference.Key);
                                ObjectReferences.Set(actualPath, reference.Value);
                            }
                        }
                    }
                }
                return(false);
            }
 public static YamlAssetPath ConvertPath(GraphNodePath path, int inNonIdentifiableType)
 {
     var currentNode = (AssetNode)path.RootNode;
     var result = new YamlAssetPath();
     var i = 0;
     foreach (var item in path.Path)
     {
         switch (item.Type)
         {
             case GraphNodePath.ElementType.Member:
                 var member = (string)item.Value;
                 result.PushMember(member);
                 currentNode = (AssetNode)((IGraphNode)currentNode).TryGetChild(member);
                 break;
             case GraphNodePath.ElementType.Target:
                 if (i < path.Path.Count - 1)
                 {
                     currentNode = (AssetNode)((IGraphNode)currentNode).Target;
                 }
                 break;
             case GraphNodePath.ElementType.Index:
                 var index = (Index)item.Value;
                 if (inNonIdentifiableType > 0 || currentNode.IsNonIdentifiableCollectionContent)
                 {
                     result.PushIndex(index.Value);
                 }
                 else
                 {
                     var id = currentNode.IndexToId(index);
                     // Create a new id if we don't have any so far
                     if (id == ItemId.Empty)
                         id = ItemId.New();
                     result.PushItemId(id);
                 }
                 if (i < path.Path.Count - 1)
                 {
                     currentNode = (AssetNode)((IGraphNode)currentNode).IndexedTarget(index);
                 }
                 break;
             default:
                 throw new ArgumentOutOfRangeException();
         }
         ++i;
     }
     return result;
 }
Example #7
0
        public void TestConcreteReferenceConcreteObjectSerialization()
        {
            var obj = new Container {
                Referenceable1 = new Referenceable {
                    Id = GuidGenerator.Get(1), Value = "Test"
                }
            };

            obj.Referenceable2 = obj.Referenceable1;
            var objectReferences = new YamlAssetMetadata <Guid>();
            var path             = new YamlAssetPath();

            path.PushMember(nameof(Container.Referenceable2));
            objectReferences.Set(path, obj.Referenceable2.Id);
            var yaml = SerializeAsString(obj, objectReferences);

            Assert.AreEqual(ConcreteReferenceConcreteObjectYaml, yaml);
        }
Example #8
0
        public void TestAbstracteferenceObjectAbstractSerialization()
        {
            var obj = new Container {
                Referenceable3 = new Referenceable {
                    Id = GuidGenerator.Get(1), Value = "Test"
                }
            };

            obj.Referenceable4 = (Referenceable)obj.Referenceable3;
            var objectReferences = new YamlAssetMetadata <Guid>();
            var path             = new YamlAssetPath();

            path.PushMember(nameof(Container.Referenceable4));
            objectReferences.Set(path, obj.Referenceable4.Id);
            var yaml = SerializeAsString(obj, objectReferences);

            Assert.AreEqual(AbstractReferenceAbstractObjectYaml, yaml);
        }
        public override object ReadDictionaryValue(ref ObjectContext objectContext, Type valueType, object key)
        {
            var    path = GetCurrentPath(ref objectContext, true);
            ItemId id;

            if (YamlAssetPath.IsCollectionWithIdType(objectContext.Descriptor.Type, key, out id))
            {
                path.PushItemId(id);
            }
            else
            {
                path.PushIndex(key);
            }
            var valueObjectContext = new ObjectContext(objectContext.SerializerContext, null, objectContext.SerializerContext.FindTypeDescriptor(valueType));

            SetCurrentPath(ref valueObjectContext, path);
            return(ReadYaml(ref valueObjectContext));
        }
        public override void WriteDictionaryValue(ref ObjectContext objectContext, object key, object value, Type valueType)
        {
            var    path = GetCurrentPath(ref objectContext, true);
            ItemId id;

            if (YamlAssetPath.IsCollectionWithIdType(objectContext.Descriptor.Type, key, out id))
            {
                path.PushItemId(id);
            }
            else
            {
                path.PushIndex(key);
            }
            var itemObjectContext = new ObjectContext(objectContext.SerializerContext, value, objectContext.SerializerContext.FindTypeDescriptor(valueType));

            SetCurrentPath(ref itemObjectContext, path);
            WriteYaml(ref itemObjectContext);
        }
        public override void WriteDictionaryKey(ref ObjectContext objectContext, object key, Type keyType)
        {
            YamlAssetMetadata <OverrideType> overrides;

            if (objectContext.SerializerContext.Properties.TryGetValue(OverrideDictionaryKey, out overrides))
            {
                var           itemPath = GetCurrentPath(ref objectContext, true);
                YamlAssetPath keyPath  = null;
                ItemId        id;
                object        actualKey;
                if (YamlAssetPath.IsCollectionWithIdType(objectContext.Descriptor.Type, key, out id, out actualKey))
                {
                    keyPath = itemPath.Clone();
                    keyPath.PushIndex(actualKey);
                    itemPath.PushItemId(id);
                }
                else
                {
                    itemPath.PushIndex(key);
                }
                var overrideType = overrides.TryGet(itemPath);
                if ((overrideType & OverrideType.New) != 0)
                {
                    objectContext.SerializerContext.Properties.Set(ItemIdSerializerBase.OverrideInfoKey, OverridePostfixes.PostFixNew.ToString());
                }
                if ((overrideType & OverrideType.Sealed) != 0)
                {
                    objectContext.SerializerContext.Properties.Set(ItemIdSerializerBase.OverrideInfoKey, OverridePostfixes.PostFixSealed.ToString());
                }
                if (keyPath != null)
                {
                    overrideType = overrides.TryGet(keyPath);
                    if ((overrideType & OverrideType.New) != 0)
                    {
                        objectContext.SerializerContext.Properties.Set(KeyWithIdSerializer.OverrideKeyInfoKey, OverridePostfixes.PostFixNew.ToString());
                    }
                    if ((overrideType & OverrideType.Sealed) != 0)
                    {
                        objectContext.SerializerContext.Properties.Set(KeyWithIdSerializer.OverrideKeyInfoKey, OverridePostfixes.PostFixSealed.ToString());
                    }
                }
            }
            base.WriteDictionaryKey(ref objectContext, key, keyType);
        }
Example #12
0
        public void TestAbstractNonIdentifiableReferenceableDictionarySerialization()
        {
            var obj  = new NonIdentifiableCollectionContainer();
            var item = new Referenceable {
                Id = GuidGenerator.Get(1), Value = "Test"
            };

            obj.AbstractRefDictionary.Add("Item1", item);
            obj.AbstractRefDictionary.Add("Item2", item);
            var objectReferences = new YamlAssetMetadata <Guid>();
            var path             = new YamlAssetPath();

            path.PushMember(nameof(CollectionContainer.AbstractRefDictionary));
            path.PushIndex("Item1");
            objectReferences.Set(path, GuidGenerator.Get(1));
            var yaml = SerializeAsString(obj, objectReferences);

            Assert.AreEqual(AbstractNonIdentifiableReferenceableDictionaryYaml, yaml);
        }
Example #13
0
        public void TestConcreteNonIdentifiableReferenceableListSerialization()
        {
            var obj  = new NonIdentifiableCollectionContainer();
            var item = new Referenceable {
                Id = GuidGenerator.Get(1), Value = "Test"
            };

            obj.ConcreteRefList.Add(item);
            obj.ConcreteRefList.Add(item);
            var objectReferences = new YamlAssetMetadata <Guid>();
            var path             = new YamlAssetPath();

            path.PushMember(nameof(CollectionContainer.ConcreteRefList));
            path.PushIndex(0);
            objectReferences.Set(path, GuidGenerator.Get(1));
            var yaml = SerializeAsString(obj, objectReferences);

            Assert.AreEqual(ConcreteNonIdentifiableReferenceableListYaml, yaml);
        }
Example #14
0
        public void TestAbstractReferenceableListSerialization()
        {
            var obj  = new CollectionContainer();
            var item = new Referenceable {
                Id = GuidGenerator.Get(1), Value = "Test"
            };

            obj.AbstractRefList.Add(item);
            obj.AbstractRefList.Add(item);
            var objectReferences = new YamlAssetMetadata <Guid>();
            var ids = CollectionItemIdHelper.GetCollectionItemIds(obj.AbstractRefList);

            ids[0] = IdentifierGenerator.Get(1);
            ids[1] = IdentifierGenerator.Get(2);
            var path = new YamlAssetPath();

            path.PushMember(nameof(CollectionContainer.AbstractRefList));
            path.PushItemId(IdentifierGenerator.Get(1));
            objectReferences.Set(path, GuidGenerator.Get(1));
            var yaml = SerializeAsString(obj, objectReferences);

            Assert.AreEqual(AbstractReferenceableListYaml, yaml);
        }
Example #15
0
        public void TestConcreteReferenceableDictionarySerialization()
        {
            var obj  = new CollectionContainer();
            var item = new Referenceable {
                Id = GuidGenerator.Get(1), Value = "Test"
            };

            obj.ConcreteRefDictionary.Add("Item1", item);
            obj.ConcreteRefDictionary.Add("Item2", item);
            var objectReferences = new YamlAssetMetadata <Guid>();
            var ids = CollectionItemIdHelper.GetCollectionItemIds(obj.ConcreteRefDictionary);

            ids["Item1"] = IdentifierGenerator.Get(1);
            ids["Item2"] = IdentifierGenerator.Get(2);
            var path = new YamlAssetPath();

            path.PushMember(nameof(CollectionContainer.ConcreteRefDictionary));
            path.PushItemId(IdentifierGenerator.Get(1));
            objectReferences.Set(path, GuidGenerator.Get(1));
            var yaml = SerializeAsString(obj, objectReferences);

            Assert.AreEqual(ConcreteReferenceableDictionaryYaml, yaml);
        }
 private static void SetCurrentPath(ref ObjectContext objectContext, YamlAssetPath path)
 {
     objectContext.Properties.Set(MemberPathKey, path);
 }
        public static IAssetNode ResolveObjectPath([NotNull] IAssetNode rootNode, [NotNull] YamlAssetPath path, out Index index, out bool overrideOnKey)
        {
            var currentNode = rootNode;

            index         = Index.Empty;
            overrideOnKey = false;
            for (var i = 0; i < path.Items.Count; i++)
            {
                var item = path.Items[i];
                switch (item.Type)
                {
                case YamlAssetPath.ItemType.Member:
                    index         = Index.Empty;
                    overrideOnKey = false;
                    if (currentNode.IsReference)
                    {
                        var memberNode = currentNode as IMemberNode;
                        if (memberNode == null)
                        {
                            throw new InvalidOperationException($"An IMemberNode was expected when processing the path [{path}]");
                        }
                        currentNode = (IAssetNode)memberNode.Target;
                    }
                    var objectNode = currentNode as IObjectNode;
                    if (objectNode == null)
                    {
                        throw new InvalidOperationException($"An IObjectNode was expected when processing the path [{path}]");
                    }
                    var name = item.AsMember();
                    currentNode = (IAssetNode)objectNode.TryGetChild(name);
                    break;

                case YamlAssetPath.ItemType.Index:
                    index         = new Index(item.Value);
                    overrideOnKey = true;
                    if (currentNode.IsReference && i < path.Items.Count - 1)
                    {
                        currentNode = (IAssetNode)currentNode.IndexedTarget(new Index(item.Value));
                    }
                    break;

                case YamlAssetPath.ItemType.ItemId:
                    var ids = CollectionItemIdHelper.GetCollectionItemIds(currentNode.Retrieve());
                    var key = ids.GetKey(item.AsItemId());
                    index         = new Index(key);
                    overrideOnKey = false;
                    if (currentNode.IsReference && i < path.Items.Count - 1)
                    {
                        currentNode = (IAssetNode)currentNode.IndexedTarget(new Index(key));
                    }
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }

                // Something wrong happen, the node is unreachable.
                if (currentNode == null)
                {
                    return(null);
                }
            }

            return(currentNode);
        }
        public void TestGenerateOverridesForSerializationOfCollectionItem()
        {
            const string expectedYaml = @"!SiliconStudio.Assets.Quantum.Tests.Types+SomeObject,SiliconStudio.Assets.Quantum.Tests
Value*: OverriddenString
";
            var asset = new Types.MyAsset4 { MyObjects = { new Types.SomeObject { Value = "String1" }, new Types.SomeObject { Value = "String2" } } };
            var context = DeriveAssetTest<Types.MyAsset4>.DeriveAsset(asset);
            var derivedPropertyNode = (AssetNode)((IGraphNode)context.DerivedGraph.RootNode)[nameof(Types.MyAsset4.MyObjects)].IndexedTarget(new Index(1));
            derivedPropertyNode[nameof(Types.SomeObject.Value)].Content.Update("OverriddenString");
            var expectedPath = new YamlAssetPath();
            expectedPath.PushMember(nameof(Types.SomeObject.Value));

            var overrides = AssetPropertyGraph.GenerateOverridesForSerialization(derivedPropertyNode);
            Assert.AreEqual(1, overrides.Count);
            Assert.True(overrides.ContainsKey(expectedPath));
            Assert.AreEqual(OverrideType.New, overrides[expectedPath]);

            // Test deserialization
            SerializeAndCompare(context.DerivedAsset.MyObjects[1], overrides, expectedYaml);
            bool aliasOccurred;
            var instance = (Types.SomeObject)AssetFileSerializer.Default.Load(DeriveAssetTest<Types.MyAsset9>.ToStream(expectedYaml), null, null, out aliasOccurred, out overrides);
            Assert.AreEqual("OverriddenString", instance.Value);
            Assert.AreEqual(1, overrides.Count);
            Assert.True(overrides.ContainsKey(expectedPath));
            Assert.AreEqual(OverrideType.New, overrides[expectedPath]);
        }
Example #19
0
        /// <inheritdoc />
        public override bool ProcessDeserializedData(AssetPropertyGraphContainer graphContainer, object targetRootObject, Type targetMemberType, ref object data, bool isRootDataObjectReference, AssetId?sourceId, YamlAssetMetadata <OverrideType> overrides, YamlAssetPath basePath)
        {
            var asset     = (AssetCompositeHierarchy <TAssetPartDesign, TAssetPart>)targetRootObject;
            var hierarchy = data as AssetCompositeHierarchyData <TAssetPartDesign, TAssetPart>;

            if (hierarchy == null)
            {
                return(false);
            }

            // Create a temporary asset to host the hierarchy to paste, so we have a property graph to manipulate it.
            var tempAsset = (AssetCompositeHierarchy <TAssetPartDesign, TAssetPart>)Activator.CreateInstance(asset.GetType());

            tempAsset.Hierarchy = hierarchy;
            // Use temporary containers so that any created nodes are discarded after the processing.
            var tempNodeContainer = new AssetNodeContainer {
                NodeBuilder = { NodeFactory = new AssetNodeFactory() }
            };
            var definition = AssetQuantumRegistry.GetDefinition(asset.GetType());
            var rootNode   = tempNodeContainer.GetOrCreateNode(tempAsset);

            // If different asset or if at least one part already exists, create a custom clone.
            if (asset.Id != sourceId || hierarchy.Parts.Values.Any(part => asset.ContainsPart(part.Part.Id)))
            {
                // Clone again to create new ids for any IIdentifiable, but keep references to external object intact.
                var cloneExternalReferences = ExternalReferenceCollector.GetExternalReferences(definition, rootNode);
                hierarchy = AssetCloner.Clone(hierarchy, AssetClonerFlags.GenerateNewIdsForIdentifiableObjects, cloneExternalReferences, out var idRemapping);
                // Remap indices of parts in Hierarchy.Part
                AssetCloningHelper.RemapIdentifiablePaths(overrides, idRemapping, basePath);
                // Make new base instances ids in case the part are inherited.
                AssetPartsAnalysis.GenerateNewBaseInstanceIds(hierarchy);
                // Update the temporary asset with this cloned hierarchy.
                rootNode[nameof(AssetCompositeHierarchy <TAssetPartDesign, TAssetPart> .Hierarchy)].Update(hierarchy);
            }

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

            // Replace references in the hierarchy being pasted by the real objects from the target asset.
            var externalReferences = new HashSet <Guid>(ExternalReferenceCollector.GetExternalReferences(definition, rootNode).Select(x => x.Id));
            var visitor            = new ObjectReferencePathGenerator(definition)
            {
                ShouldOutputReference = x => externalReferences.Contains(x)
            };

            visitor.Visit(rootNode);

            FixupObjectReferences.FixupReferences(tempAsset, visitor.Result, referenceableObjects, true);

            data = hierarchy;

            return(true);
        }
Example #20
0
        public AssetNode ResolveObjectPath(YamlAssetPath path, out Index index, out bool overrideOnKey)
        {
            var currentNode = this;
            index = Index.Empty;
            overrideOnKey = false;
            for (var i = 0; i < path.Items.Count; i++)
            {
                var item = path.Items[i];
                switch (item.Type)
                {
                    case YamlAssetPath.ItemType.Member:
                        index = Index.Empty;
                        overrideOnKey = false;
                        if (currentNode.Content.IsReference)
                        {
                            currentNode = (AssetNode)((IGraphNode)currentNode).Target;
                        }
                        string name = item.AsMember();
                        currentNode = (AssetNode)((IGraphNode)currentNode).TryGetChild(name);
                        break;
                    case YamlAssetPath.ItemType.Index:
                        index = new Index(item.Value);
                        overrideOnKey = true;
                        if (currentNode.Content.IsReference && i < path.Items.Count - 1)
                        {
                            Index index1 = new Index(item.Value);
                            currentNode = (AssetNode)((IGraphNode)currentNode).IndexedTarget(index1);
                        }
                        break;
                    case YamlAssetPath.ItemType.ItemId:
                        var ids = CollectionItemIdHelper.GetCollectionItemIds(currentNode.Content.Retrieve());
                        var key = ids.GetKey(item.AsItemId());
                        index = new Index(key);
                        overrideOnKey = false;
                        if (currentNode.Content.IsReference && i < path.Items.Count - 1)
                        {
                            Index index1 = new Index(key);
                            currentNode = (AssetNode)((IGraphNode)currentNode).IndexedTarget(index1);
                        }
                        break;
                    default:
                        throw new ArgumentOutOfRangeException();
                }

                // Something wrong happen, the node is unreachable.
                if (currentNode == null)
                    return null;
            }

            return currentNode;
        }
Example #21
0
        public static YamlAssetPath ConvertPath(GraphNodePath path, int inNonIdentifiableType)
        {
            var currentNode = (IAssetNode)path.RootNode;
            var result      = new YamlAssetPath();
            var i           = 0;

            foreach (var item in path.Path)
            {
                switch (item.Type)
                {
                case GraphNodePath.ElementType.Member:
                    var member = (string)item.Value;
                    result.PushMember(member);
                    var objectNode = currentNode as IObjectNode;
                    if (objectNode == null)
                    {
                        throw new InvalidOperationException($"An IObjectNode was expected when processing the path [{path}]");
                    }
                    currentNode = (IAssetNode)objectNode.TryGetChild(member);
                    break;

                case GraphNodePath.ElementType.Target:
                    if (i < path.Path.Count - 1)
                    {
                        var targetingMemberNode = currentNode as IMemberNode;
                        if (targetingMemberNode == null)
                        {
                            throw new InvalidOperationException($"An IMemberNode was expected when processing the path [{path}]");
                        }
                        currentNode = (IAssetNode)targetingMemberNode.Target;
                    }
                    break;

                case GraphNodePath.ElementType.Index:
                    var index      = (Index)item.Value;
                    var memberNode = currentNode as AssetMemberNode;
                    if (memberNode == null)
                    {
                        throw new InvalidOperationException($"An AssetMemberNode was expected when processing the path [{path}]");
                    }
                    if (inNonIdentifiableType > 0 || memberNode.IsNonIdentifiableCollectionContent)
                    {
                        result.PushIndex(index.Value);
                    }
                    else
                    {
                        var id = memberNode.IndexToId(index);
                        // Create a new id if we don't have any so far
                        if (id == ItemId.Empty)
                        {
                            id = ItemId.New();
                        }
                        result.PushItemId(id);
                    }
                    if (i < path.Path.Count - 1)
                    {
                        currentNode = (IAssetNode)currentNode.IndexedTarget(index);
                    }
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }
                ++i;
            }
            return(result);
        }
        public static YamlAssetPath ConvertPath([NotNull] GraphNodePath path, int inNonIdentifiableType = 0)
        {
            if (path == null)
            {
                throw new ArgumentNullException(nameof(path));
            }
            var currentNode = (IAssetNode)path.RootNode;
            var result      = new YamlAssetPath();
            var i           = 0;

            foreach (var item in path.Path)
            {
                switch (item.Type)
                {
                case GraphNodePath.ElementType.Member:
                {
                    var member = item.Name;
                    result.PushMember(member);
                    var objectNode = currentNode as IObjectNode;
                    if (objectNode == null)
                    {
                        throw new InvalidOperationException($"An IObjectNode was expected when processing the path [{path}]");
                    }
                    currentNode = (IAssetNode)objectNode.TryGetChild(member);
                    break;
                }

                case GraphNodePath.ElementType.Target:
                {
                    if (i < path.Path.Count - 1)
                    {
                        var targetingMemberNode = currentNode as IMemberNode;
                        if (targetingMemberNode == null)
                        {
                            throw new InvalidOperationException($"An IMemberNode was expected when processing the path [{path}]");
                        }
                        currentNode = (IAssetNode)targetingMemberNode.Target;
                    }
                    break;
                }

                case GraphNodePath.ElementType.Index:
                {
                    var index      = item.Index;
                    var objectNode = currentNode as AssetObjectNode;
                    if (objectNode == null)
                    {
                        throw new InvalidOperationException($"An IObjectNode was expected when processing the path [{path}]");
                    }
                    if (inNonIdentifiableType > 0 || !CollectionItemIdHelper.HasCollectionItemIds(objectNode.Retrieve()))
                    {
                        result.PushIndex(index.Value);
                    }
                    else
                    {
                        var id = objectNode.IndexToId(index);
                        // Create a new id if we don't have any so far
                        if (id == ItemId.Empty)
                        {
                            id = ItemId.New();
                        }
                        result.PushItemId(id);
                    }
                    if (i < path.Path.Count - 1)
                    {
                        currentNode = (IAssetNode)objectNode.IndexedTarget(index);
                    }
                    break;
                }

                default:
                    throw new ArgumentOutOfRangeException();
                }
                ++i;
            }
            return(result);
        }
Example #23
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);
        }
        public void TestGenerateOverridesForSerializationOfObjectMember()
        {
            const string expectedYaml = @"!SiliconStudio.Assets.Quantum.Tests.Types+SomeObject,SiliconStudio.Assets.Quantum.Tests
Value*: OverriddenString
";
            var asset = new Types.MyAsset9 { MyObject = new Types.SomeObject { Value = "String1" } };
            var context = DeriveAssetTest<Types.MyAsset9>.DeriveAsset(asset);
            var derivedPropertyNode = (AssetNode)((IGraphNode)context.DerivedGraph.RootNode)[nameof(Types.MyAsset9.MyObject)];
            derivedPropertyNode.Target[nameof(Types.SomeObject.Value)].Content.Update("OverriddenString");
            var expectedPath = new YamlAssetPath();
            expectedPath.PushMember(nameof(Types.SomeObject.Value));

            var overrides = AssetPropertyGraph.GenerateOverridesForSerialization(derivedPropertyNode);
            Assert.AreEqual(1, overrides.Count);
            Assert.True(overrides.ContainsKey(expectedPath));
            Assert.AreEqual(OverrideType.New, overrides[expectedPath]);

            // We expect the same resulting path both from the member node and the target object node
            overrides = AssetPropertyGraph.GenerateOverridesForSerialization(derivedPropertyNode.Target);
            Assert.AreEqual(1, overrides.Count);
            Assert.True(overrides.ContainsKey(expectedPath));
            Assert.AreEqual(OverrideType.New, overrides[expectedPath]);

            // Test deserialization
            SerializeAndCompare(context.DerivedAsset.MyObject, overrides, expectedYaml);
            bool aliasOccurred;
            var instance = (Types.SomeObject)AssetFileSerializer.Default.Load(DeriveAssetTestBase.ToStream(expectedYaml), null, null, out aliasOccurred, out overrides);
            Assert.AreEqual("OverriddenString", instance.Value);
            Assert.AreEqual(1, overrides.Count);
            Assert.True(overrides.ContainsKey(expectedPath));
            Assert.AreEqual(OverrideType.New, overrides[expectedPath]);
        }
        /// <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 collectionDescriptor = (CollectionDescriptor)TypeDescriptorFactory.Default.Find(targetRootObject.GetType());

            var collection = data as IList <AssetItem>;

            if (collection == null)
            {
                collection = (IList <AssetItem>)Activator.CreateInstance(collectionDescriptor.Type, true);
                collectionDescriptor.Add(collection, data);
            }

            for (var i = 0; i < collection.Count; i++)
            {
                var assetItem = collection[i];
                // If the asset already exists, clone it with new identifiers
                if (session.GetAssetById(assetItem.Id) != null)
                {
                    // Create a derived asset and restore archetype to handle asset-specific cloning process.
                    Dictionary <Guid, Guid> idRemapping;
                    var clone = AssetCloner.Clone(assetItem.Asset, AssetClonerFlags.GenerateNewIdsForIdentifiableObjects, out idRemapping);

                    var assetType = assetItem.Asset.GetType();
                    if (assetType.HasInterface(typeof(AssetCompositeHierarchy <,>)))
                    {
                        try
                        {
                            // TODO: Find a way to fallback to the asset or generalize for all asset composite
                            dynamic assetComposite = clone;
                            // Remap indices of parts in Hierarchy.Part
                            var path = basePath.Clone();
                            path.PushItemId(CollectionItemIdHelper.GetCollectionItemIds(collection)[i]);
                            AssetCloningHelper.RemapIdentifiablePaths(overrides, idRemapping, path);
                            AssetPartsAnalysis.GenerateNewBaseInstanceIds(assetComposite.Hierarchy);
                        }
                        catch (RuntimeBinderException e)
                        {
                            e.Ignore();
                        }
                    }
                    // FIXME: rework this
                    var postProcessor = session.ServiceProvider.Get <ICopyPasteService>().PostProcessors.FirstOrDefault(p => p.Accept(assetType));
                    postProcessor?.PostPasteDeserialization(clone);
                    collection[i] = new AssetItem(assetItem.Location, clone);
                }
            }

            // Get the fixed-up value
            data = collection;
            return(true);
        }
Example #26
0
 /// <inheritdoc />
 public abstract bool ProcessDeserializedData(AssetPropertyGraphContainer graphContainer, object targetRootObject, Type targetMemberType, ref object data, bool isRootDataObjectReference, AssetId?sourceId, YamlAssetMetadata <OverrideType> overrides, YamlAssetPath basePath);
 private static void SetCurrentPath(ref ObjectContext objectContext, YamlAssetPath path)
 {
     objectContext.Properties.Set(MemberPathKey, path);
 }