示例#1
0
            public int    Parameter2; // Parameter #2

            public CTDAField(UnityBinaryReader r, int dataSize, GameFormatId format)
            {
                if (format == GameFormatId.TES3)
                {
                    Index           = r.ReadByte();
                    Type            = r.ReadByte();
                    FunctionId      = r.ReadASCIIString(2);
                    CompareOp       = (byte)(r.ReadByte() << 1);
                    Name            = r.ReadASCIIString(dataSize - 5);
                    ComparisonValue = Parameter1 = Parameter2 = 0;
                    return;
                }
                CompareOp = r.ReadByte();
                r.SkipBytes(3); // Unused
                ComparisonValue = r.ReadLESingle();
                FunctionId      = r.ReadASCIIString(4);
                Parameter1      = r.ReadLEInt32();
                Parameter2      = r.ReadLEInt32();
                if (dataSize != 24)
                {
                    r.SkipBytes(4); // Unused
                }
                Index = Type = 0;
                Name  = null;
            }
示例#2
0
 public HEDRField(UnityBinaryReader r, int dataSize)
 {
     Version         = r.ReadLESingle();
     FileType        = r.ReadLEUInt32();
     CompanyName     = r.ReadASCIIString(32, ASCIIFormat.ZeroPadded);
     FileDescription = r.ReadASCIIString(256, ASCIIFormat.ZeroPadded);
     NumRecords      = r.ReadLEUInt32();
 }
示例#3
0
        public BYTVField?XRGD;              // Ragdoll Data (optional)

        public override bool CreateField(UnityBinaryReader r, GameFormatId format, string type, int dataSize)
        {
            switch (type)
            {
            case "EDID": EDID = r.ReadSTRV(dataSize); return(true);

            case "NAME": NAME = new FMIDField <Record>(r, dataSize); return(true);

            case "DATA": DATA = new REFRRecord.DATAField(r, dataSize); return(true);

            case "XPCI": XPCI = new FMIDField <CELLRecord>(r, dataSize); return(true);

            case "FULL": XPCI.Value.AddName(r.ReadASCIIString(dataSize)); return(true);

            case "XLOD": XLOD = r.ReadBYTV(dataSize); return(true);

            case "XESP": XESP = new REFRRecord.XESPField(r, dataSize); return(true);

            case "XMRC": XMRC = new FMIDField <REFRRecord>(r, dataSize); return(true);

            case "XHRS": XHRS = new FMIDField <ACRERecord>(r, dataSize); return(true);

            case "XSCL": XSCL = r.ReadT <FLTVField>(dataSize); return(true);

            case "XRGD": XRGD = r.ReadBYTV(dataSize); return(true);

            default: return(false);
            }
        }
示例#4
0
 public AI_FField(UnityBinaryReader r, int dataSize)
 {
     X        = r.ReadLESingle();
     Y        = r.ReadLESingle();
     Z        = r.ReadLESingle();
     Duration = r.ReadLEInt16();
     Id       = r.ReadASCIIString(32, ASCIIFormat.ZeroPadded);
     Unknown  = r.ReadLEInt16();
 }
示例#5
0
        public FormId <Record> Item;      // The ID of the item

        public CNTOField(UnityBinaryReader r, int dataSize, GameFormatId format)
        {
            if (format == GameFormatId.TES3)
            {
                ItemCount = r.ReadLEUInt32();
                Item      = new FormId <Record>(r.ReadASCIIString(32, ASCIIFormat.ZeroPadded));
                return;
            }
            Item      = new FormId <Record>(r.ReadLEUInt32());
            ItemCount = r.ReadLEUInt32();
        }
示例#6
0
 public SCHDField(UnityBinaryReader r, int dataSize)
 {
     Name           = r.ReadASCIIString(32, ASCIIFormat.ZeroPadded);
     NumShorts      = r.ReadLEInt32();
     NumLongs       = r.ReadLEInt32();
     NumFloats      = r.ReadLEInt32();
     ScriptDataSize = r.ReadLEInt32();
     LocalVarSize   = r.ReadLEInt32();
     // SCVRField
     Variables = null;
 }
