示例#1
0
        /// <summary>
        /// Applies the data stored in this serialized data to the specified object using reflection.
        /// </summary>
        public void ApplyTo(object obj, List <ParsingError> errors, PrototypeParserState state)
        {
            foreach (var field in fields)
            {
                var fieldInfo = this.targetType.GetFieldData(field.Key);
                var value     = field.Value;

                var sub = value as SerializedData;
                if (!ReferenceEquals(sub, null))
                {
                    // Field already set?
                    value = fieldInfo.fieldInfo.GetValue(obj);

                    // If not, create new obj
                    if (ReferenceEquals(value, null))
                    {
                        value = sub.targetType.Create();
                    }

                    sub.ApplyTo(value, errors, state);
                }

                var col = value as SerializedCollectionData;
                if (!ReferenceEquals(col, null))
                {
                    // Field already set?
                    value = fieldInfo.fieldInfo.GetValue(obj);

                    CollectionOverrideAction action;
                    if (!ReferenceEquals(value, null))
                    {
                        if (!collectionOverrideActions.TryGetValue(field.Key, out action))
                        {
                            action = CollectionOverrideAction.Combine;                             // Always default to comibining
                        }
                        switch (action)
                        {
                        case CollectionOverrideAction.Combine: value = col.CombineWithInNew(value); break;

                        case CollectionOverrideAction.Replace: value = col.CreateCollection(); break;
                        }
                    }
                    else                     // Write new collection
                    {
                        value = col.CreateCollection();
                    }
                }

                if (!ParsingValidation.TypeCheck(debug.TryGet(field.Key), field.Key, value, fieldInfo.fieldInfo.FieldType, filename, errors))
                {
                    continue;
                }

                fieldInfo.fieldInfo.SetValue(obj, value);
            }
        }
        protected override Vector2 _Deserialize(string value, PrototypeParserState state)
        {
            string[] parts = value.Split(',');
            if (parts.Length < 2)
            {
                throw new FormatException("Malformed vector2 data " + value + " - Format: (x,y - . as decimal delimiter)");
            }

            return(new Vector2(float.Parse(parts[0], CultureInfo.InvariantCulture), float.Parse(parts[1], CultureInfo.InvariantCulture)));
        }
        protected override Type _Deserialize(string value, PrototypeParserState state)
        {
            // Create std namespace name string by prepending std namespace to value
            bool   doStdNamespaceCheck   = !value.Contains('.');
            string stdNamespacePrepended = doStdNamespaceCheck ? state.parameters.standardNamespace + "." + value : null;

            // Look for type
            foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
            {
                var t = asm.GetType(value, false, false);
                if (doStdNamespaceCheck && ReferenceEquals(t, null))
                {
                    t = asm.GetType(stdNamespacePrepended, false, false);
                }

                if (!ReferenceEquals(t, null))
                {
                    return(t);
                }
            }

            return(null);
        }
