/// <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); }
private void RegisterComponent(EntityComponent component) { if (component != null && ComponentType.IsInstanceOfType(component)) { var rootNode = controller.GameSideNodeContainer.GetOrCreateNode(component); var listener = new AssetGraphNodeChangeListener(rootNode, AssetQuantumRegistry.GetDefinition(typeof(EntityHierarchyAssetBase))); listener.Initialize(); listener.ValueChanged += ComponentPropertyChanged; listener.ItemChanged += ComponentPropertyChanged; registeredListeners.Add(component, listener); } }
/// <inheritdoc/> protected override Dictionary <Guid, IIdentifiable> CollectIdentifiableObjects() { var allElements = RootElements.Values.BreadthFirst(x => x.VisualChildren); var definition = AssetQuantumRegistry.GetDefinition(Asset.Asset.GetType()); var identifiableObjects = new Dictionary <Guid, IIdentifiable>(); foreach (var entityNode in allElements.Select(x => GameSideNodeContainer.GetOrCreateNode(x))) { foreach (var identifiable in IdentifiableObjectCollector.Collect(definition, entityNode)) { identifiableObjects.Add(identifiable.Key, identifiable.Value); } } return(identifiableObjects); }
/// <inheritdoc/> protected override Dictionary <Guid, IIdentifiable> CollectIdentifiableObjects() { var allEntities = Game.ContentScene.Yield().BreadthFirst(x => x.Children).SelectMany(x => x.Entities).BreadthFirst(x => x.Transform.Children.Select(y => y.Entity)); var definition = AssetQuantumRegistry.GetDefinition(Asset.Asset.GetType()); var identifiableObjects = new Dictionary <Guid, IIdentifiable>(); foreach (var entityNode in allEntities.Select(x => GameSideNodeContainer.GetOrCreateNode(x))) { foreach (var identifiable in IdentifiableObjectCollector.Collect(definition, entityNode)) { identifiableObjects.Add(identifiable.Key, identifiable.Value); } } return(identifiableObjects); }
protected IEnumerable <TAssetPart> ClonePartsForGameSide([NotNull] AssetCompositeHierarchy <TAssetPartDesign, TAssetPart> asset, [NotNull] IEnumerable <TAssetPart> parts) { var flags = SubHierarchyCloneFlags.RemoveOverrides; var sourceContainer = Asset.PropertyGraph.Container.NodeContainer; var targetContainer = GameSideNodeContainer; var clone = AssetCompositeHierarchyPropertyGraph <TAssetPartDesign, TAssetPart> .CloneSubHierarchies(sourceContainer, targetContainer, asset, parts.Select(p => p.Id), flags, out _); // Collect external references after cloning, we need to fix them up! var rootNode = GameSideNodeContainer.GetOrCreateNode(clone); var definition = AssetQuantumRegistry.GetDefinition(asset.GetType()); var unresolvedReferences = ExternalReferenceCollector.GetExternalReferenceAccessors(definition, rootNode); // Retrieve all available game-side identifiable objects, so we can try to resolve external references with items from this collection. var identifiableObjects = CollectIdentifiableObjects(); foreach (var reference in unresolvedReferences) { if (identifiableObjects.TryGetValue(reference.Key.Id, out var realObject)) { // Target object found, let's update the reference with the real game-side object. foreach (var accessor in reference.Value) { accessor.UpdateValue(realObject); } } else { // Target object not found, let's clear the reference since the currently set object could be asset-side, or a temporary proxy, etc. foreach (var accessor in reference.Value) { accessor.UpdateValue(null); } } } return(clone.RootParts); }