示例#7
0
 public EFITField(UnityBinaryReader r, int dataSize, GameFormatId format)
 {
     if (format == GameFormatId.TES3)
     {
         EffectId     = r.ReadASCIIString(2);
         SkillId      = r.ReadByte();
         AttributeId  = r.ReadByte();
         Type         = r.ReadLEInt32();
         Area         = r.ReadLEInt32();
         Duration     = r.ReadLEInt32();
         MagnitudeMin = r.ReadLEInt32();
         MagnitudeMax = r.ReadLEInt32();
         return;
     }
     EffectId     = r.ReadASCIIString(4);
     MagnitudeMin = r.ReadLEInt32();
     Area         = r.ReadLEInt32();
     Duration     = r.ReadLEInt32();
     Type         = r.ReadLEInt32();
     ActorValue   = r.ReadLEInt32();
 }
示例#8
0
 public SCITField(UnityBinaryReader r, int dataSize)
 {
     Name         = "Script Effect";
     ScriptFormId = r.ReadLEInt32();
     if (dataSize == 4)
     {
         return;
     }
     School       = r.ReadLEInt32();
     VisualEffect = r.ReadASCIIString(4);
     Flags        = dataSize > 12 ? r.ReadLEUInt32() : 0;
 }
示例#9
0
 public RDSDField(UnityBinaryReader r, int dataSize, GameFormatId format)
 {
     if (format == GameFormatId.TES3)
     {
         Sound  = new FormId <SOUNRecord>(r.ReadASCIIString(32, ASCIIFormat.ZeroPadded));
         Flags  = 0;
         Chance = r.ReadByte();
         return;
     }
     Sound  = new FormId <SOUNRecord>(r.ReadLEUInt32());
     Flags  = r.ReadLEUInt32();
     Chance = r.ReadLEUInt32(); //: float with TES5
 }
示例#10
0
 public Header(UnityBinaryReader r, GameFormatId format, Header parent)
 {
     Parent = parent;
     Type   = r.ReadASCIIString(4);
     if (Type == "GRUP")
     {
         DataSize  = (uint)(r.ReadLEUInt32() - (format == GameFormatId.TES4 ? 20 : 24));
         Label     = r.ReadBytes(4);
         GroupType = (HeaderGroupType)r.ReadLEInt32();
         r.ReadLEUInt32(); // stamp | stamp + uknown
         if (format != GameFormatId.TES4)
         {
             r.ReadLEUInt32(); // version + uknown
         }
         Position = r.BaseStream.Position;
         return;
     }
     DataSize = r.ReadLEUInt32();
     if (format == GameFormatId.TES3)
     {
         r.ReadLEUInt32(); // Unknown
     }
     Flags = (HeaderFlags)r.ReadLEUInt32();
     if (format == GameFormatId.TES3)
     {
         Position = r.BaseStream.Position;
         return;
     }
     // tes4
     FormId = r.ReadLEUInt32();
     r.ReadLEUInt32();
     if (format == GameFormatId.TES4)
     {
         Position = r.BaseStream.Position;
         return;
     }
     // tes5
     r.ReadLEUInt32();
     Position = r.BaseStream.Position;
 }
示例#11
0
        public static DATVField ReadDATV(this UnityBinaryReader r, int length, char type)
        {
            switch (type)
            {
            case 'b': return(new DATVField {
                    B = r.ReadLEInt32() != 0
                });

            case 'i': return(new DATVField {
                    I = r.ReadLEInt32()
                });

            case 'f': return(new DATVField {
                    F = r.ReadLESingle()
                });

            case 's': return(new DATVField {
                    S = r.ReadASCIIString(length, ASCIIFormat.PossiblyNullTerminated)
                });

            default: throw new InvalidOperationException($"{type}");
            }
        }
示例#12
0
 public AI_AField(UnityBinaryReader r, int dataSize)
 {
     Name    = r.ReadASCIIString(32, ASCIIFormat.ZeroPadded);
     Unknown = r.ReadByte();
 }
示例#13
0
 public void FULLField(UnityBinaryReader r, int dataSize)
 {
     Name = r.ReadASCIIString((int)dataSize, ASCIIFormat.PossiblyNullTerminated);
 }
