Ejemplo n.º 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);
            }
        }
Ejemplo n.º 2
0
        private void _PreParse(string xmlContent, string filename, ref PrototypeParseParameters parameters, List <SerializedData> result)
        {
            ListPool <SerializedData> .GetIfNull(ref result);

            ListPool <ParsingError> .GetIfNull(ref errors);

            var xElement = XElement.Parse(xmlContent);


            // Validity checks
            if (!ParsingValidation.ContainerElementName(xElement, filename, errors) ||
                !ParsingValidation.ContainerTypeAttribute(xElement, filename, errors))
            {
                return;
            }

            // Get type
            XAttribute typeAttribute = xElement.Attribute(PrototypeContainerAttributeType);
            var        type          = GetSerializableTypeCacheFor(typeAttribute.Value, ref parameters);

            if (!ParsingValidation.TypeFound(xElement, typeAttribute, type, filename, errors))
            {
                return;
            }

            // Iterate over nodes
            foreach (var xNode in xElement.Nodes())
            {
                var elementType  = type;
                var nodeXElement = xNode as XElement;

                // Validity checks
                if (!ParsingValidation.NodeIsElement(xNode, filename, errors) ||
                    !ParsingValidation.PrototypeElementName(nodeXElement, filename, errors))
                {
                    continue;
                }


                var elementTypeAttribute = nodeXElement.Attribute(PrototypeContainerAttributeType);
                if (!ReferenceEquals(elementTypeAttribute, null))
                {
                    elementType = GetSerializableTypeCacheFor(elementTypeAttribute.Value, ref parameters);
                    if (!ParsingValidation.TypeFound(nodeXElement, elementTypeAttribute, elementType, filename, errors))
                    {
                        continue;
                    }
                }

                // Prepare
                var data = new SerializedData(elementType, nodeXElement, filename);
                result.Add(data);
            }
        }
Ejemplo n.º 3
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);
                    }
                }
            }
        }
Ejemplo n.º 4
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);
            }
        }