示例#4
0
        /// <summary>
        /// Actually loads the data from the previous parse <see cref="ParseFields(List{ParsingError})"/>.
        /// It will for every field with string data deserialize this data using <see cref="IPrototypeDataSerializer"/>.
        ///
        /// For every sub-data field (<seealso cref="ParseFields(List{ParsingError})"/>) a <see cref="SerializedData"/> object is being written to <see cref="fields"/>.
        /// The sub-data object will have <see cref="PrepareParse(SerializableTypeCache, XElement, string)"/>, <see cref="ParseFields(List{ParsingError})"/> and <see cref="LoadFields(List{ParsingError}, PrototypeParserState)"/> called.
        /// </summary>
        public void LoadFields(List <ParsingError> errors, PrototypeParserState state)
        {
            foreach (var xNode in xElement.Nodes())
            {
                if (!ParsingValidation.NodeIsElement(xNode, this.filename, errors))                 // Malformed XML
                {
                    continue;
                }

                var xElement    = xNode as XElement;
                var elementName = xElement.Name.LocalName;

                // Field unknown?
                if (!ParsingValidation.FieldKnown(xElement, targetType, elementName, filename, errors))
                {
                    continue;
                }

                debug.Add(elementName, xElement);
                var  fieldData    = targetType.GetFieldData(elementName);
                var  fieldType    = fieldData.serializableTypeCache;
                bool isCollection = SerializedCollectionData.IsCollection(fieldData.fieldInfo.FieldType);
                IPrototypeDataSerializer serializer = PrototypeCaches.GetBestSerializerFor(fieldData.fieldInfo.FieldType);

                if (!ReferenceEquals(serializer, null))
                {
                    try
                    {
                        if (!ParsingValidation.SerializerWasFound(xElement, serializer, elementName, targetType == null ? null : targetType.type, fieldType == null ? null : fieldType.type, filename, errors))
                        {
                            continue;
                        }

                        fields.Add(elementName, serializer.Deserialize(fieldData.fieldInfo.FieldType, xElement, state));
                    }
                    catch (Exception ex)
                    {
                        errors.Add(new ParsingError(ParsingErrorSeverity.ERROR, filename, -1, "Serializer threw exception on field " + elementName + " on type " + targetType.type + ":\n\n" + ex.ToString() + "\n\nSkipping field!"));
                    }
                }
                else if (isCollection)
                {
                    var col = new SerializedCollectionData(fieldData.fieldInfo.FieldType, xElement, this.filename);
                    col.ParseAndLoadData(errors, state);
                    fields.Add(elementName, col);

                    // Collection override action?
                    var collectionOverrideAttrib = xElement.Attribute(PrototypeParser.PrototypeAttributeCollectionOverrideAction);
                    if (!ReferenceEquals(collectionOverrideAttrib, null))
                    {
                        collectionOverrideActions.Set(elementName, (CollectionOverrideAction)Enum.Parse(typeof(CollectionOverrideAction), collectionOverrideAttrib.Value));
                    }
                }
                else
                {
                    // A known serializable

                    // Prototype reference?
                    if (fieldData.isPrototype)
                    {
                        fields.Add(elementName, new SerializedPrototypeReference()
                        {
                            identifier = xElement.Value as string
                        });
                    }
                    else
                    {
                        // Determine which type to serialize
                        var    targetType = fieldData.serializableTypeCache;
                        string typeName   = fieldData.fieldInfo.Name;

                        // Check if element explicitly overwrites the type to support polymorphism
                        // The field type might be some base class type and the xml overwrites this type with a class extending from the base
                        var classAttrib = xElement.Attribute(PrototypeParser.PrototypeAttributeType);
                        if (!ReferenceEquals(classAttrib, null))
                        {
                            targetType = PrototypeCaches.GetSerializableTypeCacheFor(classAttrib.Value, state.parameters.standardNamespace);
                            typeName   = classAttrib.Value;
                        }

                        // Field not serializable?
                        if (!ParsingValidation.DataFieldSerializerValid(xElement, targetType, typeName, elementName, filename, errors))
                        {
                            continue;
                        }

                        // Resolve field name type
                        var d = new SerializedData(targetType, xElement as XElement, this.filename);
                        d.LoadFields(errors, state);
                        fields.Add(elementName, d);
                    }
                }
            }
        }
示例#5
0
        /// <summary>
        /// The last step for loading data.
        /// In this step, prototype references are being resolved for this serialized data and their sub data objects.
        /// </summary>
        /// <param name="prototypes">Prototypes to use for remapping</param>
        /// <param name="errors"></param>
        public void ResolveReferenceFields(List <IPrototype> prototypes, List <ParsingError> errors, PrototypeParserState state)
        {
            Dictionary <string, object> updates = DictionaryPool <string, object> .Get();

            try
            {
                foreach (var field in fields)
                {
                    var @ref = field.Value as SerializedPrototypeReference;
                    if (!ReferenceEquals(@ref, null))
                    {
                        updates.Add(field.Key, @ref.Resolve(prototypes));
                    }

                    var sub = field.Value as SerializedData;
                    if (!ReferenceEquals(sub, null))
                    {
                        sub.ResolveReferenceFields(prototypes, errors, state);
                    }

                    var col = field.Value as SerializedCollectionData;
                    if (!ReferenceEquals(col, null))
                    {
                        col.ResolveReferenceFieldsAndSubData(prototypes, errors, state);
                    }
                }

                // Write updates
                foreach (var update in updates)
                {
                    this.fields[update.Key] = update.Value;
                }
            }
            finally
            {
                DictionaryPool <string, object> .Return(updates);
            }
        }
