Exemple #1
0
        public void TestCustomSerializationStructsInMap()
        {
            var tester = new UAsset(Path.Combine("TestCustomSerializationStructsInMap", "wtf.uasset"), UE4Version.VER_UE4_25);

            Assert.IsTrue(tester.VerifyBinaryEquality());

            // Get the map property in export 2
            Export exportTwo = FPackageIndex.FromRawIndex(2).ToExport(tester);

            Assert.IsTrue(exportTwo is NormalExport);

            NormalExport exportTwoNormal = (NormalExport)exportTwo;

            var             mapPropertyName = FName.FromString("KekWait");
            MapPropertyData testMap         = exportTwoNormal[mapPropertyName] as MapPropertyData;

            Assert.IsNotNull(testMap);
            Assert.IsTrue(testMap == exportTwoNormal[mapPropertyName.Value.Value]);

            // Get the first entry of the map
            StructPropertyData entryKey   = testMap?.Value?.Keys?.ElementAt(0) as StructPropertyData;
            StructPropertyData entryValue = testMap?.Value?[0] as StructPropertyData;

            Assert.IsNotNull(entryKey?.Value?[0]);
            Assert.IsNotNull(entryValue?.Value?[0]);

            // Check that the properties are correct
            Assert.IsTrue(entryKey.Value[0] is VectorPropertyData);
            Assert.IsTrue(entryValue.Value[0] is LinearColorPropertyData);
        }
Exemple #2
0
        public override ZeroPaddingMode Read2(BinaryReader reader, int nextStarting)
        {
            // Find an ObjectProperty named RowStruct
            string decidedStructType = "Generic";

            foreach (PropertyData thisData in Data)
            {
                if (thisData.Name == "RowStruct" && thisData is ObjectPropertyData thisObjData)
                {
                    decidedStructType = Asset.GetHeaderReference((int)thisObjData.Value.Property);
                    break;
                }
            }
            Debug.WriteLine(decidedStructType);

            reader.ReadInt32();

            Data2 = new DataTable();

            int numEntries = reader.ReadInt32();

            for (int i = 0; i < numEntries; i++)
            {
                string rowName        = Asset.GetHeaderReference(reader.ReadInt32());
                int    duplicateIndex = reader.ReadInt32();
                var    nextStruct     = new StructPropertyData(rowName, Asset)
                {
                    StructType = decidedStructType
                };
                nextStruct.Read(reader, false, 0);
                Data2.Table.Add(new DataTableEntry(nextStruct, duplicateIndex));
            }
            return(ZeroPaddingMode.Unknown);
        }
Exemple #3
0
        public override void Read(AssetBinaryReader reader, int nextStarting)
        {
            base.Read(reader, nextStarting);

            // Find an ObjectProperty named RowStruct
            FName decidedStructType = new FName("Generic");

            foreach (PropertyData thisData in Data)
            {
                if (thisData.Name.Value.Value == "RowStruct" && thisData is ObjectPropertyData thisObjData && thisObjData.Value.IsImport())
                {
                    decidedStructType = thisObjData.ToImport(reader.Asset).ObjectName;
                    break;
                }
            }

            reader.ReadInt32();

            Table = new UDataTable();

            int numEntries = reader.ReadInt32();

            for (int i = 0; i < numEntries; i++)
            {
                FName rowName    = reader.ReadFName();
                var   nextStruct = new StructPropertyData(rowName)
                {
                    StructType = decidedStructType
                };
                nextStruct.Read(reader, false, 1);
                Table.Data.Add(nextStruct);
            }
        }
