public TestCopyPasteProperties() { propertyGraphContainer = new AssetPropertyGraphContainer(new AssetNodeContainer { NodeBuilder = { NodeFactory = new AssetNodeFactory() } }); service = TestHelper.CreateCopyPasteService(propertyGraphContainer); }
public static DeriveAssetTest <TAsset, TAssetPropertyGraph> DeriveAsset(TAsset baseAsset, bool deriveTwice = true) { var container = new AssetPropertyGraphContainer(new AssetNodeContainer { NodeBuilder = { NodeFactory = new AssetNodeFactory() } }); var baseContainer = new AssetTestContainer <TAsset, TAssetPropertyGraph>(container, baseAsset); baseContainer.BuildGraph(); var derivedAsset = (TAsset)baseContainer.Asset.CreateDerivedAsset("MyAsset"); var derivedContainer = new AssetTestContainer <TAsset, TAssetPropertyGraph>(baseContainer.Container, derivedAsset); derivedContainer.BuildGraph(); derivedContainer.Graph.RefreshBase(); AssetTestContainer <TAsset, TAssetPropertyGraph> subDerivedContainer = null; if (deriveTwice) { var subDerivedAsset = (TAsset)derivedContainer.Asset.CreateDerivedAsset("MySubAsset"); subDerivedContainer = new AssetTestContainer <TAsset, TAssetPropertyGraph>(baseContainer.Container, subDerivedAsset); subDerivedContainer.BuildGraph(); subDerivedContainer.Graph.RefreshBase(); } var result = new DeriveAssetTest <TAsset, TAssetPropertyGraph>(baseContainer, derivedContainer, subDerivedContainer); return(result); }
/// <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); }
public void TestCollectionItemIdentifierWithDuplicates() { var container = new AssetPropertyGraphContainer(new AssetNodeContainer { NodeBuilder = { NodeFactory = new AssetNodeFactory() } }); var asset = new Types.MyAsset2 { MyStrings = { "aaa", "bbb", "ccc" } }; var ids = CollectionItemIdHelper.GetCollectionItemIds(asset.MyStrings); ids.Add(0, IdentifierGenerator.Get(100)); ids.Add(1, IdentifierGenerator.Get(200)); ids.Add(2, IdentifierGenerator.Get(100)); var assetItem = new AssetItem("MyAsset", asset); Assert.Equal(IdentifierGenerator.Get(100), ids[0]); Assert.Equal(IdentifierGenerator.Get(200), ids[1]); Assert.Equal(IdentifierGenerator.Get(100), ids[2]); var graph = AssetQuantumRegistry.ConstructPropertyGraph(container, assetItem, null); Assert.IsAssignableFrom <AssetObjectNode>(graph.RootNode); Assert.True(CollectionItemIdHelper.TryGetCollectionItemIds(asset.MyStrings, out ids)); Assert.Equal(3, ids.KeyCount); Assert.Equal(0, ids.DeletedCount); Assert.Equal(IdentifierGenerator.Get(100), ids[0]); Assert.Equal(IdentifierGenerator.Get(200), ids[1]); Assert.NotEqual(IdentifierGenerator.Get(100), ids[2]); Assert.NotEqual(IdentifierGenerator.Get(200), ids[2]); }
protected DeriveAssetTestBase(Asset baseAsset, Asset derivedAsset) { Container = new AssetPropertyGraphContainer(new PackageSession(), new AssetNodeContainer { NodeBuilder = { ContentFactory = new AssetNodeFactory() } }); BaseAssetItem = new AssetItem("MyAsset", baseAsset); DerivedAssetItem = new AssetItem("MyDerivedAsset", derivedAsset); }
public void TestSimpleConstruction() { var container = new AssetPropertyGraphContainer(new PackageSession(), new AssetNodeContainer()); var asset = new Types.MyAsset1 { MyString = "String" }; var assetItem = new AssetItem("MyAsset", asset); var graph = AssetQuantumRegistry.ConstructPropertyGraph(container, assetItem, null); Assert.IsAssignableFrom<AssetNode>(graph.RootNode); }
public static ICopyPasteService CreateCopyPasteService() { var propertyGraphContainer = new AssetPropertyGraphContainer(new AssetNodeContainer { NodeBuilder = { NodeFactory = new AssetNodeFactory() } }); return(CreateCopyPasteService(propertyGraphContainer)); }
public void TestSimpleCollectionUpdate() { var container = new AssetPropertyGraphContainer(new PackageSession(), new AssetNodeContainer()); var asset = new Types.MyAsset2 { MyStrings = { "aaa", "bbb", "ccc" } }; var assetItem = new AssetItem("MyAsset", asset); var graph = AssetQuantumRegistry.ConstructPropertyGraph(container, assetItem, null); var node = ((IGraphNode)graph.RootNode).TryGetChild(nameof(Types.MyAsset2.MyStrings)); //var ids = CollectionItemIdHelper.TryGetCollectionItemIds(asset.MyStrings, out itemIds); }
protected CopyPasteTest([NotNull] Asset asset) { Container = new AssetPropertyGraphContainer(new AssetNodeContainer { NodeBuilder = { NodeFactory = new AssetNodeFactory() } }); AssetItem = new AssetItem("MyAsset", asset); var assetGraph = AssetQuantumRegistry.ConstructPropertyGraph(Container, AssetItem, null); Assert.IsAssignableFrom <EntityHierarchyPropertyGraph>(assetGraph); AssetGraph = (EntityHierarchyPropertyGraph)assetGraph; }
public void TestSimpleConstruction() { var container = new AssetPropertyGraphContainer(new PackageSession(), new AssetNodeContainer()); var asset = new Types.MyAsset1 { MyString = "String" }; var assetItem = new AssetItem("MyAsset", asset); var graph = AssetQuantumRegistry.ConstructPropertyGraph(container, assetItem, null); Assert.IsAssignableFrom <AssetNode>(graph.RootNode); }
/// <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); }
public static ICopyPasteService CreateCopyPasteService(AssetPropertyGraphContainer propertyGraphContainer) { // CopyPasteService is internal var serviceType = typeof(Xenko.Core.Assets.Editor.EditorPath).Assembly.GetType("Xenko.Core.Assets.Editor.Services.CopyPasteService"); var service = (ICopyPasteService)Activator.CreateInstance(serviceType, propertyGraphContainer); service.RegisterProcessor(new AssetPropertyPasteProcessor()); service.RegisterProcessor(new EntityComponentPasteProcessor()); service.RegisterProcessor(new EntityHierarchyPasteProcessor()); return(service); }
public void TestSimpleConstruction() { var container = new AssetPropertyGraphContainer(new AssetNodeContainer { NodeBuilder = { NodeFactory = new AssetNodeFactory() } }); var asset = new Types.MyAsset1 { MyString = "String" }; var assetItem = new AssetItem("MyAsset", asset); var graph = AssetQuantumRegistry.ConstructPropertyGraph(container, assetItem, null); Assert.IsAssignableFrom <AssetObjectNode>(graph.RootNode); }
public static Types.MyAssetHierarchyPropertyGraph BuildAssetAndGraph(int rootCount, int depth, int childPerPart, Action <AssetCompositeHierarchyData <Types.MyPartDesign, Types.MyPart> > initializeProperties = null) { var container = new AssetPropertyGraphContainer(new AssetNodeContainer { NodeBuilder = { NodeFactory = new AssetNodeFactory() } }); var asset = BuildHierarchy(rootCount, depth, childPerPart); var assetItem = new AssetItem("MyAsset", asset); initializeProperties?.Invoke(asset.Hierarchy); var graph = (Types.MyAssetHierarchyPropertyGraph)AssetQuantumRegistry.ConstructPropertyGraph(container, assetItem, null); return(graph); }
public void TestSimpleCollectionUpdate() { var container = new AssetPropertyGraphContainer(new AssetNodeContainer { NodeBuilder = { NodeFactory = new AssetNodeFactory() } }); var asset = new Types.MyAsset2 { MyStrings = { "aaa", "bbb", "ccc" } }; var assetItem = new AssetItem("MyAsset", asset); var graph = AssetQuantumRegistry.ConstructPropertyGraph(container, assetItem, null); var node = graph.RootNode[nameof(Types.MyAsset2.MyStrings)]; //var ids = CollectionItemIdHelper.TryGetCollectionItemIds(asset.MyStrings, out itemIds); }
public void TestNestedCollectionConstruction() { var container = new AssetPropertyGraphContainer(new PackageSession(), new AssetNodeContainer()); var asset = new Types.MyAsset7 { MyAsset2 = new Types.MyAsset2 { MyStrings = { "aaa", "bbb", "ccc" } } }; var assetItem = new AssetItem("MyAsset", asset); var graph = AssetQuantumRegistry.ConstructPropertyGraph(container, assetItem, null); Assert.IsAssignableFrom<AssetNode>(graph.RootNode); CollectionItemIdentifiers ids; Assert.True(CollectionItemIdHelper.TryGetCollectionItemIds(asset.MyAsset2.MyStrings, out ids)); Assert.AreEqual(3, ids.KeyCount); Assert.AreEqual(0, ids.DeletedCount); Assert.True(ids.ContainsKey(0)); Assert.True(ids.ContainsKey(1)); Assert.True(ids.ContainsKey(2)); }
public static AssetPropertyGraph ConstructPropertyGraph(AssetPropertyGraphContainer container, AssetItem assetItem, ILogger logger) { var assetType = assetItem.Asset.GetType(); while (assetType != null) { Type propertyGraphType; var typeToTest = assetType.IsGenericType ? assetType.GetGenericTypeDefinition() : assetType; if (NodeGraphTypes.TryGetValue(typeToTest, out propertyGraphType)) { return (AssetPropertyGraph)Activator.CreateInstance(propertyGraphType, container, assetItem, logger); } assetType = assetType.BaseType; } throw new InvalidOperationException("No AssetPropertyGraph type matching the given asset type has been found"); }
public AssetPropertyGraph(AssetPropertyGraphContainer container, AssetItem assetItem, ILogger logger) { if (container == null) throw new ArgumentNullException(nameof(container)); if (assetItem == null) throw new ArgumentNullException(nameof(assetItem)); Container = container; AssetCollectionItemIdHelper.GenerateMissingItemIds(assetItem.Asset); CollectionItemIdsAnalysis.FixupItemIds(assetItem, logger); Asset = assetItem.Asset; RootNode = (AssetNode)Container.NodeContainer.GetOrCreateNode(assetItem.Asset); ApplyOverrides(RootNode, assetItem.Overrides); nodeListener = new GraphNodeChangeListener(RootNode, ShouldListenToTargetNode); nodeListener.Changing += AssetContentChanging; nodeListener.Changed += AssetContentChanged; baseLinker = new AssetToBaseNodeLinker(this) { LinkAction = LinkBaseNode }; }
public static DeriveAssetTest <TAsset, TAssetPropertyGraph> LoadFromYaml(string baseYaml, string derivedYaml) { var container = new AssetPropertyGraphContainer(new AssetNodeContainer { NodeBuilder = { NodeFactory = new AssetNodeFactory() } }); var baseAsset = AssetFileSerializer.Load <TAsset>(AssetTestContainer.ToStream(baseYaml), $"MyAsset{Types.FileExtension}"); var derivedAsset = AssetFileSerializer.Load <TAsset>(AssetTestContainer.ToStream(derivedYaml), $"MyDerivedAsset{Types.FileExtension}"); var baseContainer = new AssetTestContainer <TAsset, TAssetPropertyGraph>(container, baseAsset.Asset); var derivedContainer = new AssetTestContainer <TAsset, TAssetPropertyGraph>(container, derivedAsset.Asset); baseAsset.YamlMetadata.CopyInto(baseContainer.AssetItem.YamlMetadata); derivedAsset.YamlMetadata.CopyInto(derivedContainer.AssetItem.YamlMetadata); baseContainer.BuildGraph(); derivedContainer.BuildGraph(); var result = new DeriveAssetTest <TAsset, TAssetPropertyGraph>(baseContainer, derivedContainer, null); derivedContainer.Graph.RefreshBase(); return(result); }
public void TestCollectionConstruction() { var container = new AssetPropertyGraphContainer(new PackageSession(), new AssetNodeContainer()); var asset = new Types.MyAsset2 { MyStrings = { "aaa", "bbb", "ccc" } }; var assetItem = new AssetItem("MyAsset", asset); var graph = AssetQuantumRegistry.ConstructPropertyGraph(container, assetItem, null); Assert.IsAssignableFrom <AssetNode>(graph.RootNode); CollectionItemIdentifiers ids; Assert.True(CollectionItemIdHelper.TryGetCollectionItemIds(asset.MyStrings, out ids)); Assert.AreEqual(3, ids.KeyCount); Assert.AreEqual(0, ids.DeletedCount); Assert.True(ids.ContainsKey(0)); Assert.True(ids.ContainsKey(1)); Assert.True(ids.ContainsKey(2)); }
public void TestCollectionItemIdentifierWithDuplicates() { var container = new AssetPropertyGraphContainer(new PackageSession(), new AssetNodeContainer()); var asset = new Types.MyAsset2 { MyStrings = { "aaa", "bbb", "ccc" } }; var ids = CollectionItemIdHelper.GetCollectionItemIds(asset.MyStrings); ids.Add(0, IdentifierGenerator.Get(100)); ids.Add(1, IdentifierGenerator.Get(200)); ids.Add(2, IdentifierGenerator.Get(100)); var assetItem = new AssetItem("MyAsset", asset); Assert.AreEqual(IdentifierGenerator.Get(100), ids[0]); Assert.AreEqual(IdentifierGenerator.Get(200), ids[1]); Assert.AreEqual(IdentifierGenerator.Get(100), ids[2]); var graph = AssetQuantumRegistry.ConstructPropertyGraph(container, assetItem, null); Assert.IsAssignableFrom<AssetNode>(graph.RootNode); Assert.True(CollectionItemIdHelper.TryGetCollectionItemIds(asset.MyStrings, out ids)); Assert.AreEqual(3, ids.KeyCount); Assert.AreEqual(0, ids.DeletedCount); Assert.AreEqual(IdentifierGenerator.Get(100), ids[0]); Assert.AreEqual(IdentifierGenerator.Get(200), ids[1]); Assert.AreNotEqual(IdentifierGenerator.Get(100), ids[2]); Assert.AreNotEqual(IdentifierGenerator.Get(200), ids[2]); }
/// <inheritdoc /> public abstract bool ProcessDeserializedData(AssetPropertyGraphContainer graphContainer, object targetRootObject, Type targetMemberType, ref object data, bool isRootDataObjectReference, AssetId?sourceId, YamlAssetMetadata <OverrideType> overrides, YamlAssetPath basePath);
public static AssetTestContainer <Types.MyAssetHierarchy, Types.MyAssetHierarchyPropertyGraph> BuildAssetContainer(int rootCount, int depth, int childPerPart, AssetPropertyGraphContainer graphContainer = null, Action <AssetCompositeHierarchyData <Types.MyPartDesign, Types.MyPart> > initializeProperties = null) { graphContainer = graphContainer ?? new AssetPropertyGraphContainer(new AssetNodeContainer { NodeBuilder = { NodeFactory = new AssetNodeFactory() } }); var asset = BuildHierarchy(rootCount, depth, childPerPart); initializeProperties?.Invoke(asset.Hierarchy); var container = new AssetTestContainer <Types.MyAssetHierarchy, Types.MyAssetHierarchyPropertyGraph>(graphContainer, asset); container.BuildGraph(); return(container); }
protected DeriveAssetTestBase(Asset baseAsset, Asset derivedAsset) { Container = new AssetPropertyGraphContainer(new PackageSession(), new AssetNodeContainer()); BaseAssetItem = new AssetItem("MyAsset", baseAsset); DerivedAssetItem = new AssetItem("MyDerivedAsset", derivedAsset); }
public CopyPasteService(AssetPropertyGraphContainer propertyGraphContainer) { // NOTE: this constructor is used through reflection by unit tests! PropertyGraphContainer = propertyGraphContainer; }
public MyAssetBasePropertyGraph(AssetPropertyGraphContainer container, AssetItem assetItem, ILogger logger) : base(container, assetItem, logger) { }
/// <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 EntityHierarchyPropertyGraph(AssetPropertyGraphContainer container, AssetItem assetItem, ILogger logger) : base(container, assetItem, logger) { }
public AssetCompositePropertyGraph(AssetPropertyGraphContainer container, AssetItem assetItem, ILogger logger) : base(container, assetItem, logger) { }
public AssetTestContainer(AssetPropertyGraphContainer container, Asset asset) { Container = container; AssetItem = new AssetItem("MyAsset", asset); }