示例#6
0
        public void ResolveReferenceFieldsAndSubData(List <IPrototype> prototypes, List <ParsingError> errors, PrototypeParserState state)
        {
            for (int i = 0; i < this.elements.Count; i++)
            {
                // Finalize, create and apply
                var element  = this.elements[i];
                var sElement = element as SerializedData;
                var protoRef = element as SerializedPrototypeReference;

                if (!ReferenceEquals(sElement, null))
                {
                    sElement.ResolveReferenceFields(prototypes, errors, state);
                    var value = sElement.targetType.Create();
                    sElement.ApplyTo(value, errors, state);
                    this.elements[i] = value;
                }
                else if (!ReferenceEquals(protoRef, null))
                {
                    this.elements[i] = protoRef.Resolve(prototypes);
                }
            }
        }
示例#7
0
        /// <summary>
        /// <see cref="SerializedData.LoadFields(List{ParsingError}, PrototypeParserState)"/>
        /// </summary>
        /// <param name="errors"></param>
        /// <param name="state"></param>
        public void ParseAndLoadData(List <ParsingError> errors, PrototypeParserState state)
        {
            var elementNodes = xElement.Nodes().ToList();
            var collection   = GetCollectionInstance(this.collectionType, elementNodes.Count);

            Type   elementType      = GetElementType(this.collectionType);
            var    elementTypeCache = PrototypeCaches.GetSerializableTypeCacheFor(elementType);
            string elementTypeName  = elementType.Name;

            foreach (var node in elementNodes)
            {
                var xElementNode = node as XElement;
                if (ReferenceEquals(xElementNode, null))                 // Malformed XML
                {
                    errors.Add(new ParsingError(ParsingErrorSeverity.ERROR, filename, (node as IXmlLineInfo).LineNumber, "Unable to cast node to element for " + node + "! Skipping element!"));
                    continue;
                }

                if (typeof(IPrototype).IsAssignableFrom(elementType))
                {
                    // Prototype ref
                    this.elements.Add(new SerializedPrototypeReference()
                    {
                        identifier = xElementNode.Value
                    });
                }
                else
                {
                    // Determine type
                    var    serializableTypeCache = elementTypeCache;
                    string typeName = elementTypeName;

                    // Try to read class attrib
                    var classAttrib = xElementNode.Attribute(PrototypeParser.PrototypeAttributeType);
                    if (!ReferenceEquals(classAttrib, null))
                    {
                        serializableTypeCache = PrototypeCaches.GetSerializableTypeCacheFor(classAttrib.Value, state.parameters.standardNamespace);
                        typeName = classAttrib.Value;
                    }

                    // Validity checks
                    // Field not serializable?
                    if (ReferenceEquals(serializableTypeCache, null))
                    {
                        // TODO: Line number, better reporting as to why this type is unserializable!
                        errors.Add(new ParsingError(ParsingErrorSeverity.ERROR, filename, -1, "Collection element with unknown type " + typeName + " unserializable! Skipping field!"));
                        continue;
                    }

                    // Add element
                    this.elements.Add(new SerializedData(serializableTypeCache, xElementNode, this.filename));
                }
            }

            foreach (var element in this.elements)
            {
                var sElement = element as SerializedData;
                if (!ReferenceEquals(sElement, null))
                {
                    sElement.LoadFields(errors, state);
                }
            }
        }
 protected override bool _Deserialize(string value, PrototypeParserState state)
 {
     return(bool.Parse(value));
 }
 protected override short _Deserialize(string value, PrototypeParserState state)
 {
     return(short.Parse(value));
 }
 protected override double _Deserialize(string value, PrototypeParserState state)
 {
     return(double.Parse(value, CultureInfo.InvariantCulture));
 }
 protected override string _Deserialize(string value, PrototypeParserState state)
 {
     return(value);
 }
 protected abstract T _Deserialize(string value, PrototypeParserState state);
 public object Deserialize(Type type, XElement value, PrototypeParserState state)
 {
     return(_Deserialize(value.Value, state));
 }
 public object Deserialize(Type type, XElement value, PrototypeParserState state)
 {
     return(Enum.Parse(type, value.Value as string));
 }