Exemple #4
0
        public void TestDataTables()
        {
            var tester = new UAsset(Path.Combine("TestDatatables", "PB_DT_RandomizerRoomCheck.uasset"), UE4Version.VER_UE4_18);

            Assert.IsTrue(tester.VerifyBinaryEquality());
            Assert.IsTrue(CheckAllExportsParsedCorrectly(tester));
            Assert.IsTrue(tester.Exports.Count == 1);

            var ourDataTableExport = tester.Exports[0] as DataTableExport;
            var ourTable           = ourDataTableExport?.Table;

            Assert.IsNotNull(ourTable);

            // Check out the first entry to make sure it's parsing alright, and flip all the flags for later testing
            StructPropertyData firstEntry = ourTable.Data[0];

            bool didFindTestName = false;

            for (int i = 0; i < firstEntry.Value.Count; i++)
            {
                var propData = firstEntry.Value[i];
                Debug.WriteLine(i + ": " + propData.Name + ", " + propData.PropertyType);
                if (propData.Name == new FName("AcceleratorANDDoubleJump"))
                {
                    didFindTestName = true;
                }
                if (propData is BoolPropertyData boolProp)
                {
                    boolProp.Value = !boolProp.Value;
                }
            }
            Assert.IsTrue(didFindTestName);

            // Save the modified table
            tester.Write(Path.Combine("TestDatatables", "MODIFIED.uasset"));

            // Load the modified table back in and make sure we're good
            var tester2 = new UAsset(Path.Combine("TestDatatables", "MODIFIED.uasset"), UE4Version.VER_UE4_18);

            Assert.IsTrue(tester2.VerifyBinaryEquality());
            Assert.IsTrue(CheckAllExportsParsedCorrectly(tester2));
            Assert.IsTrue(tester2.Exports.Count == 1);

            // Flip the flags back to what they originally were
            firstEntry = (tester2.Exports[0] as DataTableExport)?.Table?.Data?[0];
            Assert.IsNotNull(firstEntry);
            for (int i = 0; i < firstEntry.Value.Count; i++)
            {
                if (firstEntry.Value[i] is BoolPropertyData boolProp)
                {
                    boolProp.Value = !boolProp.Value;
                }
            }

            // Save and check that it's binary equal to what we originally had
            tester2.Write(tester2.FilePath);
            Assert.IsTrue(File.ReadAllBytes(Path.Combine("TestDatatables", "PB_DT_RandomizerRoomCheck.uasset")).SequenceEqual(File.ReadAllBytes(Path.Combine("TestDatatables", "MODIFIED.uasset"))));
        }
Exemple #5
0
        public override int Write(BinaryWriter writer, bool includeHeader)
        {
            if (Value.Length > 0)
            {
                ArrayType = Value[0].Type;
            }

            if (includeHeader)
            {
                writer.Write((long)Asset.SearchHeaderReference(ArrayType));
                writer.Write((byte)0);
            }

            int here = (int)writer.BaseStream.Position;

            writer.Write(Value.Length);
            if (ArrayType == "StructProperty")
            {
                StructPropertyData firstElem = Value.Length == 0 ? DummyStruct : (StructPropertyData)Value[0];
                string             fullType  = firstElem.StructType;

                writer.Write((long)Asset.SearchHeaderReference(firstElem.Name));
                writer.Write((long)Asset.SearchHeaderReference("StructProperty"));
                int lengthLoc = (int)writer.BaseStream.Position;
                writer.Write((long)0);
                writer.Write((long)Asset.SearchHeaderReference(fullType));
                writer.Write(firstElem.StructGUID.ToByteArray());
                writer.Write((byte)0);

                for (int i = 0; i < Value.Length; i++)
                {
                    ((StructPropertyData)Value[i]).StructType = fullType;
                    Value[i].Write(writer, false);
                }

                int fullLen = (int)writer.BaseStream.Position - lengthLoc;
                int newLoc  = (int)writer.BaseStream.Position;
                writer.Seek(lengthLoc, SeekOrigin.Begin);
                writer.Write(fullLen - 32 - (includeHeader ? 1 : 0));
                writer.Seek(newLoc, SeekOrigin.Begin);
            }
            else
            {
                for (int i = 0; i < Value.Length; i++)
                {
                    Value[i].Write(writer, false);
                }
            }

            return((int)writer.BaseStream.Position - here);
        }
