Пример #1
0
        /// <summary>
        /// Tries to parse an asset reference in the format "GUID:Location".
        /// </summary>
        /// <param name="referenceType"></param>
        /// <param name="assetReferenceText">The asset reference.</param>
        /// <param name="assetReference">The reference.</param>
        /// <returns><c>true</c> if parsing was successful, <c>false</c> otherwise.</returns>
        public static bool TryParse(Type referenceType, string assetReferenceText, out AssetReference assetReference)
        {
            if (referenceType == null)
            {
                throw new ArgumentNullException("referenceType");
            }
            if (assetReferenceText == null)
            {
                throw new ArgumentNullException("assetReferenceText");
            }

            assetReference = null;
            Guid  guid;
            UFile location;
            Guid  referenceId;

            if (!TryParse(assetReferenceText, out referenceId, out guid, out location))
            {
                return(false);
            }
            assetReference = New(referenceType, guid, location);
            if (referenceId != Guid.Empty)
            {
                IdentifiableHelper.SetId(assetReference, referenceId);
            }
            return(true);
        }
Пример #2
0
        public void TestResolveCollectionBroken()
        {
            var memberPath = new MemberPath();

            memberPath.Push(MemberSubs);
            memberPath.Push(ListClassDesc, 0);

            var referenceElt = new MyClass();

            IdentifiableHelper.SetId(referenceElt, Guid.NewGuid());

            var reference = new MyClass {
                Subs = { referenceElt }
            };
            var dual = new MyClass();

            dual.Subs.Add(new MyClass());
            dual.Subs.Add(new MyClass());

            var resolvedPaths = memberPath.Resolve(reference, dual).ToList();

            Assert.AreEqual(0, resolvedPaths.Count);

            memberPath = new MemberPath();
            memberPath.Push(MemberSubs);
            memberPath.Push(ListClassDesc, 1);

            resolvedPaths = memberPath.Resolve(reference, dual).ToList();
            Assert.AreEqual(0, resolvedPaths.Count);
        }
Пример #3
0
        protected override void TransformObjectAfterRead(ref ObjectContext objectContext)
        {
            if (IsSerializingAsReference)
            {
                // Transform the deserialized reference into a fake Entity, EntityComponent, etc...
                // Fake objects will later be fixed later with EntityAnalysis.FixupEntityReferences()
                if (!objectContext.SerializerContext.IsSerializing)
                {
                    var entityComponentReference = objectContext.Instance as EntityComponentReference;
                    if (entityComponentReference != null)
                    {
                        var entityReference = new Entity {
                            Id = entityComponentReference.Entity.Id
                        };
                        var entityComponent = (EntityComponent)Activator.CreateInstance(entityComponentReference.ComponentType);
                        IdentifiableHelper.SetId(entityComponent, entityComponentReference.Id);
                        entityComponent.Entity = entityReference;

                        objectContext.Instance = entityComponent;
                    }
                    else if (objectContext.Instance is EntityReference)
                    {
                        objectContext.Instance = new Entity {
                            Id = ((EntityReference)objectContext.Instance).Id
                        };
                    }
                    else
                    {
                        base.TransformObjectAfterRead(ref objectContext);
                    }
                }
            }
        }
Пример #4
0
        protected override object ResolveReference(object partReference)
        {
            var entityComponentReference = partReference as EntityComponent;

            if (entityComponentReference != null)
            {
                var containingEntity = entityComponentReference.Entity;
                if (containingEntity == null)
                {
                    throw new InvalidOperationException("Found a reference to a component which doesn't have any entity");
                }

                var realEntity = (Entity)base.ResolveReference(containingEntity);
                if (realEntity == null)
                {
                    return(null);
                }

                var componentId   = IdentifiableHelper.GetId(entityComponentReference);
                var realComponent = realEntity.Components.FirstOrDefault(c => IdentifiableHelper.GetId(c) == componentId);
                return(realComponent);
            }

            return(base.ResolveReference(partReference));
        }