示例#14
0
 public static FILEField ReadFILE(this UnityBinaryReader r, int length, ASCIIFormat format = ASCIIFormat.PossiblyNullTerminated)
 {
     return(new FILEField {
         Value = r.ReadASCIIString(length, format)
     });
 }
        public override bool CreateField(UnityBinaryReader r, GameFormatId format, string type, int dataSize)
        {
            switch (type)
            {
            case "EDID": EDID = r.ReadSTRV(dataSize); return(true);

            case "NAME": NAME = new FMIDField <Record>(r, dataSize); return(true);

            case "XTEL": XTEL = new XTELField(r, dataSize); return(true);

            case "DATA": DATA = new DATAField(r, dataSize); return(true);

            case "XLOC": XLOC = new XLOCField(r, dataSize); return(true);

            case "XOWN": if (XOWNs == null)
                {
                    XOWNs = new List <CELLRecord.XOWNGroup>();
                }
                XOWNs.Add(new CELLRecord.XOWNGroup {
                    XOWN = new FMIDField <Record>(r, dataSize)
                }); return(true);

            case "XRNK": XOWNs.Last().XRNK = r.ReadT <IN32Field>(dataSize); return(true);

            case "XGLB": XOWNs.Last().XGLB = new FMIDField <Record>(r, dataSize); return(true);

            case "XESP": XESP = new XESPField(r, dataSize); return(true);

            case "XTRG": XTRG = new FMIDField <Record>(r, dataSize); return(true);

            case "XSED": XSED = new XSEDField(r, dataSize); return(true);

            case "XLOD": XLOD = r.ReadBYTV(dataSize); return(true);

            case "XCHG": XCHG = r.ReadT <FLTVField>(dataSize); return(true);

            case "XHLT": XCHG = r.ReadT <FLTVField>(dataSize); return(true);

            case "XPCI": XPCI = new FMIDField <CELLRecord>(r, dataSize); _nextFull = 1; return(true);

            case "FULL":
                if (_nextFull == 1)
                {
                    XPCI.Value.AddName(r.ReadASCIIString(dataSize));
                }
                else if (_nextFull == 2)
                {
                    XMRKs.Last().FULL = r.ReadSTRV(dataSize);
                }
                _nextFull = 0;
                return(true);

            case "XLCM": XLCM = r.ReadT <IN32Field>(dataSize); return(true);

            case "XRTM": XRTM = new FMIDField <REFRRecord>(r, dataSize); return(true);

            case "XACT": XACT = r.ReadT <UI32Field>(dataSize); return(true);

            case "XCNT": XCNT = r.ReadT <IN32Field>(dataSize); return(true);

            case "XMRK": if (XMRKs == null)
                {
                    XMRKs = new List <XMRKGroup>();
                }
                XMRKs.Add(new XMRKGroup()); _nextFull = 2; return(true);

            case "FNAM": XMRKs.Last().FNAM = r.ReadT <BYTEField>(dataSize); return(true);

            case "TNAM": XMRKs.Last().TNAM = r.ReadT <BYTEField>(dataSize); r.ReadByte(); return(true);

            case "ONAM": return(true);

            case "XRGD": XRGD = r.ReadBYTV(dataSize); return(true);

            case "XSCL": XSCL = r.ReadT <FLTVField>(dataSize); return(true);

            case "XSOL": XSOL = r.ReadT <BYTEField>(dataSize); return(true);

            default: return(false);
            }
        }
示例#16
0
 public FMIDField(UnityBinaryReader r, int dataSize)
 {
     Value = dataSize == 4 ?
             new FormId <TRecord>(r.ReadLEUInt32()) :
             new FormId <TRecord>(r.ReadASCIIString(dataSize, ASCIIFormat.ZeroPadded));
 }
示例#17
0
 public void NAM2Field(UnityBinaryReader r, int dataSize)
 {
     ActorNotes = r.ReadASCIIString((int)dataSize, ASCIIFormat.PossiblyNullTerminated);
 }
