Esempio n. 1
0
        public void Deserialize(BinaryReader reader, PackageFile package)
        {
            PropertyTags = new List <PropertyTag>();
            Properties   = new List <ISerializable>();
            while (true)
            {
                var pos  = reader.BaseStream.Position;
                var name = new FName();
                name.Deserialize(reader, package);
                if (name.Value == "None")
                {
                    break;
                }

                reader.BaseStream.Position = pos;

                var tag = new PropertyTag();
                tag.Deserialize(reader, package);
                PropertyTags.Add(tag);

                Type?propertyType;
                if (!PackageFile.KnownTypes.TryGetValue(tag.Type.Value, out propertyType))
                {
                    if (!PackageFile.KnownTypes.TryGetValue("F" + tag.Type.Value, out propertyType))
                    {
                        throw new Exception($"UAsset uses unknown struct type {tag.Type.Value}!");
                    }
                }

                var prop = Activator.CreateInstance(propertyType) as ISerializable;
                prop.Deserialize(reader, package);
                Properties.Add(prop);
            }
            Reserved = reader.ReadUInt32();

            // ObjectProperty data comes after the properties/propertytags section
            // I don't know if any other properties are handled this way, probably not, doing this is likely wrong for 99% of other UE4 properties

            PropertiesData = new Dictionary <FName, ISerializableText>();
            foreach (var prop in Properties)
            {
                if (prop.GetType() != typeof(ObjectProperty))
                {
                    continue;
                }

                var objectProperty = prop as ObjectProperty;

                Type?propertyType;
                if (!PackageFile.KnownTypes.TryGetValue(objectProperty.Value.ImportObject.ObjectName.Value, out propertyType))
                {
                    if (!PackageFile.KnownTypes.TryGetValue("F" + objectProperty.Value.ImportObject.ObjectName.Value, out propertyType))
                    {
                        throw new Exception($"UAsset uses unknown struct type {objectProperty.Value.ImportObject.ObjectName.Value}!");
                    }
                }

                if (propertyType == typeof(FJackDataTableNativizationAsset) || propertyType == typeof(FJackDataTableBlueprintClass))
                {
                    Program.DoFNameCleanup = false; // contains a bunch of unreferenced FNames, can't cleanup properly :(
                }
                if (package.SkipPropertyDataLoad)
                {
                    continue;
                }

                int count = reader.ReadInt32();
                for (int i = 0; i < count; i++)
                {
                    var rowName = new FName();
                    rowName.Deserialize(reader, package);

                    var position = reader.BaseStream.Position;
                    if (propertyType.BaseType.GetInterfaces().Contains(typeof(ISerializableText)))
                    {
                        int structSize = 0;
                        var settings   = propertyType.GetCustomAttribute <SerializerAttribute>();
                        if (settings == null || !settings.NoStructSize)
                        {
                            structSize = reader.ReadInt32();
                            position   = reader.BaseStream.Position;
                        }

                        var propData = Activator.CreateInstance(propertyType) as ISerializableText;
                        propData.Deserialize(reader, package);

                        var length = reader.BaseStream.Position - position;
                        if (structSize != 0 && length != structSize)
                        {
                            throw new Exception($"DataTable read incorrect number of bytes (read {length}, expected {structSize}!)");
                            reader.BaseStream.Position = position + structSize;
                        }

                        PropertiesData.Add(rowName, propData);
                    }
                }
            }
        }
Esempio n. 2
0
        public object DeserializeValue(Type type, SerializerAttribute settings, BinaryReader reader, PackageFile package, bool isListElement = false)
        {
            switch (type.Name)
            {
            case "String":     // FString
                return(reader.ReadFString());

            case "Byte[]":
                int    sz   = settings?.Size ?? 0;
                byte[] data = reader.ReadBytes(sz);
                return(data);

            case "Boolean":
                return(DeserializeBool(settings, reader, package, isListElement));

            case "Byte":
                return(reader.ReadByte());

            case "Int16":
                return(reader.ReadInt16());

            case "UInt16":
                return(reader.ReadUInt16());

            case "Int32":
                return(reader.ReadInt32());

            case "UInt32":
                return(reader.ReadUInt32());

            case "Single":
                return(reader.ReadSingle());

            case "Double":
                return(reader.ReadDouble());

            case "Int64":
                return(reader.ReadInt64());

            case "UInt64":
                return(reader.ReadUInt64());

            case "List`1":
                // TArray
                var elementType = type.GetGenericArguments()[0];
                var listType    = typeof(List <>).MakeGenericType(elementType);
                var list        = Activator.CreateInstance(listType) as IList;

                int count = reader.ReadInt32();
                for (int i = 0; i < count; i++)
                {
                    list.Add(DeserializeValue(elementType, settings, reader, package, true));
                }

                return(list);

            case "FName":
                var name = new FName();
                name.Deserialize(reader, package);
                return(name);

            default:
                if (type.IsEnum)
                {
                    var enumType = Enum.GetUnderlyingType(type);
                    return(DeserializeValue(enumType, settings, reader, package));
                }
                if (type.GetInterfaces().Contains(typeof(ISerializable)))
                {
                    var obj = Activator.CreateInstance(type) as ISerializable;
                    obj.Deserialize(reader, package);
                    return(obj);
                }
                break;
            }

            return(null);
        }
Esempio n. 3
0
        public void Serialize(BinaryWriter writer, PackageFile package)
        {
            for (int i = 0; i < PropertyTags.Count; i++)
            {
                var           tag      = PropertyTags[i];
                ISerializable property = null;
                if (Properties.Count >= i)
                {
                    property = Properties[i];
                }

                tag.Serialize(writer, package);
                if (property != null)
                {
                    property.Serialize(writer, package);
                }
            }
            var endName = new FName();

            endName.Value = "None";
            endName.Serialize(writer, package);

            writer.Write(Reserved);

            foreach (var prop in Properties)
            {
                if (prop.GetType() != typeof(ObjectProperty))
                {
                    continue;
                }

                writer.Write(PropertiesData.Count);

                foreach (var kvp in PropertiesData)
                {
                    kvp.Key.Serialize(writer, package);

                    bool writeStructSize = true;
                    var  settings        = kvp.Value.GetType().GetCustomAttribute <SerializerAttribute>();
                    if (settings != null && settings.NoStructSize)
                    {
                        writeStructSize = false;
                    }

                    long structSizePosition = 0;

                    if (writeStructSize)
                    {
                        structSizePosition = writer.BaseStream.Position;
                        writer.Write((int)0);// dummy val, we'll fix it later
                    }

                    var structStartPosition = writer.BaseStream.Position;
                    kvp.Value.Serialize(writer, package);
                    var structEndPosition = writer.BaseStream.Position;

                    if (writeStructSize)
                    {
                        var structSize = structEndPosition - structStartPosition;
                        writer.BaseStream.Position = structSizePosition;
                        writer.Write((uint)structSize);
                        writer.BaseStream.Position = structEndPosition;
                    }
                }
            }
        }