Пример #5
0
        private static void FixupEntityReferences(object rootToVisit, EntityHierarchyData entityHierarchy)
        {
            var entityAnalysisResult = Visit(rootToVisit);

            // Reverse the list, so that we can still properly update everything
            // (i.e. if we have a[0], a[1], a[1].Test, we have to do it from back to front to be valid at each step)
            entityAnalysisResult.EntityReferences.Reverse();

            // Updates Entity/EntityComponent references
            foreach (var entityLink in entityAnalysisResult.EntityReferences)
            {
                object obj = null;

                if (entityLink.EntityComponent != null)
                {
                    var containingEntity = entityLink.EntityComponent.Entity;
                    if (containingEntity == null)
                    {
                        throw new InvalidOperationException("Found a reference to a component which doesn't have any entity");
                    }

                    EntityDesign realEntity;
                    if (entityHierarchy.Entities.TryGetValue(containingEntity.Id, out realEntity))
                    {
                        var componentId = IdentifiableHelper.GetId(entityLink.EntityComponent);
                        obj = realEntity.Entity.Components.FirstOrDefault(c => IdentifiableHelper.GetId(c) == componentId);
                        if (obj == entityLink.EntityComponent)
                        {
                            continue;
                        }
                    }
                }
                else
                {
                    EntityDesign realEntity;
                    if (entityHierarchy.Entities.TryGetValue(entityLink.Entity.Id, out realEntity))
                    {
                        obj = realEntity.Entity;

                        // If we already have the proper item, let's skip
                        if (obj == entityLink.Entity)
                        {
                            continue;
                        }
                    }
                }

                if (obj != null)
                {
                    // We could find the referenced item, let's use it
                    entityLink.Path.Apply(rootToVisit, MemberPathAction.ValueSet, obj);
                }
                else
                {
                    // Item could not be found, let's null it
                    entityLink.Path.Apply(rootToVisit, MemberPathAction.ValueClear, null);
                }
            }
        }
Пример #6
0
 public EntityComponentReference(EntityComponent entityComponent)
 {
     this.Entity = new EntityReference()
     {
         Id = entityComponent.Entity.Id
     };
     this.Id    = IdentifiableHelper.GetId(entityComponent);
     this.Value = entityComponent;
 }
Пример #7
0
        public void FillFromPart(object assetPart)
        {
            var component = (EntityComponent)assetPart;

            Entity = new EntityReference {
                Id = component.Entity.Id
            };
            Id = IdentifiableHelper.GetId(component);
        }
Пример #8
0
        private static ModelMaterial AttachId(ModelMaterial modelMaterial)
        {
            // Compute an id for the list item based on the name of the material
            var materialNameKey = modelMaterial.Name;
            var modelMaterialId = ObjectId.FromBytes(Encoding.UTF8.GetBytes(materialNameKey)).ToGuid();

            IdentifiableHelper.SetId(modelMaterial, modelMaterialId);
            return(modelMaterial);
        }
Пример #9
0
        public object GenerateProxyPart(Type partType)
        {
            var component = (EntityComponent)Activator.CreateInstance(partType);

            component.Entity = new Entity {
                Id = Entity.Id
            };
            IdentifiableHelper.SetId(component, Id);
            return(component);
        }
Пример #10
0
        public void TestHash()
        {
            var obj1 = new TestAssetClonerObject
            {
                Name      = "Test1",
                SubObject = new TestAssetClonerObject()
                {
                    Name = "Test2"
                },
                ObjectWithAttachedReference = new TestObjectReference()
            };

            // Create a fake reference to make sure that the attached reference will not be serialized
            var attachedReference = AttachedReferenceManager.GetOrCreateAttachedReference(obj1.ObjectWithAttachedReference);

            attachedReference.Url = "just_for_test";
            attachedReference.Id  = Guid.NewGuid();

            // Setup some proper id on objects so serialization is stable
            IdentifiableHelper.SetId(obj1, new Guid("EC86143E-896F-45C5-9A4D-627317D22955"));
            IdentifiableHelper.SetId(obj1.SubObject, new Guid("34E160CD-1D94-468E-8BFD-F82FF96013FC"));

            var obj2 = (TestAssetClonerObject)AssetCloner.Clone(obj1);

            var hash1 = AssetHash.Compute(obj1);
            var hash2 = AssetHash.Compute(obj2);

            Assert.AreEqual(hash1, hash2);

            obj1.Name = "Yes";
            var hash11 = AssetHash.Compute(obj1);

            Assert.AreNotEqual(hash11, hash2);
            obj1.Name = "Test1";

            var hash12 = AssetHash.Compute(obj1);

            Assert.AreEqual(hash12, hash2);

            // Test the same with overrides
            var objDesc    = TypeDescriptorFactory.Default.Find(typeof(TestAssetClonerObject));
            var memberDesc = objDesc.Members.First(t => t.Name == "Name");

            obj1.SetOverride(memberDesc, OverrideType.New);
            obj1.SubObject.SetOverride(memberDesc, OverrideType.Sealed);

            obj2 = (TestAssetClonerObject)AssetCloner.Clone(obj1);

            var hash1WithOverrides = AssetHash.Compute(obj1);
            var hash2WithOverrides = AssetHash.Compute(obj2);

            Assert.AreNotEqual(hash1, hash1WithOverrides);
            Assert.AreNotEqual(hash2, hash2WithOverrides);
            Assert.AreEqual(hash1WithOverrides, hash2WithOverrides);
        }
