コード例 #1
0
        private static void STUv2ProcessInstance(AssetRecord record, STUInstance instance)
        {
            var fields = GetFields(instance.GetType(), true);

            foreach (FieldInfo field in fields)
            {
                object fieldValue = field.GetValue(instance);
                Type   fieldType  = field.FieldType;
                if (fieldValue == null)
                {
                    continue;
                }

                var fieldAttribute = field.GetCustomAttribute <STUFieldAttribute>();
                if (fieldAttribute != null)
                {
                    if (fieldAttribute.ReaderType == typeof(InlineInstanceFieldReader))
                    {
                        if (!fieldType.IsArray)
                        {
                            STUv2ProcessInstance(record, (STUInstance)fieldValue);
                        }
                        else
                        {
                            IEnumerable enumerable = (IEnumerable)fieldValue;
                            foreach (object val in enumerable)
                            {
                                STUv2ProcessInstance(record, (STUInstance)val);
                            }
                        }

                        return;
                    }
                }

                if (fieldType.IsArray)
                {
                    Type        elementType = fieldType.GetElementType();
                    IEnumerable enumerable  = (IEnumerable)fieldValue;
                    foreach (object val in enumerable)
                    {
                        STUv2ProcessField(record, val, elementType);
                    }
                }
                else
                {
                    STUv2ProcessField(record, fieldValue, fieldType);
                }
            }
        }
コード例 #2
0
        internal object InitializeObject(object instance, Type type, STUInstanceField[] writtenFields,
                                         BinaryReader reader)
        {
            Dictionary <uint, FieldInfo> fieldMap = CreateFieldMap(GetValidFields(type));

            uint?instanceChecksum = (Attribute.GetCustomAttribute(instance.GetType(), typeof(STUAttribute), false) as STUAttribute)?.Checksum;

            if (instance is STUInstance stuInstance && instanceChecksum != null)
            {
                stuInstance.InstanceChecksum = (uint)instanceChecksum;
            }

            foreach (STUInstanceField writtenField in writtenFields)
            {
                if (!fieldMap.ContainsKey(writtenField.FieldChecksum))
                {
                    Debugger.Log(0, "STU",
                                 $"[STU:{type}]: Unknown field {writtenField.FieldChecksum:X8} ({writtenField.FieldSize} bytes)\n");
                    if (writtenField.FieldSize == 0)
                    {
                        uint size = reader.ReadUInt32();
                        reader.BaseStream.Position += size;
                        continue;
                    }
                    reader.BaseStream.Position += writtenField.FieldSize;
                    continue;
                }
                FieldInfo         field   = fieldMap[writtenField.FieldChecksum];
                STUFieldAttribute element = field.GetCustomAttribute <STUFieldAttribute>() ?? new STUFieldAttribute();
                bool skip = false;
                if (element?.STUVersionOnly != null)
                {
                    skip = element.STUVersionOnly.All(version => version != Version);
                }
                if (element?.IgnoreVersion != null && skip)
                {
                    skip = !element.IgnoreVersion.Any(stufield => stufield == writtenField.FieldChecksum);
                }
                if (skip)
                {
                    continue;
                }
                if (!CheckCompatVersion(field, BuildVersion))
                {
                    continue;
                }
                if (field.FieldType.IsArray)
                {
                    field.SetValue(instance, InitializeObjectArray(writtenField, field.FieldType.GetElementType(), reader, element));
                }
                else
                {
                    if (writtenField.FieldSize == 0)
                    {
                        if (field.FieldType.IsClass || field.FieldType.IsValueType)
                        {
                            STUInlineInfo inline         = reader.Read <STUInlineInfo>();
                            object        inlineInstance = Activator.CreateInstance(field.FieldType);
                            if (inline.FieldListIndex < 0 || inline.FieldListIndex >= InstanceFields.Length)
                            {
                                continue;
                            }
                            field.SetValue(instance,
                                           InitializeObject(inlineInstance, field.FieldType, InstanceFields[inline.FieldListIndex],
                                                            reader));
                            STUInstance fieldInstance = field.GetValue(instance) as STUInstance;
                            if (fieldInstance != null)
                            {
                                fieldInstance.Usage = InstanceUsage.Inline;
                            }
                            HiddenInstances.Add(fieldInstance);
                            continue;
                        }
                    }
                    if (writtenField.FieldSize == 4 && field.FieldType.IsClass && !IsSimple(field.FieldType) && typeof(STUInstance).IsAssignableFrom(field.FieldType))
                    {
                        int instanceIndex = reader.ReadInt32();  // sometimes the inline isn't defined in the instance
                        EmbedRequests.Add(new KeyValuePair <object, FieldInfo>(instance, field), instanceIndex);
                        // this is embedded, don't initialise the class
                        continue;
                    }

                    reader.BaseStream.Position += element.Padding;

                    long position = -1;
                    if (element?.ReferenceValue == true)
                    {
                        long offset = reader.ReadInt64();
                        if (offset == 0)
                        {
                            continue;
                        }
                        position = reader.BaseStream.Position;
                        reader.BaseStream.Position = offset;
                    }
                    field.SetValue(instance, GetValue(instance, writtenField, field.FieldType, reader, element, field));
                    if (position > -1)
                    {
                        reader.BaseStream.Position = position;
                    }
                }
                if (element?.Verify != null)
                {
                    if (!field.GetValue(instance).Equals(element.Verify))
                    {
                        throw new Exception("Verification failed");
                    }
                }

                if (element.Demangle)
                {
                    DemangleInstance(instance, writtenField.FieldChecksum);
                }
            }

            return(instance);
        }
