Example #1
0
 /// <param name="persistentField">A persitent field descriptor.</param>
 /// <param name="valueType">A type to handle. If field is a collection then this type is a type of
 /// the collection's item.</param>
 /// <param name="simpleTypeProtoType">A proto that handles (de)serializing (in)to a simple string.
 /// if this proto cannot handle <paramref name="valueType"/> then the type will be attempted to be
 /// handled as a complex type.</param>
 internal OrdinaryFieldHandler(
     PersistentField persistentField, Type valueType, Type simpleTypeProtoType)
 {
     this.persistentField = persistentField;
     this.valueType       = valueType;
     this.simpleTypeProto = Activator.CreateInstance(simpleTypeProtoType)
                            as AbstractOrdinaryValueTypeProto;
 }
Example #2
0
        /// <param name="fieldInfo">An annotated field metadata.</param>
        /// <param name="fieldAttr">An annotation of the field.</param>
        public PersistentField(FieldInfo fieldInfo, PersistentFieldAttribute fieldAttr)
        {
            this.fieldInfo = fieldInfo;
            cfgPath        = fieldAttr.path;
            var ordinaryType = fieldInfo.FieldType;

            if (fieldAttr.collectionTypeProto != null)
            {
                collectionProto =
                    Activator.CreateInstance(fieldAttr.collectionTypeProto, new[] { fieldInfo.FieldType })
                    as AbstractCollectionTypeProto;
                ordinaryType = collectionProto.GetItemType();
            }
            simpleTypeProto =
                Activator.CreateInstance(fieldAttr.ordinaryTypeProto)
                as AbstractOrdinaryValueTypeProto;
            isCustomSimpleType = typeof(IPersistentField).IsAssignableFrom(ordinaryType);

            // Determine if field's or collection item's type is a class (compound type).
            isCompound = !simpleTypeProto.CanHandle(ordinaryType) && !isCustomSimpleType &&
                         (ordinaryType.IsValueType && !ordinaryType.IsEnum || // IsStruct
                          ordinaryType.IsClass && ordinaryType != typeof(string) &&
                          !ordinaryType.IsEnum); // IsClass

            if (!isCompound && !simpleTypeProto.CanHandle(ordinaryType) && !isCustomSimpleType)
            {
                Debug.LogErrorFormat(
                    "Proto {0} cannot handle value in field {1}.{2}",
                    ordinaryType.FullName, fieldInfo.DeclaringType.FullName, fieldInfo.Name);
                isDisabled = true;
            }

            // For a compound type retrieve all its persisted fields.
            if (isCompound && !isDisabled)
            {
                // Ignore static fields of the compound type since it can be used by multiple persistent
                // fields or as an item in a collection field.
                // Also, ignore groups in the compound types to reduce configuration complexity.
                compoundTypeFields =
                    PersistentFieldsFactory.GetPersistentFields(
                        ordinaryType, false /* needStatic */, true /* needInstance */, null /* group */)
                    // Parent nodes have to be handled before children!
                    .OrderBy(x => string.Join("/", x.cfgPath))
                    .ToArray();

                // Disable if cannot deal with the field anyways.
                if (compoundTypeFields.Length == 0 && !typeof(IConfigNode).IsAssignableFrom(ordinaryType))
                {
                    Debug.LogErrorFormat(
                        "Compound type in field {0}.{1} has no persistent fields and doesn't implement"
                        + " IConfigNode",
                        fieldInfo.DeclaringType.FullName, fieldInfo.Name);
                    isDisabled = true;
                }
            }
        }
Example #3
0
        /// <summary>
        /// Stores a value of arbitrary type <typeparamref name="T"/> into a config node.
        /// </summary>
        /// <param name="node">A node to set data in.</param>
        /// <param name="pathKeys">An array of values that makes the full path. First node in the array is
        /// the top most component of the path.</param>
        /// <param name="value">A value to store. The <paramref name="typeProto"/> handler must know how
        /// to convert value's type into string.</param>
        /// <param name="typeProto">A proto capable to handle the type of <paramref name="value"/>. If not
        /// set then <see cref="StandardOrdinaryTypesProto"/> is used.</param>
        /// <typeparam name="T">The value type to store. Type proto must be able to handle it.
        /// </typeparam>
        /// <exception cref="ArgumentException">If type cannot be handled by the proto.</exception>
        public static void SetValueByPath <T>(ConfigNode node, string[] pathKeys, T value,
                                              AbstractOrdinaryValueTypeProto typeProto = null)
        {
            if (typeProto == null)
            {
                typeProto = standardTypesProto;
            }
            if (!typeProto.CanHandle(typeof(T)))
            {
                throw new ArgumentException(string.Format(
                                                "Proto {0} cannot handle type {1}", typeProto.GetType(), typeof(T)));
            }
            var strValue = typeProto.SerializeToString(value);

            SetValueByPath(node, pathKeys, strValue);
        }
Example #4
0
        /// <summary>
        /// Reads a value of an arbitrary type <typeparamref name="T"/> from the config node.
        /// </summary>
        /// <param name="node">The node to read data from.</param>
        /// <param name="pathKeys">
        /// The array of values that makes the full path. The first node in the array is the top most
        /// component of the path.
        /// </param>
        /// <param name="typeProto">
        /// A proto that can parse values of type <typeparamref name="T"/>. If not set, then
        /// <see cref="StandardOrdinaryTypesProto"/> is used.
        /// </param>
        /// <returns>The parsed value or <c>null</c> if not found.</returns>
        /// <typeparam name="T">
        /// The value type to write. The <paramref name="typeProto"/> instance must be able to handle it.
        /// </typeparam>
        /// <exception cref="ArgumentException">If type cannot be handled by the proto.</exception>
        /// <seealso cref="SetValueByPath&lt;T&gt;(ConfigNode, string[], T, KSPDev.ConfigUtils.AbstractOrdinaryValueTypeProto)"/>
        public static T?GetValueByPath <T>(
            ConfigNode node, string[] pathKeys, AbstractOrdinaryValueTypeProto typeProto = null)
            where T : struct
        {
            if (typeProto == null)
            {
                typeProto = standardTypesProto;
            }
            if (!typeProto.CanHandle(typeof(T)))
            {
                throw new ArgumentException(string.Format(
                                                "Proto {0} cannot handle type {1}", typeProto.GetType(), typeof(T)));
            }
            var strValue = ConfigAccessor.GetValueByPath(node, pathKeys);

            return(strValue == null
        ? null
        : (T?)typeProto.ParseFromString(strValue, typeof(T)));
        }
