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; }
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(); }
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); } }
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(); }
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(); }
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; }
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(); }
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; }
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 }
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; }
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}"); } }
public AI_AField(UnityBinaryReader r, int dataSize) { Name = r.ReadASCIIString(32, ASCIIFormat.ZeroPadded); Unknown = r.ReadByte(); }
public void FULLField(UnityBinaryReader r, int dataSize) { Name = r.ReadASCIIString((int)dataSize, ASCIIFormat.PossiblyNullTerminated); }
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); } }
public FMIDField(UnityBinaryReader r, int dataSize) { Value = dataSize == 4 ? new FormId <TRecord>(r.ReadLEUInt32()) : new FormId <TRecord>(r.ReadASCIIString(dataSize, ASCIIFormat.ZeroPadded)); }
public void NAM2Field(UnityBinaryReader r, int dataSize) { ActorNotes = r.ReadASCIIString((int)dataSize, ASCIIFormat.PossiblyNullTerminated); }
public void NAM1Field(UnityBinaryReader r, int dataSize) { ResponseText = r.ReadASCIIString((int)dataSize, ASCIIFormat.PossiblyNullTerminated); }
public MODLGroup(UnityBinaryReader r, int dataSize) { Value = r.ReadASCIIString((int)dataSize, ASCIIFormat.PossiblyNullTerminated); }
public FieldHeader(UnityBinaryReader r, GameFormatId format) { Type = r.ReadASCIIString(4); DataSize = (int)(format == GameFormatId.TES3 ? r.ReadLEUInt32() : r.ReadLEUInt16()); }
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)); } }