Пример #11
0
        private static void PrepareMembersCallback(SharpYaml.Serialization.Descriptors.ObjectDescriptor objDesc, List <IMemberDescriptor> memberDescriptors)
        {
            var type = objDesc.Type;

            if (IdentifiableHelper.IsIdentifiable(type) && !typeof(IIdentifiable).IsAssignableFrom(type))
            {
                memberDescriptors.Add(CustomDynamicMemberDescriptor);
            }

            // Call custom callbacks to prepare members
            PrepareMembersEvent?.Invoke(objDesc, memberDescriptors);
        }
Пример #12
0
        public override string ConvertTo(ref ObjectContext objectContext)
        {
            var attachedReference = AttachedReferenceManager.GetAttachedReference(objectContext.Instance);

            if (attachedReference == null)
            {
                throw new YamlException($"Unable to extract asset reference from object [{objectContext.Instance}]");
            }

            var referenceId = IdentifiableHelper.GetId(objectContext.Instance);

            return($"{referenceId}/{attachedReference.Id}:{attachedReference.Url}");
        }
Пример #13
0
        private static void PrepareMembersCallback(SharpYaml.Serialization.Descriptors.ObjectDescriptor objDesc, List <IMemberDescriptor> memberDescriptors)
        {
            var type = objDesc.Type;

            // Early exit if we don't need to add a unique identifier to a type
            if (!IdentifiableHelper.IsIdentifiable(type) || typeof(IIdentifiable).IsAssignableFrom(type))
            {
                return;
            }

            // Otherwise we can add it
            memberDescriptors.Add(CustomDynamicMemberDescriptor);
        }
Пример #14
0
        public override object ConvertFrom(ref ObjectContext objectContext, Scalar fromScalar)
        {
            Guid id;

            if (!Guid.TryParse(fromScalar.Value, out id))
            {
                throw new YamlException(fromScalar.Start, fromScalar.End, $"Unable to parse id [{fromScalar.Value}]");
            }
            var materialNull = new MaterialNull();

            IdentifiableHelper.SetId(materialNull, id);
            return(materialNull);
        }
Пример #15
0
        public void TestResolveComplex()
        {
            var memberPath = new MemberPath();

            memberPath.Push(MemberSubs);
            memberPath.Push(ListClassDesc, 1);
            memberPath.Push(MemberSub);
            memberPath.Push(MemberValue);

            var id           = Guid.NewGuid();
            var referenceElt = new MyClass {
                Sub = new MyClass {
                    Value = 1
                }
            };
            var dualElt1 = new MyClass {
                Sub = new MyClass {
                    Value = 2
                }
            };
            var dualElt2 = new MyClass {
                Sub = new MyClass {
                    Value = 3
                }
            };
            var brokenDual = new MyClass();

            IdentifiableHelper.SetId(referenceElt, id);
            IdentifiableHelper.SetId(dualElt1, id);
            IdentifiableHelper.SetId(dualElt2, id);
            IdentifiableHelper.SetId(brokenDual, id);

            var reference = new MyClass {
                Subs = { new MyClass(), referenceElt }
            };
            var dual = new MyClass {
                Subs = { new MyClass(), new MyClass(), dualElt1, brokenDual, new MyClass(), dualElt2 }
            };

            var resolvedPaths = memberPath.Resolve(reference, dual).ToList();

            Assert.AreEqual(2, resolvedPaths.Count);

            object value;

            Assert.IsTrue(resolvedPaths[0].TryGetValue(dual, out value));
            Assert.AreEqual(dual.Subs[2].Sub.Value, value);

            Assert.IsTrue(resolvedPaths[1].TryGetValue(dual, out value));
            Assert.AreEqual(dual.Subs[5].Sub.Value, value);
        }
Пример #16
0
        public override object ConvertFrom(ref ObjectContext context, Scalar fromScalar)
        {
            AssetReference assetReference;
            Guid           referenceId;

            if (!AssetReference.TryParse(fromScalar.Value, out assetReference, out referenceId))
            {
                throw new YamlException(fromScalar.Start, fromScalar.End, "Unable to decode asset reference [{0}]. Expecting format GUID:LOCATION".ToFormat(fromScalar.Value));
            }
            if (referenceId != Guid.Empty)
            {
                IdentifiableHelper.SetId(assetReference, referenceId);
            }
            return(assetReference);
        }
