public static void ReadAndMapProperty(this Stream stream, object obj, List<string> nameTable)
        {
            var baseProperty = stream.ReadBaseProperty();

            var pi = obj.GetType().GetField(nameTable[baseProperty.NameIdx], BindingFlags.Public | BindingFlags.Instance);
            if (pi == null) return;

            var fieldType = pi.FieldType.IsGenericType && pi.FieldType.GetGenericTypeDefinition() == typeof (Nullable<>)
                ? Nullable.GetUnderlyingType(pi.FieldType)
                : pi.FieldType;
            object value = null;

            switch (nameTable[baseProperty.TypeIdx])
            {
                case "IntProperty":
                    value = stream.ReadInt32();
                    break;
                case "BoolProperty":
                    value = stream.ReadBool();
                    break;
                case "ByteProperty":
                    stream.ReadInt32(); // EnumNameIdx
                    var enumValueNameIdx = stream.ReadInt32();
                    value = Enum.Parse(fieldType, nameTable[enumValueNameIdx]);
                    break;
                case "FloatProperty":
                    value = stream.ReadFloat();
                    break;
                case "NameProperty":
                    value = stream.ReadNameProperty(nameTable);
                    break;
                case "StrProperty":
                    value = stream.ReadString();
                    break;
                case "ArrayProperty":
                    // У массивов NumElements входит в PropertySize
                    var numElements = stream.ReadInt32();
                    // Если элементов нет, то следом идет сразу следующее свойство, массив не заканчивается ничем, нет даже None
                    if (numElements == 0) return;

                    value = Activator.CreateInstance(fieldType);

                    var elementType = fieldType.GetGenericArguments()[0];
                    for (var i = 0; i < numElements; i++)
                    {
                        if (elementType == typeof (int)) // array<int>
                        {
                            (value as IList).Add(stream.ReadInt32());
                        }
                        else if (elementType == typeof (string)) // array<string>
                        {
                            (value as IList).Add(stream.ReadString());
                        }
                        else if (elementType == typeof (NameProperty)) // array<name>
                        {
                            (value as IList).Add(stream.ReadNameProperty(nameTable));
                        }
                        else
                        {
                            var element = Activator.CreateInstance(elementType);
                            var nameIdx = stream.ReadInt32();
                            while (nameTable[nameIdx] != "None")
                            {
                                stream.Seek(-4, SeekOrigin.Current);
                                stream.ReadAndMapProperty(element, nameTable);
                                nameIdx = stream.ReadInt32();
                            }
                            (value as IList).Add(element);
                        }
                    }
                    break;
                case "StructProperty":
                    // У структур StructNameIdx не входит в PropertySize
                    var structNameIdx = stream.ReadInt32();
                    switch (nameTable[structNameIdx])
                    {
                        case "Vector":
                            value = new Vector
                            {
                                X = stream.ReadFloat(),
                                Y = stream.ReadFloat(),
                                Z = stream.ReadFloat()
                            };
                            break;
                        case "Rotator":
                            value = new Rotator
                            {
                                Pitch = stream.ReadInt32(),
                                Yaw = stream.ReadInt32(),
                                Roll = stream.ReadInt32()
                            };
                            break;
                        case "Transform":
                            stream.Seek(baseProperty.PropertySize, SeekOrigin.Current);
                            break;
                        default:
                            // На случай SEpisodeBoundaryStats[]
                            value = Activator.CreateInstance(fieldType.IsArray ? fieldType.GetElementType() : fieldType);
                            var nameIdx = stream.ReadInt32();
                            // None в конце всех структур, кроме стандартных Vector, Rotator, Transform
                            while (nameTable[nameIdx] != "None")
                            {
                                stream.Seek(-4, SeekOrigin.Current);
                                stream.ReadAndMapProperty(value, nameTable);
                                nameIdx = stream.ReadInt32();
                            }
                            break;
                    }
                    break;
            }
            if (fieldType.IsArray)
            {
                var array = (Array) pi.GetValue(obj);
                array.SetValue(value, baseProperty.ArrayIdx);
                pi.SetValue(obj, array);
            }
            else
            {
                pi.SetValue(obj, value);
            }
        }