Exemple #6
0
        private PropertyData MapTypeToClass(string type, string name, AssetReader asset, BinaryReader reader, long leng, bool includeHeader)
        {
            switch (type)
            {
            case "StructProperty":
                StructPropertyData data = new StructPropertyData(name, asset, "Generic");
                data.Read(reader, false, leng);
                return(data);

            default:
                var res = MainSerializer.TypeToClass(type, name, asset, null, leng);
                res.Read(reader, includeHeader, leng);
                return(res);
            }
        }
Exemple #7
0
        private PropertyData MapTypeToClass(FName type, FName name, AssetBinaryReader reader, int leng, bool includeHeader, bool isKey)
        {
            switch (type.Value.Value)
            {
            case "StructProperty":
                FName strucType = null;

                if (reader.Asset.MapStructTypeOverride.ContainsKey(name.Value.Value))
                {
                    if (isKey)
                    {
                        strucType = reader.Asset.MapStructTypeOverride[name.Value.Value].Item1;
                    }
                    else
                    {
                        strucType = reader.Asset.MapStructTypeOverride[name.Value.Value].Item2;
                    }
                }

                if (strucType == null)
                {
                    strucType = new FName("Generic");
                }

                StructPropertyData data = new StructPropertyData(name, strucType);
                data.Offset = reader.BaseStream.Position;
                data.Read(reader, false, 1);
                return(data);

            default:
                var res = MainSerializer.TypeToClass(type, name, reader.Asset, null, leng);
                res.Offset = reader.BaseStream.Position;
                res.Read(reader, includeHeader, leng);
                return(res);
            }
        }
Exemple #8
0
        public static PropertyData TypeToClass(string type, string name, AssetReader asset, BinaryReader reader = null, long leng = 0, bool includeHeader = true)
        {
            //Debug.WriteLine(type);
            PropertyData data;

            switch (type)
            {
            case "BoolProperty":
                data = new BoolPropertyData(name, asset);
                break;

            case "Int8Property":
                data = new Int8PropertyData(name, asset);
                break;

            case "Int16Property":
                data = new Int16PropertyData(name, asset);
                break;

            case "IntProperty":
                data = new IntPropertyData(name, asset);
                break;

            case "Int64Property":
                data = new Int64PropertyData(name, asset);
                break;

            case "UInt16Property":
                data = new UInt16PropertyData(name, asset);
                break;

            case "UInt32Property":
                data = new UInt32PropertyData(name, asset);
                break;

            case "UInt64Property":
                data = new UInt64PropertyData(name, asset);
                break;

            case "FloatProperty":
                data = new FloatPropertyData(name, asset);
                break;

            case "TextProperty":
                data = new TextPropertyData(name, asset);
                break;

            case "StrProperty":
                data = new StrPropertyData(name, asset);
                break;

            case "ObjectProperty":
                data = new ObjectPropertyData(name, asset);
                break;

            case "EnumProperty":
                data = new EnumPropertyData(name, asset);
                break;

            case "ByteProperty":
                data = new BytePropertyData(name, asset);
                break;

            case "NameProperty":
                data = new NamePropertyData(name, asset);
                break;

            case "ArrayProperty":
                data = new ArrayPropertyData(name, asset);
                break;

            case "MapProperty":
                data = new MapPropertyData(name, asset);
                break;

            case "StructProperty":
                data = new StructPropertyData(name, asset);
                break;

            case "Guid":
                data = new GuidPropertyData(name, asset);
                break;

            case "LinearColor":
                data = new LinearColorPropertyData(name, asset);
                break;

            case "Color":
                data = new ColorPropertyData(name, asset);
                break;

            case "Vector":
                data = new VectorPropertyData(name, asset);
                break;

            case "Vector2D":
                data = new Vector2DPropertyData(name, asset);
                break;

            case "Box":
                data = new BoxPropertyData(name, asset);
                break;

            case "IntPoint":
                data = new IntPointPropertyData(name, asset);
                break;

            case "DateTime":
                data = new DateTimePropertyData(name, asset);
                break;

            case "Timespan":
                data = new TimespanPropertyData(name, asset);
                break;

            case "Rotator":
                data = new RotatorPropertyData(name, asset);
                break;

            case "Quat":
                data = new QuatPropertyData(name, asset);
                break;

            case "Vector4":
                data = new Vector4PropertyData(name, asset);
                break;

            case "SoftObjectProperty":
                data = new SoftObjectPropertyData(name, asset);
                break;

            case "MulticastDelegateProperty":
                data = new MulticastDelegatePropertyData(name, asset);
                break;

            default:
#if DEBUG
                Debug.WriteLine("Last type: " + lastType);
#endif
                if (reader == null)
                {
                    throw new FormatException("Unknown property type: " + type + " (on " + name + ")");
                }
                throw new FormatException("Unknown property type: " + type + " (on " + name + " at " + reader.BaseStream.Position + ")");
            }
#if DEBUG
            lastType = type;
#endif
            if (reader != null)
            {
                data.Read(reader, includeHeader, leng);
            }
            return(data);
        }