Пример #17
0
        private static AssetItem ImportSkeleton(List <AssetItem> assetReferences, UFile assetSource, UFile localPath, EntityInfo entityInfo)
        {
            var asset = new SkeletonAsset {
                Source = assetSource
            };

            if (entityInfo.Nodes != null)
            {
                for (int i = 0; i < entityInfo.Nodes.Count; i++)
                {
                    var node     = entityInfo.Nodes[i];
                    var nodeInfo = new NodeInformation(node.Name, node.Depth, node.Preserve);

                    // Try to keep identifier id consistent
                    // TODO: We might remove this as we don't expect Skeleton asset to be inherited, but they could
                    int sameNameAndDepthCount = 0;
                    for (int j = 0; j < i; j++)
                    {
                        var againstNode = entityInfo.Nodes[i];
                        // If we found a node with the same name and depth, we use a increment a counter
                        if (againstNode.Name == node.Name && againstNode.Depth == node.Depth)
                        {
                            sameNameAndDepthCount++;
                        }
                    }

                    var nodeNameKey = nodeInfo.Name + nodeInfo.Depth + ((sameNameAndDepthCount > 0) ? "_" + sameNameAndDepthCount : string.Empty);
                    var nodeId      = ObjectId.FromBytes(Encoding.UTF8.GetBytes(nodeNameKey)).ToGuid();

                    IdentifiableHelper.SetId(nodeInfo, nodeId);

                    asset.Nodes.Add(nodeInfo);
                }
            }

            if (entityInfo.AnimationNodes != null && entityInfo.AnimationNodes.Count > 0)
            {
                asset.PreserveNodes(entityInfo.AnimationNodes);
            }

            var skeletonUrl = new UFile(localPath.GetFileName() + " Skeleton");
            var assetItem   = new AssetItem(skeletonUrl, asset);

            assetReferences.Add(assetItem);
            return(assetItem);
        }
Пример #18
0
        public override object ConvertFrom(ref ObjectContext context, Scalar fromScalar)
        {
            AssetId guid;
            UFile   location;
            Guid    referenceId;

            if (!AssetReference.TryParse(fromScalar.Value, out guid, out location, out referenceId))
            {
                throw new YamlException(fromScalar.Start, fromScalar.End, "Unable to decode asset reference [{0}]. Expecting format GUID:LOCATION".ToFormat(fromScalar.Value));
            }

            var instance = AttachedReferenceManager.CreateProxyObject(context.Descriptor.Type, guid, location);

            if (referenceId != Guid.Empty)
            {
                IdentifiableHelper.SetId(instance, referenceId);
            }
            return(instance);
        }
Пример #19
0
        /// <summary>
        /// Tries to parse a package reference in the format {guid:location}.
        /// </summary>
        /// <param name="packageReferenceAsText">The package reference as text.</param>
        /// <param name="packageReference">The package reference.</param>
        /// <returns><c>true</c> if the package reference is a valid reference, <c>false</c> otherwise.</returns>
        public static bool TryParse(string packageReferenceAsText, out PackageReference packageReference)
        {
            Guid  id;
            UFile location;

            packageReference = null;
            Guid referenceId;

            if (AssetReference.TryParse(packageReferenceAsText, out referenceId, out id, out location))
            {
                packageReference = new PackageReference(id, location);
                if (referenceId != Guid.Empty)
                {
                    IdentifiableHelper.SetId(packageReference, referenceId);
                }
                return(true);
            }
            return(false);
        }
Пример #20
0
        public override string ReadMemberName(ref ObjectContext objectContext, string memberName, out bool skipMember)
        {
            var newMemberName = memberName.Trim(Override.PostFixSealed, Override.PostFixNew);
            var objectType    = objectContext.Instance.GetType();

            if (newMemberName.Length != memberName.Length)
            {
                var overrideType = OverrideType.Base;
                if (memberName.Contains(Override.PostFixNewSealed) || memberName.EndsWith(Override.PostFixNewSealedAlt))
                {
                    overrideType = OverrideType.New | OverrideType.Sealed;
                }
                else if (memberName.EndsWith(Override.PostFixNew))
                {
                    overrideType = OverrideType.New;
                }
                else if (memberName.EndsWith(Override.PostFixSealed))
                {
                    overrideType = OverrideType.Sealed;
                }

                if (overrideType != OverrideType.Base)
                {
                    if (cachedDescriptor == null || cachedDescriptor.Type != objectType)
                    {
                        cachedDescriptor = typeDescriptorFactory.Find(objectType);
                    }
                    var memberDescriptor = cachedDescriptor[newMemberName];
                    objectContext.Instance.SetOverride(memberDescriptor, overrideType);
                }
            }

            var resultMemberName = base.ReadMemberName(ref objectContext, newMemberName, out skipMember);

            // If ~Id was not found as a member, don't generate an error, as we may have switched an object
            // to NonIdentifiable but we don't want to write an upgrader for this
            if (!IdentifiableHelper.IsIdentifiable(objectType) && memberName == IdentifiableHelper.YamlSpecialId)
            {
                skipMember = true;
            }
            return(resultMemberName);
        }