示例#15
0
        private void _Parse(List <SerializedData> data, ref PrototypeParseParameters parameters)
        {
            ListPool <ParsingError> .GetIfNull(ref errors);

            // Get prototypes with others inheriting from first

            // Key = type which is inheriting from something, Value = the type its inheriting from
            Dictionary <SerializedData, List <SerializedData> > inheritingFrom = new Dictionary <SerializedData, List <SerializedData> >();       // This is only used for topo sort!
            Dictionary <SerializedData, object> instances = new Dictionary <SerializedData, object>();
            Dictionary <string, SerializedData> idMapping = new Dictionary <string, SerializedData>();
            List <SerializedData> invalid = new List <SerializedData>();


            // Pre-parse names, create instances and apply name
            foreach (var d in data)
            {
                if (!ParsingValidation.ElementHasId(d.xElement, d.filename, errors))
                {
                    invalid.Add(d);
                    continue;
                }

                // Read name
                var attribName = d.xElement.Attribute(PrototypeAttributeIdentifier);
                idMapping.Add(attribName.Value, d);

                // Check if abstract prototype data
                var  attribAbstract = d.xElement.Attribute(PrototypeAttributeAbstract);
                bool isAbstract     = !ReferenceEquals(attribAbstract, null) && string.Equals("True", attribAbstract.Value);

                if (!isAbstract)
                {
                    var obj = d.targetType.Create();
                    instances.Add(d, obj);

                    (obj as IPrototype).identifier = attribName.Value;
                    this.prototypes.Add(obj as IPrototype);
                }
            }

            // Remove invalidated entries
            foreach (var d in invalid)
            {
                data.Remove(d);
            }

            invalid.Clear();
            foreach (var d in data)
            {
                SerializedData inheritedData;
                if (!string.IsNullOrEmpty(d.inherits) && idMapping.TryGetValue(d.inherits, out inheritedData))
                {
                    inheritingFrom.GetOrCreate(d).Add(inheritedData);
                }
            }

            PrototypeParserState state = new PrototypeParserState()
            {
                parameters = parameters
            };

            // Remove invalidated entries
            foreach (var d in invalid)
            {
                data.Remove(d);
            }

            // Step 1 - sort by inheritance
            List <SerializedData> empty = new List <SerializedData>();
            var sorted = data.TSort((sd) => inheritingFrom.ContainsKey(sd) ? inheritingFrom[sd] : empty, true).ToList();

            // Step 2 - Preloads the fields and creates sub-data objects
            foreach (var d in sorted)
            {
                d.LoadFields(errors, state);
            }

            // Step 3 - run sorting algorithm for reference resolve
            foreach (var d in data)
            {
                d.ResolveReferenceFields(this.prototypes, errors, state);
            }

            // Step 4 - Final data apply
            List <SerializedData> inheritingFromTmp = new List <SerializedData>();

            foreach (var d in sorted)
            {
                if (!instances.ContainsKey(d))
                {
                    continue;
                }

                // Apply inherited data first
                if (!string.IsNullOrEmpty(d.inherits))
                {
                    // Look up all inherited data in bottom to top order
                    inheritingFromTmp.Clear();
                    var inheritedData = d.inherits;

                    while (!string.IsNullOrEmpty(inheritedData))
                    {
                        SerializedData serializedData = null;
                        if (!this.serializedData.TryGetValue(inheritedData, out serializedData) && !idMapping.TryGetValue(inheritedData, out serializedData))
                        {
                            this.errors.Add(new ParsingError(ParsingErrorSeverity.ERROR, d.filename, (d.xElement as IXmlLineInfo).LinePosition, "Could not find the prototype '" + inheritedData + "' for prototype '" + (instances[d] as IPrototype).identifier + "'! Ignoring inheritance!"));
                        }
                        else
                        {
                            inheritingFromTmp.Add(serializedData);
                        }

                        // Recursion
                        inheritedData = serializedData.inherits;
                    }

                    // Reverse so we apply in top to bottom order
                    inheritingFromTmp.Reverse();

                    // Apply
                    foreach (var _d in inheritingFromTmp)
                    {
                        _d.ApplyTo(instances[d], errors, state);
                    }
                }

                // Apply data over inherited
                d.ApplyTo(instances[d], errors, state);
            }

            // Step 5 - record serialized data in result
            foreach (var kvp in idMapping)
            {
                this.serializedData.Add(kvp.Key, kvp.Value);
            }
        }