Пример #1
0
        public FieldOrderer(WarcraftVersion version, IReadOnlyList <PropertyInfo> originalProperties)
        {
            this.Version            = version;
            this.OriginalProperties = originalProperties;

            // Get the properties that should move, and their movement information
            this.MovingProperties = DBCInspector.GetMovedProperties(this.Version, originalProperties);

            // Build the precedence chains for the moving properties
            this.PrecedenceChains = BuildPrecedenceChains();
        }
Пример #2
0
        /// <summary>
        /// Reads a property value from the given <see cref="BinaryReader"/>.
        /// </summary>
        /// <param name="reader">The reader, containing the data.</param>
        /// <param name="recordInfo">The reflected field information.</param>
        /// <param name="property">The property which will contain the data.</param>
        /// <param name="elementType">The element type of the field. This is primarily used for reading arrays.</param>
        /// <param name="version">The version of the record.</param>
        /// <returns>The value that should be assigned to the property.</returns>
        public static object ReadPropertyValue
        (
            BinaryReader reader,
            RecordFieldInformation recordInfo,
            PropertyInfo property,
            Type elementType,
            WarcraftVersion version
        )
        {
            object fieldValue;

            if (DBCInspector.IsPropertyForeignKey(property))
            {
                // Get the foreign key information
                var foreignKeyAttribute = recordInfo.PropertyForeignKeyAttributes[property];

                // Get the inner type
                var keyType  = GetUnderlyingStoredPrimitiveType(elementType);
                var keyValue = reader.Read(keyType);

                // Create the specific ForeignKey type
                var genericKeyFieldType  = typeof(ForeignKey <>);
                var specificKeyFieldType = genericKeyFieldType.MakeGenericType(keyType);

                fieldValue = Activator.CreateInstance
                             (
                    specificKeyFieldType,
                    foreignKeyAttribute.Database,
                    foreignKeyAttribute.Field,
                    keyValue
                             );
            }
            else if (elementType.IsEnum)
            {
                // Get the underlying type of the enum
                var enumType = elementType.GetEnumUnderlyingType();
                fieldValue = reader.Read(enumType);
            }
            else
            {
                if (elementType == typeof(LocalizedStringReference))
                {
                    fieldValue = reader.Read(elementType, version);
                }
                else
                {
                    fieldValue = reader.Read(elementType);
                }
            }

            return(fieldValue);
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="RecordFieldInformation"/> class.
        /// </summary>
        /// <param name="recordType">The type of record to build the reflection data for.</param>
        /// <param name="version">The version to build data for.</param>
        /// <exception cref="ArgumentException">Thrown if the specified type is not a record type.</exception>
        public RecordFieldInformation(Type recordType, WarcraftVersion version)
        {
            if (!recordType.IsSubclassOf(typeof(DBCRecord)))
            {
                throw new ArgumentException("The specified type was not a record type.", nameof(recordType));
            }

            if (!recordType.GetCustomAttributes().Any(a => a is DatabaseRecordAttribute))
            {
                throw new ArgumentException($"The record type {recordType.Name} was not decorated with the \"DatabaseRecord\" attribute.");
            }

            this.Type    = recordType;
            this.Version = version;
            var orderer = new FieldOrderer(this.Version, DBCInspector.GetVersionRelevantProperties(this.Version, this.Type).ToList());

            this.VersionRelevantProperties = orderer.ReorderProperties().ToList();

            this.PropertyFieldAttributes        = new Dictionary <PropertyInfo, RecordFieldAttribute>();
            this.PropertyFieldArrayAttributes   = new Dictionary <PropertyInfo, RecordFieldArrayAttribute>();
            this.PropertyFieldArrayElementTypes = new Dictionary <PropertyInfo, Type>();
            this.PropertyForeignKeyAttributes   = new Dictionary <PropertyInfo, ForeignKeyInfoAttribute>();

            foreach (var property in this.VersionRelevantProperties)
            {
                if (!property.CanWrite)
                {
                    throw new ArgumentException("Property setter not found. Record properties must have a setter.");
                }

                var fieldInfoAttribute = DBCInspector.GetPropertyFieldAttribute(property);
                this.PropertyFieldAttributes.Add(property, fieldInfoAttribute);

                if (DBCInspector.IsPropertyFieldArray(property))
                {
                    this.PropertyFieldArrayAttributes.Add(property, DBCInspector.GetVersionRelevantPropertyFieldArrayAttribute(this.Version, property));
                    this.PropertyFieldArrayElementTypes.Add(property, DBCInspector.GetFieldArrayPropertyElementType(property.PropertyType));
                }

                if (DBCInspector.IsPropertyForeignKey(property))
                {
                    this.PropertyForeignKeyAttributes.Add(property, DBCInspector.GetForeignKeyInfo(property));
                }
            }

            this.FieldCount = DBCInspector.GetPropertyCount(this.Version, this.Type);
            this.Size       = DBCInspector.GetRecordSize(this.Version, this.Type);
        }