Пример #21
0
        /// <inheritdoc/>
        protected override void TransformObjectAfterRead(ref ObjectContext objectContext)
        {
            if (!AreCollectionItemsIdentifiable(ref objectContext))
            {
                base.TransformObjectAfterRead(ref objectContext);
                return;
            }

            var info = (InstanceInfo)objectContext.Properties[InstanceInfoKey];

            // This is to be backward compatible with previous serialization. We fetch ids from the ~Id member of each item
            if (info.Instance != null)
            {
                ICollection <ItemId> deletedItems;
                objectContext.Properties.TryGetValue(DeletedItemsKey, out deletedItems);
                TransformAfterDeserialization((IDictionary)objectContext.Instance, info.Descriptor, info.Instance, deletedItems);
            }
            objectContext.Instance = info.Instance;

            var enumerable = objectContext.Instance as IEnumerable;

            if (enumerable != null)
            {
                var ids        = CollectionItemIdHelper.GetCollectionItemIds(objectContext.Instance);
                var descriptor = (DictionaryDescriptor)info.Descriptor;
                foreach (var item in descriptor.GetEnumerator(objectContext.Instance))
                {
                    ItemId id;
                    if (ids.TryGet(item.Key, out id) && id != ItemId.Empty)
                    {
                        continue;
                    }

                    var guid = item.Value != null?IdentifiableHelper.GetId(item.Value) : Guid.NewGuid();

                    ids[item.Key] = guid != Guid.Empty ? new ItemId(guid.ToByteArray()) : ItemId.New();
                }
            }

            base.TransformObjectAfterRead(ref objectContext);
        }
Пример #22
0
        private void DiffValue(Diff3Node diff3, ref NodeDescription baseNodeDesc, ref NodeDescription asset1NodeDesc, ref NodeDescription asset2NodeDesc)
        {
            var node            = diff3.Asset1Node ?? diff3.Asset2Node ?? diff3.BaseNode;
            var dataVisitMember = node as DataVisitMember;

            if (dataVisitMember != null)
            {
                var diffMember = dataVisitMember.MemberDescriptor.GetCustomAttributes <DiffMemberAttribute>(true).FirstOrDefault();
                if (diffMember != null)
                {
                    if (diffMember.PreferredChange.HasValue)
                    {
                        diff3.ChangeType = diffMember.PreferredChange.Value;
                    }

                    diff3.Weight = diffMember.Weight;
                }
            }

            var instanceType = asset1NodeDesc.Instance?.GetType() ?? asset2NodeDesc.Instance?.GetType();

            object baseInstance   = baseNodeDesc.Instance;
            object asset1Instance = asset1NodeDesc.Instance;
            object asset2Instance = asset2NodeDesc.Instance;

            // If this is an identifiable type (but we are for example not visiting its member), compare only the Ids instead
            if (UseOverrideMode && instanceType != null && IdentifiableHelper.IsIdentifiable(instanceType))
            {
                baseInstance   = IdentifiableHelper.GetId(baseInstance);
                asset1Instance = IdentifiableHelper.GetId(asset1Instance);
                asset2Instance = IdentifiableHelper.GetId(asset2Instance);
            }

            var baseAsset1Equals = Equals(baseInstance, asset1Instance);
            var baseAsset2Equals = Equals(baseInstance, asset2Instance);
            var asset1And2Equals = Equals(asset1Instance, asset2Instance);

            diff3.ChangeType = baseAsset1Equals && baseAsset2Equals
                ? Diff3ChangeType.None
                : baseAsset2Equals ? Diff3ChangeType.MergeFromAsset1 : baseAsset1Equals ? Diff3ChangeType.MergeFromAsset2 : asset1And2Equals ? Diff3ChangeType.MergeFromAsset1And2 : Diff3ChangeType.Conflict;
        }
Пример #23
0
 public override void Serialize(ref MaterialNull obj, ArchiveMode mode, SerializationStream stream)
 {
     if (stream.Context.SerializerSelector.HasProfile("AssetClone"))
     {
         // At design time, when performing a clone, we keep the associated id of this instance.
         if (mode == ArchiveMode.Serialize)
         {
             var id = IdentifiableHelper.GetId(obj);
             stream.Write(id);
         }
         else
         {
             var id = stream.Read <Guid>();
             obj = new MaterialNull();
             IdentifiableHelper.SetId(obj, id);
         }
     }
     else
     {
         // For runtime serialization, a MaterialNull becomes null
         obj = null;
     }
 }
