/// <inheritdoc/>
        public override string ConvertTo(ref ObjectContext objectContext)
        {
            var key = (IKeyWithId)objectContext.Instance;
            var keyDescriptor = objectContext.SerializerContext.FindTypeDescriptor(key.KeyType);
            var keySerializer = objectContext.SerializerContext.Serializer.GetSerializer(objectContext.SerializerContext, keyDescriptor);

            // TODO: serialize non-scalar keys!
            // Guid:
            //     Key: {Key}
            //     Value: {Value}

            var scalarKeySerializer = keySerializer as ScalarSerializerBase;
            if (scalarKeySerializer == null)
                throw new InvalidOperationException("Non-scalar key not yet supported!");

            var context = new ObjectContext(objectContext.SerializerContext, key.Key, keyDescriptor);

            objectContext.Instance = key.Id;
            var itemIdPart = base.ConvertTo(ref objectContext);
            objectContext.Instance = key;

            if (key.IsDeleted)
                return $"{itemIdPart}~";

            var keyString = scalarKeySerializer.ConvertTo(ref context);
            string overrideInfo;
            if (objectContext.SerializerContext.Properties.TryGetValue(OverrideKeyInfoKey, out overrideInfo))
            {
                keyString += overrideInfo;
                objectContext.SerializerContext.Properties.Remove(OverrideKeyInfoKey);
            }
            return $"{itemIdPart}~{keyString}";
        }
        public override string ReadMemberName(ref ObjectContext objectContext, string memberName, out bool skipMember)
        {
            var objectType = objectContext.Instance.GetType();

            OverrideType[] overrideTypes;
            var realMemberName = TrimAndParseOverride(memberName, out overrideTypes);

            // For member names, we have a single override, so we always take the last one of the array (In case of legacy property serialized with ~Name)
            var overrideType = overrideTypes[overrideTypes.Length - 1];
            if (overrideType != OverrideType.Base)
            {
                Dictionary<YamlAssetPath, OverrideType> overrides;
                if (!objectContext.SerializerContext.Properties.TryGetValue(OverrideDictionaryKey, out overrides))
                {
                    overrides = new Dictionary<YamlAssetPath, OverrideType>();
                    objectContext.SerializerContext.Properties.Add(OverrideDictionaryKey, overrides);
                }

                var path = GetCurrentPath(ref objectContext, true);
                path.PushMember(realMemberName);
                overrides.Add(path, overrideType);
            }

            var resultMemberName = base.ReadMemberName(ref objectContext, realMemberName, 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 (!ShadowId.IsTypeIdentifiable(objectType) && memberName == ShadowId.YamlSpecialId)
            {
                skipMember = true;
            }
            return resultMemberName;
        }
 /// <inheritdoc/>
 protected override void WriteYamlAfterTransform(ref ObjectContext objectContext, bool transformed)
 {
     if (transformed)
         base.WriteYamlAfterTransform(ref objectContext, true);
     else
         GetCollectionSerializerForNonTransformedObject().WriteYaml(ref objectContext);
 }
 protected override void WriteScalar(ref ObjectContext objectContext, ScalarEventInfo scalar)
 {
     // TODO: if ParameterKey is written to an object, It will not serialized a tag
     scalar.Tag = null;
     scalar.IsPlainImplicit = true;
     base.WriteScalar(ref objectContext, scalar);
 }
        public override void WriteMemberValue(ref ObjectContext objectContext, IMemberDescriptor memberDescriptor, object memberValue, Type memberType)
        {
            var memberObjectContext = new ObjectContext(objectContext.SerializerContext, memberValue, objectContext.SerializerContext.FindTypeDescriptor(memberType));

            bool nonIdentifiableItems;
            // We allow compact style only for collection with non-identifiable items
            var allowCompactStyle = objectContext.SerializerContext.Properties.TryGetValue(CollectionWithIdsSerializerBase.NonIdentifiableCollectionItemsKey, out nonIdentifiableItems) && nonIdentifiableItems;

            var member = memberDescriptor as MemberDescriptorBase;
            if (member != null && objectContext.Settings.Attributes.GetAttribute<NonIdentifiableCollectionItemsAttribute>(member.MemberInfo) != null)
            {
                memberObjectContext.Properties.Add(CollectionWithIdsSerializerBase.NonIdentifiableCollectionItemsKey, true);
                allowCompactStyle = true;
            }

            if (allowCompactStyle)
            {
                memberObjectContext.Style = memberDescriptor.Style;
            }

            var path = GetCurrentPath(ref objectContext, true);
            path.PushMember(memberDescriptor.Name);
            SetCurrentPath(ref memberObjectContext, path);

            WriteYaml(ref memberObjectContext);
        }
        /// <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);
        }
        /// <inheritdoc/>
        protected override void CreateOrTransformObject(ref ObjectContext objectContext)
        {
            if (LocalContext.Value.SerializeAsReference)
            {
                var attribute = LocalContext.Value.EnteredTypes.Peek();
                var referenceType = attribute.ReferenceType;
                var reference = (IAssetPartReference)Activator.CreateInstance(referenceType);

                if (objectContext.SerializerContext.IsSerializing)
                {
                    // Serialization: properly fill the reference with information from the real object
                    reference.FillFromPart(objectContext.Instance);
                }
                else
                {
                    // Deserialization: store the real type of the asset part (this information won't be accessible later when we need it)
                    reference.InstanceType = objectContext.Descriptor.Type;
                }

                // Replace the real object with the reference.
                objectContext.Instance = reference;
            }

            base.CreateOrTransformObject(ref objectContext);

            // TODO: FIXME: Decouple the deserialization of the graph of objects and the patching of single objects (shouldn't be at the same place), and move this code in the Entity assembly (remove dynamic usage)
            // When deserializing, we don't keep the TransformComponent created when the Entity is created
            if (!objectContext.SerializerContext.IsSerializing && objectContext.Instance?.GetType().Name == "Entity")
            {
                dynamic entity = objectContext.Instance;
                entity.Components.Clear();
            }
        }
 /// <inheritdoc/>
 public override object ReadYaml(ref ObjectContext objectContext)
 {
     var token = PreSerialize(ref objectContext);
     var result = base.ReadYaml(ref objectContext);
     PostSerialize(ref objectContext, token);
     return result;
 }
        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}]");

            return $"{attachedReference.Id}:{attachedReference.Url}";
        }
 private static void PostSerialize(ref ObjectContext objectContext, ContextToken contextToken)
 {
     // Restore contexts that must be restored
     if (contextToken.NonIdentifiableItems)
     {
         objectContext.SerializerContext.Properties.Remove(CollectionWithIdsSerializerBase.NonIdentifiableCollectionItemsKey);
     }
 }
 public override object ConvertFrom(ref ObjectContext context, Scalar fromScalar)
 {
     PackageVersionRange packageVersion;
     if (!PackageVersionRange.TryParse(fromScalar.Value, out packageVersion))
     {
         throw new YamlException(fromScalar.Start, fromScalar.End, "Invalid version dependency format. Unable to decode [{0}]".ToFormat(fromScalar.Value));
     }
     return packageVersion;
 }
 public override object ConvertFrom(ref ObjectContext context, Scalar fromScalar)
 {
     PackageReference packageReference;
     if (!PackageReference.TryParse(fromScalar.Value, out packageReference))
     {
         throw new YamlException(fromScalar.Start, fromScalar.End, "Unable to decode package reference [{0}]. Expecting format GUID:LOCATION".ToFormat(fromScalar.Value));
     }
     return packageReference;
 }
 public override object ConvertFrom(ref ObjectContext objectContext, Scalar fromScalar)
 {
     var parameterKey = ParameterKeys.FindByName(fromScalar.Value);
     if (parameterKey == null)
     {
         throw new YamlException(fromScalar.Start, fromScalar.End, "Unable to find registered ParameterKey [{0}]".ToFormat(fromScalar.Value));
     }
     return parameterKey;
 }
        public object ReadYaml(ref ObjectContext objectContext)
        {
            if (!objectContext.Reader.Accept<Scalar>())
            {
                // Old format, fallback to ObjectSerializer
                return ObjectSerializer.ReadYaml(ref objectContext);
            }

            // If it's a scalar (new format), redirect to our scalar serializer
            return scalarRedirectSerializer.ReadYaml(ref objectContext);
        }
 /// <inheritdoc/>
 public override string ConvertTo(ref ObjectContext objectContext)
 {
     var result = ((ItemId)objectContext.Instance).ToString();
     string overrideInfo;
     if (objectContext.SerializerContext.Properties.TryGetValue(OverrideInfoKey, out overrideInfo))
     {
         result += overrideInfo;
         objectContext.SerializerContext.Properties.Remove(OverrideInfoKey);
     }
     return result;
 }
 /// <inheritdoc/>
 public override object ReadYaml(ref ObjectContext objectContext)
 {
     var contextToken = PrepareLocalContext(objectContext.Descriptor.Type);
     try
     {
         return base.ReadYaml(ref objectContext);
     }
     finally
     {
         CleanLocalContext(contextToken);
     }
 }
        protected override void TransformObjectAfterRead(ref ObjectContext objectContext)
        {
            if (!objectContext.SerializerContext.IsSerializing)
            {
                var settingsDictionary = (SettingsDictionary)objectContext.Instance;
                var settingsProfile = settingsDictionary.Profile;

                settingsProfile.Container.DecodeSettings(settingsDictionary, settingsProfile);

                objectContext.Instance = settingsProfile;
            }
        }
 /// <inheritdoc/>
 public override void WriteYaml(ref ObjectContext objectContext)
 {
     var contextToken = PrepareLocalContext(objectContext.Descriptor.Type);
     try
     {
         base.WriteYaml(ref objectContext);
     }
     finally
     {
         CleanLocalContext(contextToken);
     }
 }
        protected override void WriteDictionaryItem(ref ObjectContext objectContext, KeyValuePair<object, object> keyValue, KeyValuePair<Type, Type> keyValueTypes)
        {
            var propertyKey = (UFile)keyValue.Key;
            objectContext.SerializerContext.ObjectSerializerBackend.WriteDictionaryKey(ref objectContext, propertyKey, keyValueTypes.Key);

            // Deduce expected value type from PropertyKey
            var parsingEvents = (List<ParsingEvent>)keyValue.Value;
            var writer = objectContext.Writer;
            foreach (var parsingEvent in parsingEvents)
            {
                writer.Emit(parsingEvent);
            }
        }
        public override object ConvertFrom(ref ObjectContext context, Scalar fromScalar)
        {
            Guid guid;
            if (!Guid.TryParse(fromScalar.Value, out guid))
            {
                throw new YamlException(fromScalar.Start, fromScalar.End, "Unable to decode asset part reference [{0}]. Expecting an ENTITY_GUID".ToFormat(fromScalar.Value));
            }

            var result = context.Instance as IdentifiableAssetPartReference ?? (IdentifiableAssetPartReference)(context.Instance = new IdentifiableAssetPartReference());
            result.Id = guid;

            return result;
        }
        public override string ConvertTo(ref ObjectContext objectContext)
        {
            var propertyKey = (PropertyKey)objectContext.Instance;

            var className = objectContext.SerializerContext.TagFromType(propertyKey.OwnerType);
            var sb = new StringBuilder(className.Length + 1 + propertyKey.Name.Length);

            sb.Append(className, 1, className.Length - 1); // Ignore initial '!'
            sb.Append('.');
            sb.Append(propertyKey.Name);

            return sb.ToString();
        }
        protected override void CreateOrTransformObject(ref ObjectContext objectContext)
        {
            var settingsProfile = (SettingsProfile)objectContext.Instance;
            var settingsDictionary = new SettingsDictionary { Profile = settingsProfile };

            if (objectContext.SerializerContext.IsSerializing)
            {
                settingsProfile.Container.EncodeSettings(settingsProfile, settingsDictionary);
            }

            objectContext.Instance = settingsDictionary;

            base.CreateOrTransformObject(ref objectContext);
        }
 private static ContextToken PreSerialize(ref ObjectContext objectContext)
 {
     var token = new ContextToken();
     // Check if we enter a context where collection items are not identifiable anymore (see doc of the related attribute)
     if (objectContext.Descriptor.Type.GetCustomAttribute<NonIdentifiableCollectionItemsAttribute>(true) != null)
     {
         if (!objectContext.SerializerContext.Properties.ContainsKey(CollectionWithIdsSerializerBase.NonIdentifiableCollectionItemsKey))
         {
             token.NonIdentifiableItems = true;
             objectContext.SerializerContext.Properties.Add(CollectionWithIdsSerializerBase.NonIdentifiableCollectionItemsKey, true);
         }
     }
     return token;
 }
        public override object ConvertFrom(ref ObjectContext context, Scalar fromScalar)
        {
            Guid entityGuid, componentGuid;

            if (!TryParse(fromScalar.Value, out entityGuid, out componentGuid))
            {
                throw new YamlException(fromScalar.Start, fromScalar.End, "Unable to decode entity component reference [{0}]. Expecting format ENTITY_GUID/COMPONENT_GUID".ToFormat(fromScalar.Value));
            }

            var result = context.Instance as EntityComponentReference ?? (EntityComponentReference)(context.Instance = new EntityComponentReference());
            result.Entity = new EntityComponentReference.EntityReference { Id = entityGuid };
            result.Id = componentGuid;
            return result;
        }
        public override object ReadMemberValue(ref ObjectContext objectContext, IMemberDescriptor memberDescriptor, object memberValue, Type memberType)
        {
            var memberObjectContext = new ObjectContext(objectContext.SerializerContext, memberValue, objectContext.SerializerContext.FindTypeDescriptor(memberType));

            var member = memberDescriptor as MemberDescriptorBase;
            if (member != null && objectContext.Settings.Attributes.GetAttribute<NonIdentifiableCollectionItemsAttribute>(member.MemberInfo) != null)
            {
                memberObjectContext.Properties.Add(CollectionWithIdsSerializerBase.NonIdentifiableCollectionItemsKey, true);
            }

            var path = GetCurrentPath(ref objectContext, true);
            path.PushMember(memberDescriptor.Name);
            SetCurrentPath(ref memberObjectContext, path);

            var result = ReadYaml(ref memberObjectContext);
            return result;
        }
        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;
        }
        /// <inheritdoc/>
        protected override void TransformObjectAfterRead(ref ObjectContext objectContext)
        {
            if (recursionLevel >= 2)
            {
                // We are inside a Script
                if (!objectContext.SerializerContext.IsSerializing)
                {
                    if (objectContext.Instance is CloneReference)
                    {
                        objectContext.Instance = References[((CloneReference)objectContext.Instance).Id];
                        return;
                    }
                }
            }

            base.TransformObjectAfterRead(ref objectContext);
        }
        protected override void ReadAddCollectionItem(ref ObjectContext objectContext, Type elementType, CollectionDescriptor collectionDescriptor, object thisObject, int index)
        {
            var scriptCollection = (EntityComponentCollection)objectContext.Instance;

            EntityComponent value = null;
            bool needAdd = true; // If we could get existing value, no need add to collection
            if (index < scriptCollection.Count)
            {
                value = scriptCollection[index];
                needAdd = false;
            }

            value = (EntityComponent)ReadCollectionItem(ref objectContext, value, elementType, index);
            if (needAdd)
            {
                scriptCollection.Add(value);
            }
        }
        public override void WriteYaml(ref ObjectContext objectContext)
        {
            // TODO: the API could be changed at the ObjectSerializer level so we can, through override:
            // TODO: - customize what to do -if- the object got transformed (currently: ObjectSerializer = routing, here = keep same serializer)
            // TODO: - override WriteYamlAfterTransform without overriding WriteYaml
            // TODO: - and similar with reading

            CreateOrTransformObject(ref objectContext);
            var newValue = objectContext.Instance;

            var transformed = false;
            if (newValue != null && newValue.GetType() != objectContext.Descriptor.Type)
            {
                transformed = true;
                objectContext.Descriptor = objectContext.SerializerContext.FindTypeDescriptor(newValue.GetType());
            }

            WriteYamlAfterTransform(ref objectContext, transformed);
        }
        protected override KeyValuePair<object, object> ReadDictionaryItem(ref ObjectContext objectContext, KeyValuePair<Type, Type> keyValueTypes)
        {
            // Read PropertyKey
            var keyResult = (UFile)objectContext.SerializerContext.ObjectSerializerBackend.ReadDictionaryKey(ref objectContext, keyValueTypes.Key);

            // Save the Yaml stream, in case loading fails we can keep this representation
            var parsingEvents = new List<ParsingEvent>();
            var reader = objectContext.Reader;
            var startDepth = reader.CurrentDepth;
            do
            {
                parsingEvents.Add(reader.Expect<ParsingEvent>());
            } while (reader.CurrentDepth > startDepth);


            var valueResult = parsingEvents;

            return new KeyValuePair<object, object>(keyResult, valueResult);
        }