예제 #1
0
        /// <summary>
        /// Lazy init method to ensure the cache is built.
        /// </summary>
        public static void LazyInit()
        {
            if (wasInitialized)
            {
                return;
            }

            foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
            {
                foreach (var type in asm.GetTypes())
                {
                    if (typeof(IPrototype).IsAssignableFrom(type) || type.GetCustomAttributes(true).Any((a) => a.GetType() == typeof(PrototypeDataSerializableAttribute)))
                    {
                        SerializableTypeCache cache = new SerializableTypeCache();
                        cache.Build(type);
                        typeCache.Add(type, cache);
                    }
                    else if (!type.IsAbstract && !type.IsInterface && typeof(IPrototypeDataSerializer).IsAssignableFrom(type))
                    {
                        serializers.Add(Activator.CreateInstance(type) as IPrototypeDataSerializer);
                    }
                }
            }

            wasInitialized = true;
        }
예제 #2
0
 public static bool TypeFound(XElement xElement, XAttribute typeAttribute, SerializableTypeCache type, string filename, List <ParsingError> errors)
 {
     if (ReferenceEquals(type, null))
     {
         errors.Add(new ParsingError(ParsingErrorSeverity.ERROR, filename, (xElement as IXmlLineInfo).LineNumber, "Element type " + typeAttribute.Value + " unknown!"));
         return(false);
     }
     return(true);
 }
예제 #3
0
        // TODO: string.Format()

        public static bool DataFieldSerializerFound(XElement xElement, SerializableTypeCache typeCache, string typeName, string fieldName, string filename, List <ParsingError> errors)
        {
            if (ReferenceEquals(typeCache, null))
            {
                string msg = string.Format("Field '{0}' with unknown type {1} - unknown by the serializer cache! Are you missing {2} attribute?", fieldName, typeName, nameof(PrototypeDataSerializableAttribute));
                errors.Add(new ParsingError(ParsingErrorSeverity.ERROR, filename, (xElement as IXmlLineInfo).LineNumber, msg));
                return(false);
            }
            return(true);
        }
예제 #4
0
        // TODO: string.Format()

        public static bool DataFieldSerializerValid(XElement xElement, SerializableTypeCache typeCache, string typeName, string fieldName, string filename, List <ParsingError> errors)
        {
            if (ReferenceEquals(typeCache, null))
            {
                // TODO: Explanation - why unserializable!?
                string msg = string.Format("Field '{0}' with unserializeable type {1}!", fieldName, typeName);
                errors.Add(new ParsingError(ParsingErrorSeverity.ERROR, filename, (xElement as IXmlLineInfo).LineNumber, msg));
                return(false);
            }
            return(true);
        }
예제 #5
0
 public static bool FieldKnown(IXmlLineInfo debug, SerializableTypeCache type, string field, string filename, List <ParsingError> errors)
 {
     if (!type.HasField(field))
     {
         // TODO: Line number
         string msg = string.Format("Unknown field {0}!", field);
         errors.Add(new ParsingError(ParsingErrorSeverity.ERROR, filename, ReferenceEquals(debug, null) ? -1 : debug.LineNumber, msg));
         return(false);
     }
     return(true);
 }
예제 #6
0
        /// <summary>
        /// Returns the serializable type cache if known for the specified type.
        /// Will be cached just in time.
        /// </summary>
        public static SerializableTypeCache GetSerializableTypeCacheFor(Type type)
        {
            SerializableTypeCache cache;

            if (!typeCache.TryGetValue(type, out cache))
            {
                cache = SerializableTypeCache.TryBuild(type);
                typeCache.Add(type, cache);
            }
            return(cache);
        }
예제 #7
0
        /// <summary>
        /// </summary>
        /// <param name="targetType">The target type to be parsed.</param>
        /// <param name="element">The xml element to parse the data from.</param>
        /// <param name="filename">The filename to be reported in case of errors.</param>
        public SerializedData(SerializableTypeCache targetType, XElement element, string filename)
        {
            this.targetType = targetType;
            this.xElement   = element;
            this.filename   = filename;

            var inheritsAttrib = element.Attribute(PrototypeParser.PrototypeAttributeInherits);

            if (!ReferenceEquals(inheritsAttrib, null))
            {
                this.inherits = inheritsAttrib.Value;
            }
        }
예제 #8
0
        /// <summary>
        /// Tries buildding the cache for the specified type.
        /// In case of an issue while building, null will be returned.
        ///
        /// If you want to know more as to why building failed, <see cref="GetBuildError(Type)"/>
        /// </summary>
        public static SerializableTypeCache TryBuild(Type type)
        {
            SerializableTypeCache stc = new SerializableTypeCache();

            try
            {
                stc.Build(type);
            }
            catch (Exception ex)
            {
                buildErrors.Set(type, ex.ToString());
                return(null);
            }

            return(stc);
        }
예제 #9
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);
                    }
                }
            }
        }