Пример #24
0
        /// <inheritdoc/>
        protected override void TransformObjectAfterRead(ref ObjectContext objectContext)
        {
            InstanceInfo info;

            if (!objectContext.Properties.TryGetValue(InstanceInfoKey, out info))
            {
                base.TransformObjectAfterRead(ref objectContext);

                if (AreCollectionItemsIdentifiable(ref objectContext))
                {
                    // This is to be backward compatible with previous serialization. We fetch ids from the ~Id member of each item
                    var enumerable = objectContext.Instance as IEnumerable;
                    if (enumerable != null)
                    {
                        var ids = CollectionItemIdHelper.GetCollectionItemIds(objectContext.Instance);
                        var i   = 0;
                        foreach (var item in enumerable)
                        {
                            var id = item != null?IdentifiableHelper.GetId(item) : Guid.NewGuid();

                            ids[i] = id != Guid.Empty ? new ItemId(id.ToByteArray()) : ItemId.New();
                            ++i;
                        }
                    }
                }
                return;
            }

            var instance = info.Instance ?? objectContext.SerializerContext.ObjectFactory.Create(info.Descriptor.Type);
            ICollection <ItemId> deletedItems;

            objectContext.Properties.TryGetValue(DeletedItemsKey, out deletedItems);
            TransformAfterDeserialization((IDictionary)objectContext.Instance, info.Descriptor, instance, deletedItems);
            objectContext.Instance = instance;

            base.TransformObjectAfterRead(ref objectContext);
        }
Пример #25
0
        public override object ConvertFrom(ref ObjectContext context, Scalar fromScalar)
        {
            Guid  guid;
            UFile location;
            Guid  referenceId;

            if (!AssetReference.TryParse(fromScalar.Value, out referenceId, out guid, out location))
            {
                throw new YamlException(fromScalar.Start, fromScalar.End, "Unable to decode asset reference [{0}]. Expecting format GUID:LOCATION".ToFormat(fromScalar.Value));
            }

            var instance = AttachedReferenceManager.CreateSerializableVersion(context.Descriptor.Type, guid, location);

            // If the referenceId is empty, force its creation, else attach it to the reference
            if (referenceId == Guid.Empty)
            {
                IdentifiableHelper.GetId(instance);
            }
            else
            {
                IdentifiableHelper.SetId(instance, referenceId);
            }
            return(instance);
        }
Пример #26
0
        public void TestIdentifierHelper()
        {
            // Has IdentifierHelper is using ShadowObject, we will test it here
            ShadowObject.Enable = true;
            var obj = new object();

            var id = IdentifiableHelper.GetId(obj);

            Assert.AreNotEqual(Guid.Empty, id);

            var id1 = IdentifiableHelper.GetId(obj);

            Assert.AreEqual(id, id1);

            // We should not get an id for a collection
            var idCollection = IdentifiableHelper.GetId(new List <object>());

            Assert.AreEqual(Guid.Empty, idCollection);

            // We should not get an id for a dictionary
            var idDict = IdentifiableHelper.GetId(new MyDictionary());

            Assert.AreEqual(Guid.Empty, idDict);
        }
Пример #27
0
 public override void Set(object thisObject, object value)
 {
     IdentifiableHelper.SetId(thisObject, (Guid)value);
 }
Пример #28
0
 public override object Get(object thisObject)
 {
     return(IdentifiableHelper.GetId(thisObject));
 }
