Exemple #1
0
        /// <summary>
        /// Parses the specified XML content and returns all prototypes which could be parsed.
        /// </summary>
        /// <param name="xmlContent">The xml content to use for parsing-</param>
        /// <param name="parameters">The parameters for the parser.</param>
        /// <param name="extend">The result to extend when parsing. Setting this will give the parser the ability to let data to be loaded now inherited from data loaded in extend.</param>
        /// <returns></returns>
        public void Parse(string xmlContent, string filename, PrototypeParseParameters parameters)
        {
            // Pre-parse data
            var data = new List <SerializedData>();

            _PreParse(xmlContent, filename, ref parameters, data);
            _Parse(data, ref parameters);
        }
Exemple #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);
            }
        }
Exemple #3
0
        /// <summary>
        /// Same as <see cref="Parse(string, string)"/>, but can parse many xmls with relationships / dependencies in them together.
        /// This will make it possible to have a prototype in one file which is inherited from in another file.
        ///
        /// The prototypes will be loaded in order and able to resolve references across multiple files!
        /// </summary>
        public void Parse(string[] xmlContents, string[] filenames, PrototypeParseParameters parameters)
        {
            List <SerializedData> data = new List <SerializedData>();

            if (xmlContents.Length != filenames.Length)
            {
                throw new ArgumentException("Xml content string count must match filename count in Prototypes.Parse()!");
            }

            for (int i = 0; i < xmlContents.Length; i++)
            {
                _PreParse(xmlContents[i], filenames[i], ref parameters, data);
            }

            _Parse(data, ref parameters);
        }
Exemple #4
0
 private static SerializableTypeCache GetSerializableTypeCacheFor(string name, ref PrototypeParseParameters parameters)
 {
     return(PrototypeCaches.GetSerializableTypeCacheFor(name, parameters.standardNamespace));
 }
Exemple #5
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);
            }
        }
 private static SerializableTypeCache LookupSerializableTypeCache(string name, ref PrototypeParseParameters parameters)
 {
     return(PrototypeCaches.LookupSerializableTypeCache(name, parameters.standardNamespace));
 }