Example #5
0
        /// <summary>
        /// Reads a value of arbitrary type <typeparamref name="T"/> from a config node.
        /// </summary>
        /// <param name="node">A node to read data from.</param>
        /// <param name="pathKeys">An array of values that makes the full path. First node in the array is
        /// the top most component of the path.</param>
        /// <param name="value">A variable to read value into. The <paramref name="typeProto"/> handler
        /// must know how to convert value's type from string.</param>
        /// <param name="typeProto">A proto capable to handle the type of <paramref name="value"/>. If not
        /// set then <see cref="StandardOrdinaryTypesProto"/> is used.</param>
        /// <returns><c>true</c> if value was successfully read and stored.</returns>
        /// <typeparam name="T">The value type to read. Type proto must be able to handle it.
        /// </typeparam>
        /// <exception cref="ArgumentException">If type cannot be handled by the proto.</exception>
        public static bool GetValueByPath <T>(ConfigNode node, string[] pathKeys, ref T value,
                                              AbstractOrdinaryValueTypeProto typeProto = null)
        {
            if (typeProto == null)
            {
                typeProto = standardTypesProto;
            }
            if (!typeProto.CanHandle(typeof(T)))
            {
                throw new ArgumentException(string.Format(
                                                "Proto {0} cannot handle type {1}", typeProto.GetType(), typeof(T)));
            }
            var strValue = GetValueByPath(node, pathKeys);

            if (strValue == null)
            {
                return(false);
            }
            value = (T)typeProto.ParseFromString(strValue, typeof(T));
            return(true);
        }
Example #6
0
 /// <summary>
 /// Reads a value of arbitrary type <typeparamref name="T"/> from a config node.
 /// </summary>
 /// <param name="node">A node to read data from.</param>
 /// <param name="path">A string path to the node. Path components should be separated by '/'
 /// symbol.</param>
 /// <param name="value">A variable to read value into. The <paramref name="typeProto"/> handler
 /// must know how to convert value's type from string.</param>
 /// <param name="typeProto">A proto capable to handle the type of <paramref name="value"/>. If not
 /// set then <see cref="StandardOrdinaryTypesProto"/> is used.</param>
 /// <returns><c>true</c> if value was successfully read and stored.</returns>
 /// <typeparam name="T">The value type to read. Type proto must be able to handle it.
 /// </typeparam>
 /// <exception cref="ArgumentException">If type cannot be handled by the proto.</exception>
 public static bool GetValueByPath <T>(ConfigNode node, string path, ref T value,
                                       AbstractOrdinaryValueTypeProto typeProto = null)
 {
     return(GetValueByPath(node, path.Split('/'), ref value, typeProto));
 }
Example #7
0
 /// <summary>
 /// Stores a value of arbitrary type <typeparamref name="T"/> into a config node.
 /// </summary>
 /// <param name="node">A node to set data in.</param>
 /// <param name="path">A string path to the node. Path components should be separated by '/'
 /// symbol.</param>
 /// <param name="value">A value to store. The <paramref name="typeProto"/> handler must know how
 /// to convert the value into string.</param>
 /// <param name="typeProto">A proto capable to handle the type of <paramref name="value"/>. If not
 /// set then <see cref="StandardOrdinaryTypesProto"/> is used.</param>
 /// <typeparam name="T">The value type to store. Type proto must be able to handle it.
 /// </typeparam>
 /// <exception cref="ArgumentException">If type cannot be handled by the proto.</exception>
 public static void SetValueByPath <T>(ConfigNode node, string path, T value,
                                       AbstractOrdinaryValueTypeProto typeProto = null)
 {
     SetValueByPath(node, path.Split('/'), value, typeProto);
 }
Example #8
0
 /// <summary>
 /// Reads a value of an arbitrary type <typeparamref name="T"/> from the config node.
 /// </summary>
 /// <param name="node">The node to read data from.</param>
 /// <param name="path">
 /// The path to the node. The path components should be separated by '/' symbol.
 /// </param>
 /// <param name="typeProto">
 /// A proto that can parse values of type <typeparamref name="T"/>. If not set, then
 /// <see cref="StandardOrdinaryTypesProto"/> is used.
 /// </param>
 /// <returns>The parsed value or <c>null</c> if not found.</returns>
 /// <typeparam name="T">
 /// The value type to write. The <paramref name="typeProto"/> instance must be able to handle it.
 /// </typeparam>
 /// <exception cref="ArgumentException">If type cannot be handled by the proto.</exception>
 /// <seealso cref="SetValueByPath&lt;T&gt;(ConfigNode, string, T, KSPDev.ConfigUtils.AbstractOrdinaryValueTypeProto)"/>
 public static T?GetValueByPath <T>(
     ConfigNode node, string path, AbstractOrdinaryValueTypeProto typeProto = null)
     where T : struct
 {
     return(GetValueByPath <T>(node, ConfigAccessor.StrToPath(path), typeProto));
 }