コード例 #3
0
        private object InitializeObjectArray(STUInstanceField field, Type type, BinaryReader reader, STUFieldAttribute element)
        {
            if (field.FieldSize == 0 && field.FieldChecksum != 0)
            {
                STUInlineArrayInfo inlineInfo = reader.Read <STUInlineArrayInfo>();
                if (inlineInfo.Size > 600000)
                {
                    return(null);                          // i feel that it's unlikley that there will be an inline with this count, exceptions if this isn't checked.
                }
                Array array = Array.CreateInstance(type, (uint)inlineInfo.Count);
                // if (inlineInfo.FieldListIndex == 0) return array;
                for (uint i = 0; i < (uint)inlineInfo.Count; ++i)
                {
                    Stream.Position += element.Padding;
                    uint   fieldIndex = reader.ReadUInt32();
                    object instance   = Activator.CreateInstance(type);
                    if (fieldIndex >= InstanceFieldLists.Length)
                    {
                        continue;
                    }
                    array.SetValue(InitializeObject(instance, type, InstanceFields[fieldIndex], reader), i);
                    STUInstance fieldInstance = array.GetValue(i) as STUInstance;
                    if (fieldInstance != null)
                    {
                        fieldInstance.Usage = InstanceUsage.InlineArray;
                    }
                    HiddenInstances.Add(fieldInstance);
                }
                return(array);
            }
            if (typeof(STUInstance).IsAssignableFrom(type))
            {
                int embedArrayOffset = reader.ReadInt32();
                Metadata.Position = embedArrayOffset;
                STUEmbedArrayInfo embedArrayInfo = MetadataReader.Read <STUEmbedArrayInfo>();

                if (embedArrayInfo.Count == 0)
                {
                    return(null);
                }
                Metadata.Position = embedArrayInfo.Offset;

                Array array = Array.CreateInstance(type, embedArrayInfo.Count);

                List <int> request = new List <int>();
                for (int i = 0; i < embedArrayInfo.Count; i++)
                {
                    int instanceIndex = MetadataReader.ReadInt32();
                    MetadataReader.ReadInt32(); // Padding
                    if (instanceIndex == -1)
                    {
                        return(null);
                    }
                    request.Add(instanceIndex);
                }
                EmbedArrayRequests[array] = request.ToArray();
                return(array);
            }
            int offset = reader.ReadInt32();

            Metadata.Position = offset;
            STUArrayInfo arrayInfo = MetadataReader.Read <STUArrayInfo>();

            Metadata.Position = arrayInfo.Offset;
            return(GetValueArray(type, element, arrayInfo, field));
        }