Пример #29
0
        private void DiffCollection(Diff3Node diff3, DataVisitNode baseNode, DataVisitNode asset1Node, DataVisitNode asset2Node)
        {
            diff3.Type = Diff3NodeType.Collection;

            var baseItems   = baseNode != null ? baseNode.Items ?? EmptyNodes : EmptyNodes;
            var asset1Items = asset1Node != null ? asset1Node.Items ?? EmptyNodes : EmptyNodes;
            var asset2Items = asset2Node != null ? asset2Node.Items ?? EmptyNodes : EmptyNodes;

            var itemEqualityComparer = equalityComparer;

            var node = diff3.Asset1Node ?? diff3.Asset2Node ?? diff3.BaseNode;

            IEnumerable <Diff3Change> changes;
            bool recurseDiff = false;

            // Find an item in any of the list
            var firstItem = baseItems.FirstOrDefault(item => item.Instance != null) ?? asset1Items.FirstOrDefault(item => item.Instance != null) ?? asset2Items.FirstOrDefault(item => item.Instance != null);

            // For now, in the context of UseOverrideMode and we have identifiers per item, use DiffCollectionByIds instead
            if (UseOverrideMode && firstItem != null)
            {
                if (IdentifiableHelper.IsIdentifiable(firstItem.Instance.GetType()))
                {
                    DiffCollectionByIds(diff3, baseNode, asset1Node, asset2Node);
                    return;
                }
                else if (firstItem.Instance is Guid)
                {
                    DiffCollectionByGuids(diff3, baseNode, asset1Node, asset2Node);
                    return;
                }
            }

            // If we have a DiffUseAsset1Attribute, list of Asset1Node becomes authoritative.
            var dataVisitMember     = node as DataVisitMember;
            var diffMemberAttribute = dataVisitMember != null?dataVisitMember.MemberDescriptor.GetCustomAttributes <DiffMemberAttribute>(true).FirstOrDefault() : null;

            if (diffMemberAttribute != null && diffMemberAttribute.PreferredChange.HasValue)
            {
                diff3.Weight = diffMemberAttribute.Weight;
            }

            if (diffMemberAttribute != null && diffMemberAttribute.PreferredChange.HasValue)
            {
                var diffChange = diffMemberAttribute.PreferredChange.Value == Diff3ChangeType.MergeFromAsset2
                    ? new Diff3Change {
                    ChangeType = SharpDiff.Diff3ChangeType.MergeFrom2, From2 = new Span(0, asset2Items.Count - 1)
                }
                    : new Diff3Change {
                    ChangeType = SharpDiff.Diff3ChangeType.MergeFrom1, From1 = new Span(0, asset1Items.Count - 1)
                };

                changes = new[] { diffChange };
                // TODO: Try to merge back data of matching nodes
            }
            else if (firstItem != null && typeof(IDiffKey).IsAssignableFrom(firstItem.InstanceType))
            {
                // If item implement IDataDiffKey, we will use that as equality key
                changes = Diff3.Compare(
                    baseItems.Select(x => ((IDiffKey)x.Instance).GetDiffKey()).ToList(),
                    asset1Items.Select(x => ((IDiffKey)x.Instance).GetDiffKey()).ToList(),
                    asset2Items.Select(x => ((IDiffKey)x.Instance).GetDiffKey()).ToList());
                recurseDiff = true;
            }
            else
            {
                // Otherwise, do a full node comparison
                itemEqualityComparer.Reset();
                changes = Diff3.Compare(baseItems, asset1Items, asset2Items, itemEqualityComparer);
            }

            foreach (var change in changes)
            {
                switch (change.ChangeType)
                {
                case SharpDiff.Diff3ChangeType.Equal:
                    for (int i = 0; i < change.Base.Length; i++)
                    {
                        var diff3Node = recurseDiff
                                ? DiffNode(baseItems[change.Base.From + i], asset1Items[change.From1.From + i], asset2Items[change.From2.From + i])
                                : new Diff3Node(baseItems[change.Base.From + i], asset1Items[change.From1.From + i], asset2Items[change.From2.From + i])
                        {
                            ChangeType = Diff3ChangeType.None
                        };
                        AddItem(diff3, diff3Node, change.From1.From != 0);
                    }
                    break;

                case SharpDiff.Diff3ChangeType.MergeFrom1:
                    for (int i = 0; i < change.From1.Length; i++)
                    {
                        var diff3Node = new Diff3Node(null, asset1Items[change.From1.From + i], null)
                        {
                            ChangeType = Diff3ChangeType.MergeFromAsset1
                        };
                        AddItem(diff3, diff3Node, change.From1.From != 0);
                    }
                    break;

                case SharpDiff.Diff3ChangeType.MergeFrom2:
                    for (int i = 0; i < change.From2.Length; i++)
                    {
                        var diff3Node = new Diff3Node(null, null, asset2Items[change.From2.From + i])
                        {
                            ChangeType = Diff3ChangeType.MergeFromAsset2
                        };
                        AddItem(diff3, diff3Node, true);
                    }
                    break;

                case SharpDiff.Diff3ChangeType.MergeFrom1And2:
                    for (int i = 0; i < change.From2.Length; i++)
                    {
                        var diff3Node = recurseDiff
                                ? DiffNode(null, asset1Items[change.From1.From + i], asset2Items[change.From2.From + i])
                                : new Diff3Node(null, asset1Items[change.From1.From + i], asset2Items[change.From2.From + i])
                        {
                            ChangeType = Diff3ChangeType.MergeFromAsset1And2
                        };
                        AddItem(diff3, diff3Node, change.From1.From != 0);
                    }
                    break;

                case SharpDiff.Diff3ChangeType.Conflict:
                    int baseIndex  = change.Base.IsValid ? change.Base.From : -1;
                    int from1Index = change.From1.IsValid ? change.From1.From : -1;
                    int from2Index = change.From2.IsValid ? change.From2.From : -1;

                    // If there are changes only from 1 or 2 or base.Length == list1.Length == list2.Length, then try to make a diff per item
                    // else output the conflict as a full conflict
                    bool tryResolveConflict = false;
                    if (baseIndex >= 0)
                    {
                        if (from1Index >= 0 && from2Index >= 0)
                        {
                            if ((change.Base.Length == change.From1.Length && change.Base.Length == change.From2.Length) ||
                                (change.From1.Length == change.From2.Length))
                            {
                                tryResolveConflict = true;
                            }
                        }
                        else if (from1Index >= 0)
                        {
                            tryResolveConflict = change.Base.Length == change.From1.Length;
                        }
                        else if (from2Index >= 0)
                        {
                            tryResolveConflict = change.Base.Length == change.From2.Length;
                        }
                        else
                        {
                            tryResolveConflict = true;
                        }
                    }

                    // Iterate on items
                    while ((baseIndex >= 0 && baseItems.Count > 0) || (from1Index >= 0 && asset1Items.Count > 0) || (from2Index >= 0 && asset2Items.Count > 0))
                    {
                        var baseItem   = GetSafeFromList(baseItems, ref baseIndex, ref change.Base);
                        var asset1Item = GetSafeFromList(asset1Items, ref from1Index, ref change.From1);
                        var asset2Item = GetSafeFromList(asset2Items, ref from2Index, ref change.From2);

                        var diff3Node = tryResolveConflict || recurseDiff?
                                        DiffNode(baseItem, asset1Item, asset2Item) :
                                            new Diff3Node(baseItem, asset1Item, asset2Item)
                        {
                            ChangeType = Diff3ChangeType.Conflict
                        };
                        AddItem(diff3, diff3Node, true);
                    }
                    break;
                }
            }

            // Any missing item? (we can detect this only at the end)
            var newItemCount = diff3.Items != null ? diff3.Items.Count : 0;

            if (asset1Items.Count != newItemCount)
            {
                diff3.ChangeType = Diff3ChangeType.Children;
            }
        }