Exemple #9
0
 public DataTableEntry(StructPropertyData data, int duplicateIndex)
 {
     Data           = data;
     DuplicateIndex = duplicateIndex;
 }
        public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0)
        {
            if (includeHeader)
            {
                ArrayType    = reader.ReadFName();
                PropertyGuid = reader.ReadPropertyGuid();
            }

            int numEntries = reader.ReadInt32();

            if (ArrayType.Value.Value == "StructProperty" && ShouldSerializeStructsDifferently)
            {
                var results = new PropertyData[numEntries];

                FName name         = this.Name;
                long  structLength = 1;
                FName fullType     = new FName("Generic");
                Guid  structGUID   = new Guid();

                if (reader.Asset.EngineVersion >= UE4Version.VER_UE4_INNER_ARRAY_TAG_INFO)
                {
                    name = reader.ReadFName();
                    if (name.Value.Value.Equals("None"))
                    {
                        Value = results;
                        return;
                    }

                    FName thisArrayType = reader.ReadFName();
                    if (thisArrayType.Value.Value.Equals("None"))
                    {
                        Value = results;
                        return;
                    }

                    if (thisArrayType.Value.Value != ArrayType.Value.Value)
                    {
                        throw new FormatException("Invalid array type: " + thisArrayType.ToString() + " vs " + ArrayType.ToString());
                    }

                    structLength = reader.ReadInt64(); // length value
                    fullType     = reader.ReadFName();
                    structGUID   = new Guid(reader.ReadBytes(16));
                    reader.ReadPropertyGuid();
                }

                if (numEntries == 0)
                {
                    DummyStruct = new StructPropertyData(name, fullType)
                    {
                        StructGUID = structGUID
                    };
                }
                else
                {
                    for (int i = 0; i < numEntries; i++)
                    {
                        var data = new StructPropertyData(name, fullType);
                        data.Offset = reader.BaseStream.Position;
                        data.Read(reader, false, structLength);
                        data.StructGUID = structGUID;
                        results[i]      = data;
                    }
                    DummyStruct = (StructPropertyData)results[0];
                }
                Value = results;
            }
            else
            {
                var results = new PropertyData[numEntries];
                if (numEntries > 0)
                {
                    int averageSizeEstimate1 = (int)(leng1 / numEntries);
                    int averageSizeEstimate2 = (int)((leng1 - 4) / numEntries);
                    for (int i = 0; i < numEntries; i++)
                    {
                        results[i]        = MainSerializer.TypeToClass(ArrayType, new FName(i.ToString(), int.MinValue), reader.Asset);
                        results[i].Offset = reader.BaseStream.Position;
                        if (results[i] is StructPropertyData)
                        {
                            ((StructPropertyData)results[i]).StructType = new FName("Generic");
                        }
                        results[i].Read(reader, false, averageSizeEstimate1, averageSizeEstimate2);
                    }
                }
                Value = results;
            }
        }
        public override int Write(AssetBinaryWriter writer, bool includeHeader)
        {
            if (Value.Length > 0)
            {
                ArrayType = Value[0].PropertyType;
            }

            if (includeHeader)
            {
                writer.Write(ArrayType);
                writer.WritePropertyGuid(PropertyGuid);
            }

            int here = (int)writer.BaseStream.Position;

            writer.Write(Value.Length);
            if (ArrayType.Value.Value == "StructProperty" && ShouldSerializeStructsDifferently)
            {
                if (Value.Length == 0 && DummyStruct == null)
                {
                    throw new InvalidOperationException("No dummy struct present in an empty StructProperty array, cannot serialize");
                }
                if (Value.Length > 0)
                {
                    DummyStruct = (StructPropertyData)Value[0];
                }

                FName fullType = DummyStruct.StructType;

                int lengthLoc = -1;
                if (writer.Asset.EngineVersion >= UE4Version.VER_UE4_INNER_ARRAY_TAG_INFO)
                {
                    writer.Write(DummyStruct.Name);
                    writer.Write(new FName("StructProperty"));
                    lengthLoc = (int)writer.BaseStream.Position;
                    writer.Write((long)0);
                    writer.Write(fullType);
                    if (writer.Asset.EngineVersion >= UE4Version.VER_UE4_STRUCT_GUID_IN_PROPERTY_TAG)
                    {
                        writer.Write(DummyStruct.StructGUID.ToByteArray());
                    }
                    if (writer.Asset.EngineVersion >= UE4Version.VER_UE4_PROPERTY_GUID_IN_PROPERTY_TAG)
                    {
                        writer.Write((byte)0);
                    }
                }

                for (int i = 0; i < Value.Length; i++)
                {
                    ((StructPropertyData)Value[i]).StructType = fullType;
                    Value[i].Offset = writer.BaseStream.Position;
                    Value[i].Write(writer, false);
                }

                if (writer.Asset.EngineVersion >= UE4Version.VER_UE4_INNER_ARRAY_TAG_INFO)
                {
                    int fullLen = (int)writer.BaseStream.Position - lengthLoc;
                    int newLoc  = (int)writer.BaseStream.Position;
                    writer.Seek(lengthLoc, SeekOrigin.Begin);
                    writer.Write(fullLen - 32 - (includeHeader ? 1 : 0));
                    writer.Seek(newLoc, SeekOrigin.Begin);
                }
            }
            else
            {
                for (int i = 0; i < Value.Length; i++)
                {
                    Value[i].Offset = writer.BaseStream.Position;
                    Value[i].Write(writer, false);
                }
            }

            return((int)writer.BaseStream.Position - here);
        }
