public AssetContentValueChangeOperation(IAssetNode node, ContentChangeType changeType, NodeIndex index, object oldValue, object newValue, OverrideType previousOverride, OverrideType newOverride, ItemId itemId, IEnumerable <IDirtiable> dirtiables) : base(node, changeType, index, oldValue, newValue, dirtiables) { this.previousOverride = previousOverride; this.itemId = itemId; this.newOverride = newOverride; }
public void ReconcileWithBase(IAssetNode rootNode) { var visitor = CreateReconcilierVisitor(); visitor.Visiting += (node, path) => ReconcileWithBaseNode(node as AssetMemberNode); visitor.Visit(rootNode); }
/// <summary> /// Resets the overrides attached to the given node and its descendants, recursively. /// </summary> /// <param name="rootNode">The node for which to reset overrides.</param> /// <param name="indexToReset">The index of the override to reset in this node, if relevant.</param> public void ResetOverride(IAssetNode rootNode, Index indexToReset) { var visitor = CreateReconcilierVisitor(); visitor.SkipRootNode = true; visitor.Visiting += (node, path) => { var childNode = node as AssetMemberNode; if (childNode == null) { return; } childNode.OverrideContent(false); foreach (var overrideItem in childNode.GetOverriddenItemIndices()) { childNode.OverrideItem(false, overrideItem); } foreach (var overrideKey in childNode.GetOverriddenKeyIndices()) { childNode.OverrideKey(false, overrideKey); } }; visitor.Visit(rootNode); ReconcileWithBase(rootNode); }
protected virtual object CloneObjectForGameSide(object assetSideObject, IAssetNode assetNode, IGraphNode gameSideNode) { // Null references, they will be handled by the editor asset loader var gameSideValue = AssetCloner.Clone(assetSideObject, AssetClonerFlags.ReferenceAsNull); return(gameSideValue); }
/// <inheritdoc/> protected override bool CanUpdate(IAssetNode node, ContentChangeType changeType, NodeIndex index, object value) { // Check if we are in the component collection of an entity (where we actually add new components) if (IsComponentForComponentCollection(node, value) && changeType == ContentChangeType.CollectionAdd) { var componentType = value.GetType(); var attributes = EntityComponentAttributes.Get(componentType); var onlySingleComponent = !attributes.AllowMultipleComponents; var collection = (EntityComponentCollection)node.Retrieve(); foreach (var existingItem in collection) { if (ReferenceEquals(existingItem, value)) { return(false); } if (onlySingleComponent && componentType == existingItem.GetType()) { return(false); } } } return(base.CanUpdate(node, changeType, index, value)); }
protected override object CloneObjectForGameSide(object assetSideObject, IAssetNode assetNode, IGraphNode gameSideNode) { // TODO: this is very similar to what AssetPropertyGraph.CloneValueFromBase is doing, except that the base cloner is different. Try to factorize! if (gameSideNode.Type == typeof(EntityComponentCollection) && assetSideObject is TransformComponent) { // We never clone TransformComponent, we cannot replace them. Instead, return the existing one. var transformComponent = (TransformComponent)gameSideNode.Retrieve(new NodeIndex(0)); // We still reset the Entity to null to make sure it works nicely with reconcilation, etc. transformComponent.Entity = null; return(transformComponent); } var gameSideValue = base.CloneObjectForGameSide(assetSideObject, assetNode, gameSideNode); // Important: In case of component, because of the Entitycomponent serializer is serializing the entity (with all its components) // We are clearing the entity of the component, so that this object can be added to the game side part. var entityComponent = gameSideValue as EntityComponent; if (entityComponent != null) { entityComponent.Entity = null; } return(gameSideValue); }
public void RegisterBaseToDerived(IAssetNode baseNode, IAssetNode derivedNode) { var ownerPart = derivedNode.GetContent(NodesToOwnerPartVisitor.OwnerPartContentName); var instanceId = (ownerPart?.Retrieve() as IAssetPartDesign)?.Base?.InstanceId ?? Guid.Empty; AssetBaseToDerivedRegistry derivedRegistry; if (!baseToInstances.TryGetValue(instanceId, out derivedRegistry)) { baseToInstances[instanceId] = derivedRegistry = new AssetBaseToDerivedRegistry(propertyGraph); } derivedRegistry.RegisterBaseToDerived(baseNode, derivedNode); }
private void RelinkToOwnerPart([NotNull] IAssetNode node, object newValue) { var partDesign = (TAssetPartDesign)node.GetContent(NodesToOwnerPartVisitor.OwnerPartContentName)?.Retrieve(); if (partDesign != null) { // A property of a part has changed LinkToOwnerPart(node, partDesign); } else if (node.Type == typeof(AssetPartCollection <TAssetPartDesign, TAssetPart>) && newValue is TAssetPartDesign) { // A new part has been added partDesign = (TAssetPartDesign)newValue; LinkToOwnerPart(Container.NodeContainer.GetNode(partDesign.Part), partDesign); } }
public IIdentifiable ResolveFromBase(object baseObjectReference, IAssetNode derivedReferencerNode) { if (derivedReferencerNode == null) { throw new ArgumentNullException(nameof(derivedReferencerNode)); } if (baseObjectReference == null) { return(null); } var baseNode = (IAssetNode)propertyGraph.Container.NodeContainer.GetNode(baseObjectReference); IAssetNode derivedNode; baseToDerived.TryGetValue(baseNode, out derivedNode); return(derivedNode?.Retrieve() as IIdentifiable); }
public IIdentifiable ResolveFromBase(object baseObjectReference, IAssetNode derivedReferencerNode) { if (derivedReferencerNode == null) { throw new ArgumentNullException(nameof(derivedReferencerNode)); } var ownerPart = derivedReferencerNode.GetContent(NodesToOwnerPartVisitor.OwnerPartContentName); var instanceId = (ownerPart?.Retrieve() as IAssetPartDesign)?.Base?.InstanceId ?? Guid.Empty; AssetBaseToDerivedRegistry derivedRegistry; if (!baseToInstances.TryGetValue(instanceId, out derivedRegistry)) { return(null); } return(derivedRegistry.ResolveFromBase(baseObjectReference, derivedReferencerNode)); }
public void RegisterBaseToDerived(IAssetNode baseNode, IAssetNode derivedNode) { var baseValue = baseNode?.Retrieve(); if (baseValue == null) { return; } if (baseValue is IIdentifiable) { baseToDerived[baseNode] = derivedNode; var baseMemberNode = baseNode as IAssetMemberNode; if (baseMemberNode?.Target != null && !propertyGraph.Definition.IsMemberTargetObjectReference(baseMemberNode, baseValue)) { baseToDerived[baseMemberNode.Target] = ((IAssetMemberNode)derivedNode).Target; } } var derivedObjectNode = derivedNode as IObjectNode; var baseObjectNode = baseNode as IObjectNode; if (derivedObjectNode?.ItemReferences != null && baseObjectNode?.ItemReferences != null) { foreach (var reference in derivedObjectNode.ItemReferences) { var target = propertyGraph.baseLinker.FindTargetReference(derivedNode, baseNode, reference); if (target == null) { continue; } baseValue = target.TargetNode?.Retrieve(); if (!propertyGraph.Definition.IsTargetItemObjectReference(baseObjectNode, target.Index, baseNode.Retrieve(target.Index))) { if (baseValue is IIdentifiable) { baseToDerived[(IAssetNode)target.TargetNode] = (IAssetNode)derivedObjectNode.IndexedTarget(reference.Index); } } } } }
protected internal override object CloneValueFromBase(object value, IAssetNode node) { var part = value as TAssetPart; // Part reference if (part != null) { // We need to find out for which entity we are cloning this (other) entity var owner = (TAssetPartDesign)node?.GetContent(NodesToOwnerPartVisitor.OwnerPartContentName).Retrieve(); if (owner != null) { // Then instead of creating a clone, we just return the corresponding part in this asset (in term of base and base instance) var partInDerived = AssetHierarchy.Hierarchy.Parts.FirstOrDefault(x => x.Base?.BasePartId == part.Id && x.Base?.InstanceId == owner.Base?.InstanceId); return(partInDerived?.Part); } } var result = base.CloneValueFromBase(value, node); return(result); }
/// <inheritdoc/> protected override object CloneValueFromBase(object value, IAssetNode node) { // TODO: check CloneObjectForGameSide if modifying this method, the logic should be factorized at some point. if (IsComponentForComponentCollection(node, value) && value is TransformComponent) { // We never clone TransformComponent, we cannot replace them. Instead, return the existing one. var transformComponent = (TransformComponent)node.Retrieve(new Index(0)); // We still reset the Entity to null to make sure it works nicely with reconcilation, etc. transformComponent.Entity = null; return transformComponent; } var clone = base.CloneValueFromBase(value, node); var component = clone as EntityComponent; if (component != null) { // Components need their Entity to be cleared first because subsequent actions will try to restore it and safeguards might throw if it's not null beforehand component.Entity = null; } return clone; }
public static void ApplyOverrides(IAssetNode rootNode, IDictionary <YamlAssetPath, OverrideType> overrides) { if (rootNode == null) { throw new ArgumentNullException(nameof(rootNode)); } if (overrides == null) { return; } foreach (var overrideInfo in overrides) { Index index; bool overrideOnKey; var node = ResolveObjectPath(rootNode, overrideInfo.Key, out index, out overrideOnKey) as AssetMemberNode; // The node is unreachable, skip this override. if (node == null) { continue; } if (index == Index.Empty) { node.SetContentOverride(overrideInfo.Value); } else if (!overrideOnKey) { node.SetItemOverride(overrideInfo.Value, index); } else { node.SetKeyOverride(overrideInfo.Value, index); } } }
public void Visit([NotNull] IAssetNode node, NodeIndex index) { if (index == NodeIndex.Empty) { // Normal case, no index Visit(node); } else if (node.IsReference) { // We have an index, and our collection is a collection of reference types, then start visit from the target item var target = ((IObjectNode)node).IndexedTarget(index); if (target != null) { Visit(target); } } else if (AssetRegistry.IsContentType(node.Descriptor.GetInnerCollectionType())) { // We have an index, and our collection is directly a collection of content type. Let's just collect the corresponding item. var gameContent = node.GetContent("Game"); var id = AttachedReferenceManager.GetAttachedReference(node.Retrieve(index))?.Id ?? AssetId.Empty; CollectContentReference(id, gameContent, index); } }
/// <inheritdoc/> public override void RefreshBase(IAssetNode node, IAssetNode baseNode) { base.RefreshBase(node, baseNode); UpdateAssetPartBases(); }
protected internal virtual object CloneValueFromBase(object value, IAssetNode node) { return(CloneFromBase(value)); }
// TODO: this method is should be called in every scenario of ReconcileWithBase, it is not the case yet. protected virtual bool CanUpdate(IAssetNode node, ContentChangeType changeType, Index index, object value) { return(true); }
// TODO: turn private public void LinkToBase(IAssetNode sourceRootNode, IAssetNode targetRootNode) { baseLinker.ShouldVisit = (member, node) => (node == sourceRootNode || !baseLinkedNodes.ContainsKey((IAssetNode)node)) && ShouldListenToTargetNode(member, node); baseLinker.LinkGraph(sourceRootNode, targetRootNode); }
public static OverrideType GetKeyOverride(this IAssetNode node, Index index) { return(((IAssetObjectNodeInternal)node).GetKeyOverride(index)); }
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); }