示例#18
0
 public void NAM1Field(UnityBinaryReader r, int dataSize)
 {
     ResponseText = r.ReadASCIIString((int)dataSize, ASCIIFormat.PossiblyNullTerminated);
 }
示例#19
0
 public MODLGroup(UnityBinaryReader r, int dataSize)
 {
     Value = r.ReadASCIIString((int)dataSize, ASCIIFormat.PossiblyNullTerminated);
 }
示例#20
0
 public FieldHeader(UnityBinaryReader r, GameFormatId format)
 {
     Type     = r.ReadASCIIString(4);
     DataSize = (int)(format == GameFormatId.TES3 ? r.ReadLEUInt32() : r.ReadLEUInt16());
 }
示例#21
0
        void ReadMetadata()
        {
            // Open
            Magic = _r.ReadLEUInt32();
            if (Magic == F4_BSAHEADER_FILEID)
            {
                Version = _r.ReadLEUInt32();
                if (Version != F4_BSAHEADER_VERSION)
                {
                    throw new InvalidOperationException("BAD MAGIC");
                }
                // Read the header
                var header_Type            = _r.ReadASCIIString(4); // 08 GNRL=General, DX10=Textures
                var header_NumFiles        = _r.ReadLEUInt32();     // 0C
                var header_NameTableOffset = _r.ReadLEUInt64();     // 10 - relative to start of file

                // Create file metadatas
                _r.BaseStream.Position = (long)header_NameTableOffset;
                _files = new FileMetadata[header_NumFiles];
                for (var i = 0; i < header_NumFiles; i++)
                {
                    var length = _r.ReadLEUInt16();
                    var path   = _r.ReadASCIIString(length);
                    _files[i] = new FileMetadata
                    {
                        Path     = path,
                        PathHash = Tes4HashFilePath(path),
                    };
                }
                if (header_Type == "GNRL")           // General BA2 Format
                {
                    _r.BaseStream.Position = 16 + 8; // sizeof(header) + 8
                    for (var i = 0; i < header_NumFiles; i++)
                    {
                        var info_NameHash     = _r.ReadLEUInt32();     // 00
                        var info_Ext          = _r.ReadASCIIString(4); // 04 - extension
                        var info_DirHash      = _r.ReadLEUInt32();     // 08
                        var info_Unk0C        = _r.ReadLEUInt32();     // 0C - flags? 00100100
                        var info_Offset       = _r.ReadLEUInt64();     // 10 - relative to start of file
                        var info_PackedSize   = _r.ReadLEUInt32();     // 18 - packed length (zlib)
                        var info_UnpackedSize = _r.ReadLEUInt32();     // 1C - unpacked length
                        var info_Unk20        = _r.ReadLEUInt32();     // 20 - BAADF00D
                        _files[i].PackedSize   = info_PackedSize;
                        _files[i].UnpackedSize = info_UnpackedSize;
                        _files[i].Offset       = (long)info_Offset;
                    }
                }
                else if (header_Type == "DX10")      // Texture BA2 Format
                {
                    _r.BaseStream.Position = 16 + 8; // sizeof(header) + 8
                    for (var i = 0; i < header_NumFiles; i++)
                    {
                        var fileMetadata         = _files[i];
                        var info_NameHash        = _r.ReadLEUInt32();     // 00
                        var info_Ext             = _r.ReadASCIIString(4); // 04
                        var info_DirHash         = _r.ReadLEUInt32();     // 08
                        var info_Unk0C           = _r.ReadByte();         // 0C
                        var info_NumChunks       = _r.ReadByte();         // 0D
                        var info_ChunkHeaderSize = _r.ReadLEUInt16();     // 0E - size of one chunk header
                        var info_Height          = _r.ReadLEUInt16();     // 10
                        var info_Width           = _r.ReadLEUInt16();     // 12
                        var info_NumMips         = _r.ReadByte();         // 14
                        var info_Format          = _r.ReadByte();         // 15 - DXGI_FORMAT
                        var info_Unk16           = _r.ReadLEUInt16();     // 16 - 0800
                        // read tex-chunks
                        var texChunks = new F4TexChunk[info_NumChunks];
                        for (var j = 0; j < info_NumChunks; j++)
                        {
                            texChunks[j] = new F4TexChunk
                            {
                                Offset       = _r.ReadLEUInt64(),   // 00
                                PackedSize   = _r.ReadLEUInt32(),   // 08
                                UnpackedSize = _r.ReadLEUInt32(),   // 0C
                                StartMip     = _r.ReadLEUInt16(),   // 10
                                EndMip       = _r.ReadLEUInt16(),   // 12
                                Unk14        = _r.ReadLEUInt32(),   // 14 - BAADFOOD
                            }
                        }
                        ;
                        var firstChunk = texChunks[0];
                        _files[i].PackedSize   = firstChunk.PackedSize;
                        _files[i].UnpackedSize = firstChunk.UnpackedSize;
                        _files[i].Offset       = (long)firstChunk.Offset;
                        fileMetadata.Tex       = new F4Tex
                        {
                            Height  = info_Height,
                            Width   = info_Width,
                            NumMips = info_NumMips,
                            Format  = (DXGIFormat)info_Format,
                            Unk16   = info_Unk16,
                            Chunks  = texChunks,
                        };
                    }
                }
            }
            else if (Magic == OB_BSAHEADER_FILEID)
            {
                Version = _r.ReadLEUInt32();
                if (Version != OB_BSAHEADER_VERSION && Version != F3_BSAHEADER_VERSION && Version != SSE_BSAHEADER_VERSION)
                {
                    throw new InvalidOperationException("BAD MAGIC");
                }
                // Read the header
                var header_FolderRecordOffset = _r.ReadLEUInt32(); // Offset of beginning of folder records
                var header_ArchiveFlags       = _r.ReadLEUInt32(); // Archive flags
                var header_FolderCount        = _r.ReadLEUInt32(); // Total number of folder records (OBBSAFolderInfo)
                var header_FileCount          = _r.ReadLEUInt32(); // Total number of file records (OBBSAFileInfo)
                var header_FolderNameLength   = _r.ReadLEUInt32(); // Total length of folder names
                var header_FileNameLength     = _r.ReadLEUInt32(); // Total length of file names
                var header_FileFlags          = _r.ReadLEUInt32(); // File flags

                // Calculate some useful values
                if ((header_ArchiveFlags & OB_BSAARCHIVE_PATHNAMES) == 0 || (header_ArchiveFlags & OB_BSAARCHIVE_FILENAMES) == 0)
                {
                    throw new InvalidOperationException("HEADER FLAGS");
                }
                _compressToggle = (header_ArchiveFlags & OB_BSAARCHIVE_COMPRESSFILES) != 0;
                if (Version == F3_BSAHEADER_VERSION || Version == SSE_BSAHEADER_VERSION)
                {
                    _hasNamePrefix = (header_ArchiveFlags & F3_BSAARCHIVE_PREFIXFULLFILENAMES) != 0;
                }
                var folderSize = Version != SSE_BSAHEADER_VERSION ? 16 : 24;

                // Create file metadatas
                _files = new FileMetadata[header_FileCount];
                var filenamesSectionStartPos = _r.BaseStream.Position = header_FolderRecordOffset + header_FolderNameLength + header_FolderCount * (folderSize + 1) + header_FileCount * 16;
                var buf = new List <byte>(64);
                for (var i = 0; i < header_FileCount; i++)
                {
                    buf.Clear();
                    byte curCharAsByte; while ((curCharAsByte = _r.ReadByte()) != 0)
                    {
                        buf.Add(curCharAsByte);
                    }
                    var path = Encoding.ASCII.GetString(buf.ToArray());
                    _files[i] = new FileMetadata
                    {
                        Path = path,
                    };
                }
                if (_r.BaseStream.Position != filenamesSectionStartPos + header_FileNameLength)
                {
                    throw new InvalidOperationException("HEADER FILENAMES");
                }

                // read-all folders
                _r.BaseStream.Position = header_FolderRecordOffset;
                var foldersFiles = new uint[header_FolderCount];
                for (var i = 0; i < header_FolderCount; i++)
                {
                    var folder_Hash = _r.ReadLEUInt64();      // Hash of the folder name
                    var folder_FileCount = _r.ReadLEUInt32(); // Number of files in folder
                    var folder_Unk = 0U; var folder_Offset = 0UL;
                    if (Version == SSE_BSAHEADER_VERSION)
                    {
                        folder_Unk = _r.ReadLEUInt32(); folder_Offset = _r.ReadLEUInt64();
                    }
                    else
                    {
                        folder_Offset = _r.ReadLEUInt32();
                    }
                    foldersFiles[i] = folder_FileCount;
                }

                // add file
                var fileNameIndex = 0U;
                for (var i = 0; i < header_FolderCount; i++)
                {
                    var folder_name = _r.ReadASCIIString(_r.ReadByte(), ASCIIFormat.PossiblyNullTerminated); // BSAReadSizedString
                    var folderFiles = foldersFiles[i];
                    for (var j = 0; j < folderFiles; j++)
                    {
                        var file_Hash      = _r.ReadLEUInt64(); // Hash of the filename
                        var file_SizeFlags = _r.ReadLEUInt32(); // Size of the data, possibly with OB_BSAFILE_FLAG_COMPRESS set
                        var file_Offset    = _r.ReadLEUInt32(); // Offset to raw file data
                        var fileMetadata   = _files[fileNameIndex++];
                        fileMetadata.SizeFlags = file_SizeFlags;
                        fileMetadata.Offset    = file_Offset;
                        var path = folder_name + "\\" + fileMetadata.Path;
                        fileMetadata.Path     = path;
                        fileMetadata.PathHash = Tes4HashFilePath(path);
                    }
                }
            }
            else if (Magic == MW_BSAHEADER_FILEID)
            {
                // Read the header
                var header_HashOffset = _r.ReadLEUInt32(); // Offset of hash table minus header size (12)
                var header_FileCount  = _r.ReadLEUInt32(); // Number of files in the archive

                // Calculate some useful values
                var headerSize             = _r.BaseStream.Position;
                var hashTablePosition      = headerSize + header_HashOffset;
                var fileDataSectionPostion = hashTablePosition + (8 * header_FileCount);

                // Create file metadatas
                _files = new FileMetadata[header_FileCount];
                for (var i = 0; i < header_FileCount; i++)
                {
                    _files[i] = new FileMetadata
                    {
                        // Read file sizes/offsets
                        SizeFlags = _r.ReadLEUInt32(),
                        Offset    = fileDataSectionPostion + _r.ReadLEUInt32(),
                    }
                }
                ;

                // Read filename offsets
                var filenameOffsets = new uint[header_FileCount]; // relative offset in filenames section
                for (var i = 0; i < header_FileCount; i++)
                {
                    filenameOffsets[i] = _r.ReadLEUInt32();
                }

                // Read filenames
                var filenamesSectionStartPos = _r.BaseStream.Position;
                var buf = new List <byte>(64);
                for (var i = 0; i < header_FileCount; i++)
                {
                    _r.BaseStream.Position = filenamesSectionStartPos + filenameOffsets[i];
                    buf.Clear();
                    byte curCharAsByte; while ((curCharAsByte = _r.ReadByte()) != 0)
                    {
                        buf.Add(curCharAsByte);
                    }
                    _files[i].Path = Encoding.ASCII.GetString(buf.ToArray());
                }

                // Read filename hashes
                _r.BaseStream.Position = hashTablePosition;
                for (var i = 0; i < header_FileCount; i++)
                {
                    _files[i].PathHash = _r.ReadLEUInt64();
                }
            }
            else
            {
                throw new InvalidOperationException("BAD MAGIC");
            }

            // Create the file metadata hash table
            _filesByHash = _files.ToLookup(x => x.PathHash);

            // Create a virtual directory tree.
            RootDir = new VirtualFileSystem.Directory();
            foreach (var fileMetadata in _files)
            {
                RootDir.CreateDescendantFile(fileMetadata.Path);
            }
        }

        ulong HashFilePath(string filePath)
        {
            if (Magic == MW_BSAHEADER_FILEID)
            {
                return(Tes3HashFilePath(filePath));
            }
            else
            {
                return(Tes4HashFilePath(filePath));
            }
        }