Exemplo n.º 2
0
        public static void ReadAndMapProperty(this Stream stream, object obj, List <string> nameTable)
        {
            var baseProperty = stream.ReadBaseProperty();

            var pi = obj.GetType().GetField(nameTable[baseProperty.NameIdx], BindingFlags.Public | BindingFlags.Instance);

            if (pi == null)
            {
                return;
            }

            var fieldType = pi.FieldType.IsGenericType && pi.FieldType.GetGenericTypeDefinition() == typeof(Nullable <>)
                ? Nullable.GetUnderlyingType(pi.FieldType)
                : pi.FieldType;
            object value = null;

            switch (nameTable[baseProperty.TypeIdx])
            {
            case "IntProperty":
                value = stream.ReadInt32();
                break;

            case "BoolProperty":
                value = stream.ReadBool();
                break;

            case "ByteProperty":
                stream.ReadInt32();     // EnumNameIdx
                var enumValueNameIdx = stream.ReadInt32();
                value = Enum.Parse(fieldType, nameTable[enumValueNameIdx]);
                break;

            case "FloatProperty":
                value = stream.ReadFloat();
                break;

            case "NameProperty":
                value = stream.ReadNameProperty(nameTable);
                break;

            case "StrProperty":
                value = stream.ReadString();
                break;

            case "ArrayProperty":
                // У массивов NumElements входит в PropertySize
                var numElements = stream.ReadInt32();
                // Если элементов нет, то следом идет сразу следующее свойство, массив не заканчивается ничем, нет даже None
                if (numElements == 0)
                {
                    return;
                }

                value = Activator.CreateInstance(fieldType);

                var elementType = fieldType.GetGenericArguments()[0];
                for (var i = 0; i < numElements; i++)
                {
                    if (elementType == typeof(int))      // array<int>
                    {
                        (value as IList).Add(stream.ReadInt32());
                    }
                    else if (elementType == typeof(string))      // array<string>
                    {
                        (value as IList).Add(stream.ReadString());
                    }
                    else if (elementType == typeof(NameProperty))      // array<name>
                    {
                        (value as IList).Add(stream.ReadNameProperty(nameTable));
                    }
                    else
                    {
                        var element = Activator.CreateInstance(elementType);
                        var nameIdx = stream.ReadInt32();
                        while (nameTable[nameIdx] != "None")
                        {
                            stream.Seek(-4, SeekOrigin.Current);
                            stream.ReadAndMapProperty(element, nameTable);
                            nameIdx = stream.ReadInt32();
                        }
                        (value as IList).Add(element);
                    }
                }
                break;

            case "StructProperty":
                // У структур StructNameIdx не входит в PropertySize
                var structNameIdx = stream.ReadInt32();
                switch (nameTable[structNameIdx])
                {
                case "Vector":
                    value = new Vector
                    {
                        X = stream.ReadFloat(),
                        Y = stream.ReadFloat(),
                        Z = stream.ReadFloat()
                    };
                    break;

                case "Rotator":
                    value = new Rotator
                    {
                        Pitch = stream.ReadInt32(),
                        Yaw   = stream.ReadInt32(),
                        Roll  = stream.ReadInt32()
                    };
                    break;

                case "Transform":
                    stream.Seek(baseProperty.PropertySize, SeekOrigin.Current);
                    break;

                default:
                    // На случай SEpisodeBoundaryStats[]
                    value = Activator.CreateInstance(fieldType.IsArray ? fieldType.GetElementType() : fieldType);
                    var nameIdx = stream.ReadInt32();
                    // None в конце всех структур, кроме стандартных Vector, Rotator, Transform
                    while (nameTable[nameIdx] != "None")
                    {
                        stream.Seek(-4, SeekOrigin.Current);
                        stream.ReadAndMapProperty(value, nameTable);
                        nameIdx = stream.ReadInt32();
                    }
                    break;
                }
                break;
            }
            if (fieldType.IsArray)
            {
                var array = (Array)pi.GetValue(obj);
                array.SetValue(value, baseProperty.ArrayIdx);
                pi.SetValue(obj, array);
            }
            else
            {
                pi.SetValue(obj, value);
            }
        }