Exemple #12
0
        public override void Read(BinaryReader reader, bool includeHeader, long leng)
        {
            if (includeHeader)
            {
                ArrayType = Asset.GetHeaderReference((int)reader.ReadInt64());
                reader.ReadByte(); // null byte
            }

            int numEntries = reader.ReadInt32();

            if (ArrayType == "StructProperty")
            {
                var    results = new PropertyData[numEntries];
                string name    = Asset.GetHeaderReference((int)reader.ReadInt64());
                if (name.Equals("None"))
                {
                    Value = results;
                    return;
                }

                if (Asset.GetHeaderReference((int)reader.ReadInt64()) != ArrayType)
                {
                    throw new FormatException("Invalid array type");
                }
                reader.ReadInt64(); // length value

                string fullType   = Asset.GetHeaderReference((int)reader.ReadInt64());
                Guid   structGUID = new Guid(reader.ReadBytes(16));
                reader.ReadByte();

                if (numEntries == 0)
                {
                    DummyStruct = new StructPropertyData(name, Asset, fullType)
                    {
                        StructGUID = structGUID
                    };
                }
                else
                {
                    for (int i = 0; i < numEntries; i++)
                    {
                        var data = new StructPropertyData(name, Asset, fullType);
                        data.Read(reader, false, 0);
                        data.StructGUID = structGUID;
                        results[i]      = data;
                    }
                }
                Value = results;
            }
            else
            {
                var results = new PropertyData[numEntries];
                if (numEntries > 0)
                {
                    int averageSize = (int)(leng / numEntries);
                    for (int i = 0; i < numEntries; i++)
                    {
                        results[i] = MainSerializer.TypeToClass(ArrayType, Name, Asset);
                        results[i].Read(reader, false, averageSize);
                    }
                }
                Value = results;
            }
        }