Пример #30
0
        private void FixReferencesToEntities(EntityDesign newEntityDesign, Dictionary <GroupPartKey, Guid> mapBaseIdToNewId)
        {
            var newEntity = newEntityDesign.Entity;

            // We need to visit all references to entities/components in order to fix references
            // (e.g entities removed, entity added from base referencing an entity from base that we have to redirect to the new child entity...)
            // Suppose for example that:
            //
            // base   newBase                                      newAsset
            // EA       EA                                           EA'
            // EB       EB                                           EB'
            // EC       EC                                           EC'
            //          ED (+link to EA via script or whather)       ED' + link to EA' (we need to change from EA to EA')
            //
            // So in the example above, when merging ED into newAsset, all references to entities declared in newBase are not automatically
            // remapped to the new entities in newAsset. This is the purpose of this whole method

            var entityVisitor          = new SingleLevelVisitor(typeof(Entity), true);
            var entityComponentVisitor = new SingleLevelVisitor(typeof(EntityComponent), true);

            DataVisitNodeBuilder.Run(TypeDescriptorFactory.Default, newEntity, new List <IDataCustomVisitor>()
            {
                entityVisitor,
                entityComponentVisitor
            });

            // Fix Entity and EntityComponent references
            foreach (var idNodes in entityVisitor.References.Concat(entityComponentVisitor.References))
            {
                var id    = idNodes.Key;
                var nodes = idNodes.Value;

                // If entity id is not in the current list, it is more likely that it was a link to a base entity
                if (!newAsset.Hierarchy.Parts.ContainsKey(id))
                {
                    var groupKey = new GroupPartKey(newEntityDesign.BasePartInstanceId, id);

                    // We are trying to remap the base id to the new id from known entities from newAsset
                    Guid newId;
                    if (mapBaseIdToNewId.TryGetValue(groupKey, out newId))
                    {
                        var linkedEntity = newAsset.Hierarchy.Parts[newId].Entity;
                        foreach (var node in nodes)
                        {
                            var entityComponent = node.Instance as EntityComponent;
                            if (entityComponent != null)
                            {
                                var entityComponentId = IdentifiableHelper.GetId(entityComponent);
                                // TODO: In case of a DataVisitMember node, we need to set an OverrideType to New if we are actually removing a base value
                                var newEntityComponent = (EntityComponent)linkedEntity.Components.FirstOrDefault(t => IdentifiableHelper.GetId(t) == entityComponentId);
                                node.SetValue(newEntityComponent);
                            }
                            else
                            {
                                // TODO: In case of a DataVisitMember node, we need to set an OverrideType to New if we are actually removing a base value
                                // Else the node applies to an entity
                                node.SetValue(linkedEntity);
                            }
                        }
                    }
                    else
                    {
                        // TODO: In case of a DataVisitMember node, we need to set an OverrideType to New if we are actually removing a base value
                        // If we are trying to link to an entity/component that was removed, we need to remove it
                        foreach (var node in nodes)
                        {
                            node.RemoveValue();
                        }
                    }
                }
            }
        }