/// <summary> /// /// </summary> /// <param name="gr"></param> /// <param name="gr2"></param> /// <param name="sb"></param> /// <param name="swe"></param> /// <returns></returns> public static bool ParseInitialSpellsOpcode(GenericReader gr, GenericReader gr2, StringBuilder sb, StreamWriter swe, byte direction) { sb.AppendLine("Packet offset " + gr.BaseStream.Position.ToString("X2")); sb.AppendLine("Opcode SMSG_INITIAL_SPELLS (0x012A)"); byte unk1 = gr2.ReadByte(); sb.AppendLine("unk byte " + unk1); ushort spells_count = gr2.ReadUInt16(); sb.AppendLine("Spells count " + spells_count); for (ushort i = 0; i < spells_count; i++) { ushort spellid = gr2.ReadUInt16(); ushort slotid = gr2.ReadUInt16(); sb.AppendLine("Spell ID " + spellid + ", slot " + slotid.ToString("X2")); } ushort cooldowns_count = gr2.ReadUInt16(); sb.AppendLine("Cooldowns count " + cooldowns_count); for (ushort i = 0; i < cooldowns_count; i++) { ushort spellid = gr2.ReadUInt16(); ushort itemid = gr2.ReadUInt16(); ushort spellcategory = gr2.ReadUInt16(); uint cooldown1 = gr2.ReadUInt32(); uint cooldown2 = gr2.ReadUInt32(); sb.AppendLine("Spell Cooldown: spell id " + spellid + ", itemid " + itemid + ", spellcategory " + spellcategory + ", cooldown1 " + cooldown1 + ", cooldown2 " + cooldown2); } return(true); }
/// <summary> /// Builds a 4-color color table for a DXT1-compressed 4x4 block of texels and then decodes the texels. /// </summary> /// <remarks>See https://msdn.microsoft.com/en-us/library/windows/desktop/bb694531(v=vs.85).aspx#BC1 </remarks> static Color32[] DecodeDXT1TexelBlock(GenericReader r, bool containsAlpha) { // Create the color table. var colorTable = new Color[4]; colorTable[0] = r.ReadUInt16().B565ToColor(); colorTable[1] = r.ReadUInt16().B565ToColor(); if (!containsAlpha) { colorTable[2] = Color.Lerp(colorTable[0], colorTable[1], 1.0f / 3); colorTable[3] = Color.Lerp(colorTable[0], colorTable[1], 2.0f / 3); } else { colorTable[2] = Color.Lerp(colorTable[0], colorTable[1], 1.0f / 2); colorTable[3] = new Color(0, 0, 0, 0); } // Calculate pixel colors. return(DecodeDXT1TexelBlock(r, colorTable)); }
/// <summary> /// Decodes a DXT3-compressed 4x4 block of texels. /// </summary> /// <remarks>See https://msdn.microsoft.com/en-us/library/windows/desktop/bb694531(v=vs.85).aspx#BC2 </remarks> static Color32[] DecodeDXT3TexelBlock(GenericReader r) { // Read compressed pixel alphas. var compressedAlphas = new byte[16]; for (var rowIndex = 0; rowIndex < 4; rowIndex++) { var compressedAlphaRow = r.ReadUInt16(); for (var columnIndex = 0; columnIndex < 4; columnIndex++) { // Each compressed alpha is 4 bits. compressedAlphas[(4 * rowIndex) + columnIndex] = (byte)((compressedAlphaRow >> (columnIndex * 4)) & 0xF); } } // Calculate pixel alphas. var alphas = new byte[16]; for (var i = 0; i < 16; i++) { var alphaPercent = (float)compressedAlphas[i] / 15; alphas[i] = (byte)Mathf.RoundToInt(alphaPercent * 255); } // Create the color table. var colorTable = new Color[4]; colorTable[0] = r.ReadUInt16().B565ToColor(); colorTable[1] = r.ReadUInt16().B565ToColor(); colorTable[2] = Color.Lerp(colorTable[0], colorTable[1], 1.0f / 3); colorTable[3] = Color.Lerp(colorTable[0], colorTable[1], 2.0f / 3); // Calculate pixel colors. var colors = DecodeDXT1TexelBlock(r, colorTable); for (var i = 0; i < 16; i++) { colors[i].a = alphas[i]; } return(colors); }
public readonly uint AnimationTimerRelated; // Animation timer value public SiMaterial(GenericReader r) { TextureId = r.ReadUInt16(); Flags = r.ReadUInt16(); SubtextureCount = r.ReadUInt16(); Flags2 = r.ReadUInt16(); FirstFaceId = r.ReadUInt16(); FaceCount = r.ReadUInt16(); DefaultAlpha = r.ReadByte(); ModifiedAlpha = r.ReadByte(); AnimationStart = r.ReadByte(); AnimationEnd = r.ReadByte(); CurFrame = r.ReadByte(); AnimationSpeed = r.ReadByte(); AnimationType = r.ReadByte(); PlaybackDirection = r.ReadByte(); AnimationTimerRelated = r.ReadUInt32(); }
/// <summary> /// Packet header parser. /// </summary> /// <param name="gr">Main stream reader.</param> /// <param name="sw">Data stream writer.</param> /// <param name="swe">Error logger writer.</param> /// <param name="data">Data logger writer.</param> /// <param name="hex">HEX logger writer.</param> /// <returns>Successful</returns> private static bool ParseHeader(GenericReader gr, StreamWriter sw, StreamWriter swe, StreamWriter data, StreamWriter hex) { StringBuilder sb = new StringBuilder(); int datasize = gr.ReadInt32(); //sb.AppendLine("Packet offset " + (gr.BaseStream.Position - 4).ToString("X2")); //sb.AppendLine("Packet number: " + packet); //sb.AppendLine("Data size " + datasize); byte[] temp = gr.ReadBytes(datasize); MemoryStream ms = new MemoryStream(temp); GenericReader gr2 = new GenericReader(ms); uint id = 0; uint sess_id = 0; string time = ""; byte direction = 0; // 0-CMSG, 1-SMSG OpCodes opcode = OpCodes.MSG_NULL_ACTION; id = gr2.ReadUInt32(); sess_id = gr2.ReadUInt32(); time = gr2.ReadStringNull(); direction = gr2.ReadByte(); opcode = (OpCodes)gr2.ReadUInt16(); long cur_pos = gr2.BaseStream.Position; HexLike(gr2, hex, id, sess_id, time, direction, opcode); gr2.BaseStream.Position = cur_pos; switch (opcode) { /*case OpCodes.SMSG_MONSTER_MOVE: * OpcodeParser.ParseMonsterMoveOpcode(gr, gr2, sb, swe, direction); * break;*/ /*case OpCodes.SMSG_INITIAL_SPELLS: * OpcodeParser.ParseInitialSpellsOpcode(gr, gr2, sb, swe, direction); * break; * case OpCodes.SMSG_AUCTION_LIST_RESULT: * OpcodeParser.ParseAuctionListResultOpcode(gr, gr2, sb, swe, direction); * break;*/ /*case OpCodes.SMSG_PARTY_MEMBER_STATS: * case OpCodes.SMSG_PARTY_MEMBER_STATS_FULL: * OpcodeParser.ParsePartyMemberStatsOpcode(gr, gr2, sb, swe, direction); * break;*/ case OpCodes.SMSG_UPDATE_OBJECT: case OpCodes.SMSG_COMPRESSED_UPDATE_OBJECT: if (opcode == OpCodes.SMSG_COMPRESSED_UPDATE_OBJECT) { gr2 = A9.Decompress(gr2); gr2.BaseStream.Position = 0; hex.WriteLine("Decompressed SMSG_COMPRESSED_UPDATE_OBJECT:"); HexLike(gr2, hex, id, sess_id, time, direction, OpCodes.SMSG_UPDATE_OBJECT); gr2.BaseStream.Position = 0; } A9.ParseUpdatePacket(gr, gr2, sb, swe); break; /*case OpCodes.SMSG_SPELLNONMELEEDAMAGELOG: * OpcodeParser.ParseSpellNonMeleeDamageLogOpcode(gr, gr2, sb, swe, direction); * break; * case OpCodes.SMSG_SPELLLOGEXECUTE: * OpcodeParser.ParseSpellLogExecuteOpcode(gr, gr2, sb, swe, direction); * break;*/ /*case OpCodes.SMSG_LOGIN_SETTIMESPEED: * OpcodeParser.ParseLoginSetTimeSpeedOpcode(gr, gr2, sb, swe, direction); * break; * case OpCodes.SMSG_TRAINER_LIST: * OpcodeParser.ParseTrainerListOpcode(gr, gr2, sb, swe, direction); * break; * case OpCodes.SMSG_ATTACKERSTATEUPDATE: * OpcodeParser.ParseAttackerStateUpdateOpcode(gr, gr2, sb, swe, direction); * break; * case OpCodes.MSG_CORPSE_QUERY: * OpcodeParser.ParseCorpseQueryOpcode(gr, gr2, sb, swe, direction); * break; * case OpCodes.SMSG_LOGIN_VERIFY_WORLD: * OpcodeParser.ParseLoginVerifyWorldOpcode(gr, gr2, sb, swe, direction); * break; * default: // unhandled opcode * return false;*/ } if (sb.ToString().Length != 0) { sw.WriteLine(sb.ToString()); } ms.Close(); gr2.Close(); return(true); }
/// <summary> /// Decodes a DXT5-compressed 4x4 block of texels. /// </summary> /// <remarks>See https://msdn.microsoft.com/en-us/library/windows/desktop/bb694531(v=vs.85).aspx#BC3 </remarks> static Color32[] DecodeDXT5TexelBlock(GenericReader r) { // Create the alpha table. var alphaTable = new float[8]; alphaTable[0] = r.ReadByte(); alphaTable[1] = r.ReadByte(); if (alphaTable[0] > alphaTable[1]) { for (var i = 0; i < 6; i++) { alphaTable[2 + i] = Mathf.Lerp(alphaTable[0], alphaTable[1], (float)(1 + i) / 7); } } else { for (var i = 0; i < 4; i++) { alphaTable[2 + i] = Mathf.Lerp(alphaTable[0], alphaTable[1], (float)(1 + i) / 5); } alphaTable[6] = 0; alphaTable[7] = 255; } // Read pixel alpha indices. var alphaIndices = new uint[16]; var alphaIndexBytesRow0 = new byte[3]; r.Read(alphaIndexBytesRow0, 0, alphaIndexBytesRow0.Length); Array.Reverse(alphaIndexBytesRow0); // Take care of little-endianness. var alphaIndexBytesRow1 = new byte[3]; r.Read(alphaIndexBytesRow1, 0, alphaIndexBytesRow1.Length); Array.Reverse(alphaIndexBytesRow1); // Take care of little-endianness. const uint bitsPerAlphaIndex = 3U; alphaIndices[0] = (uint)Utils.GetBits(21, bitsPerAlphaIndex, alphaIndexBytesRow0); alphaIndices[1] = (uint)Utils.GetBits(18, bitsPerAlphaIndex, alphaIndexBytesRow0); alphaIndices[2] = (uint)Utils.GetBits(15, bitsPerAlphaIndex, alphaIndexBytesRow0); alphaIndices[3] = (uint)Utils.GetBits(12, bitsPerAlphaIndex, alphaIndexBytesRow0); alphaIndices[4] = (uint)Utils.GetBits(9, bitsPerAlphaIndex, alphaIndexBytesRow0); alphaIndices[5] = (uint)Utils.GetBits(6, bitsPerAlphaIndex, alphaIndexBytesRow0); alphaIndices[6] = (uint)Utils.GetBits(3, bitsPerAlphaIndex, alphaIndexBytesRow0); alphaIndices[7] = (uint)Utils.GetBits(0, bitsPerAlphaIndex, alphaIndexBytesRow0); alphaIndices[8] = (uint)Utils.GetBits(21, bitsPerAlphaIndex, alphaIndexBytesRow1); alphaIndices[9] = (uint)Utils.GetBits(18, bitsPerAlphaIndex, alphaIndexBytesRow1); alphaIndices[10] = (uint)Utils.GetBits(15, bitsPerAlphaIndex, alphaIndexBytesRow1); alphaIndices[11] = (uint)Utils.GetBits(12, bitsPerAlphaIndex, alphaIndexBytesRow1); alphaIndices[12] = (uint)Utils.GetBits(9, bitsPerAlphaIndex, alphaIndexBytesRow1); alphaIndices[13] = (uint)Utils.GetBits(6, bitsPerAlphaIndex, alphaIndexBytesRow1); alphaIndices[14] = (uint)Utils.GetBits(3, bitsPerAlphaIndex, alphaIndexBytesRow1); alphaIndices[15] = (uint)Utils.GetBits(0, bitsPerAlphaIndex, alphaIndexBytesRow1); // Create the color table. var colorTable = new Color[4]; colorTable[0] = r.ReadUInt16().B565ToColor(); colorTable[1] = r.ReadUInt16().B565ToColor(); colorTable[2] = Color.Lerp(colorTable[0], colorTable[1], 1.0f / 3); colorTable[3] = Color.Lerp(colorTable[0], colorTable[1], 2.0f / 3); // Calculate pixel colors. var colors = DecodeDXT1TexelBlock(r, colorTable); for (var i = 0; i < 16; i++) { colors[i].a = (byte)Mathf.Round(alphaTable[alphaIndices[i]]); } return(colors); }
/// <summary> /// /// </summary> /// <param name="gr"></param> /// <param name="gr2"></param> /// <param name="sb"></param> /// <param name="swe"></param> /// <returns></returns> public static bool ParsePartyMemberStatsOpcode(GenericReader gr, GenericReader gr2, StringBuilder sb, StreamWriter swe, byte direction) { sb.AppendLine("Packet offset " + gr.BaseStream.Position.ToString("X2")); sb.AppendLine("Opcode SMSG_PARTY_MEMBER_STATS (0x007E)"); byte MAX_AURAS = 56; ulong guid = gr2.ReadPackedGuid(); sb.AppendLine("GUID " + guid.ToString("X16")); GroupUpdateFlags flags = (GroupUpdateFlags)gr2.ReadUInt32(); sb.AppendLine("Flags " + flags); if ((flags & GroupUpdateFlags.GROUP_UPDATE_FLAG_ONLINE) != 0) { GroupMemberOnlineStatus online = (GroupMemberOnlineStatus)gr2.ReadUInt16(); // flag sb.AppendLine("Online state " + online); } if ((flags & GroupUpdateFlags.GROUP_UPDATE_FLAG_CUR_HP) != 0) { ushort hp = gr2.ReadUInt16(); sb.AppendLine("Cur. health " + hp); } if ((flags & GroupUpdateFlags.GROUP_UPDATE_FLAG_MAX_HP) != 0) { ushort maxhp = gr2.ReadUInt16(); sb.AppendLine("Max health " + maxhp); } if ((flags & GroupUpdateFlags.GROUP_UPDATE_FLAG_POWER_TYPE) != 0) { Powers power = (Powers)gr2.ReadByte(); sb.AppendLine("Power type " + power); } if ((flags & GroupUpdateFlags.GROUP_UPDATE_FLAG_CUR_POWER) != 0) { ushort curpower = gr2.ReadUInt16(); sb.AppendLine("Cur. power " + curpower); } if ((flags & GroupUpdateFlags.GROUP_UPDATE_FLAG_MAX_POWER) != 0) { ushort maxpower = gr2.ReadUInt16(); sb.AppendLine("Max power " + maxpower); } if ((flags & GroupUpdateFlags.GROUP_UPDATE_FLAG_LEVEL) != 0) { ushort level = gr2.ReadUInt16(); sb.AppendLine("Level " + level); } if ((flags & GroupUpdateFlags.GROUP_UPDATE_FLAG_ZONE) != 0) { ushort zone = gr2.ReadUInt16(); sb.AppendLine("Zone " + zone); } if ((flags & GroupUpdateFlags.GROUP_UPDATE_FLAG_POSITION) != 0) { short x = gr2.ReadInt16(); short y = gr2.ReadInt16(); sb.AppendLine("Position: " + x + ", " + y); } if ((flags & GroupUpdateFlags.GROUP_UPDATE_FLAG_AURAS) != 0) { ulong mask = gr2.ReadUInt64(); sb.AppendLine("Auras mask " + mask.ToString("X16")); BitArray bitArr = new BitArray(BitConverter.GetBytes(mask)); for (int i = 0; i < bitArr.Length; i++) { if (i >= MAX_AURAS) // we can have only 56 auras { break; } if (bitArr[i]) { ushort spellid = gr2.ReadUInt16(); sb.AppendLine("Aura " + i.ToString() + ": " + spellid.ToString()); byte unk = gr2.ReadByte(); sb.AppendLine("Aura unk " + i.ToString() + ": " + unk.ToString()); } } } if ((flags & GroupUpdateFlags.GROUP_UPDATE_FLAG_PET_GUID) != 0) { ulong petguid = gr2.ReadUInt64(); sb.AppendLine("Pet guid " + petguid.ToString("X16")); } if ((flags & GroupUpdateFlags.GROUP_UPDATE_FLAG_PET_NAME) != 0) { string name = gr2.ReadStringNull(); sb.AppendLine("Pet name " + name); } if ((flags & GroupUpdateFlags.GROUP_UPDATE_FLAG_PET_MODEL_ID) != 0) { ushort modelid = gr2.ReadUInt16(); sb.AppendLine("Pet model id " + modelid); } if ((flags & GroupUpdateFlags.GROUP_UPDATE_FLAG_PET_CUR_HP) != 0) { ushort pethp = gr2.ReadUInt16(); sb.AppendLine("Pet cur. HP " + pethp); } if ((flags & GroupUpdateFlags.GROUP_UPDATE_FLAG_PET_MAX_HP) != 0) { ushort petmaxhp = gr2.ReadUInt16(); sb.AppendLine("Pet max HP " + petmaxhp); } if ((flags & GroupUpdateFlags.GROUP_UPDATE_FLAG_PET_POWER_TYPE) != 0) { Powers power = (Powers)gr2.ReadByte(); sb.AppendLine("Pet power type " + power); } if ((flags & GroupUpdateFlags.GROUP_UPDATE_FLAG_PET_CUR_POWER) != 0) { ushort petpower = gr2.ReadUInt16(); sb.AppendLine("Pet cur. power " + petpower); } if ((flags & GroupUpdateFlags.GROUP_UPDATE_FLAG_PET_MAX_POWER) != 0) { ushort petmaxpower = gr2.ReadUInt16(); sb.AppendLine("Pet max power " + petmaxpower); } if ((flags & GroupUpdateFlags.GROUP_UPDATE_FLAG_PET_AURAS) != 0) { ulong mask = gr2.ReadUInt64(); sb.AppendLine("Pet auras mask " + mask.ToString("X16")); BitArray bitArr = new BitArray(BitConverter.GetBytes(mask)); for (int i = 0; i < bitArr.Length; i++) { if (i >= MAX_AURAS) // we can have only 56 auras { break; } if (bitArr[i]) { ushort spellid = gr2.ReadUInt16(); sb.AppendLine("Pet aura " + i.ToString() + ": " + spellid.ToString()); byte unk = gr2.ReadByte(); sb.AppendLine("Pet aura unk " + i.ToString() + ": " + unk.ToString()); } i++; } } if (gr2.BaseStream.Position == gr2.BaseStream.Length) { sb.AppendLine("parsed: ok..."); } else { sb.AppendLine("parsed: error..."); } return(true); }
void ReadMetadata() { // Open Magic = _r.ReadUInt32(); if (Magic == F4_BSAHEADER_FILEID) { Version = _r.ReadUInt32(); 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.ReadUInt32(); // 0C var header_NameTableOffset = _r.ReadUInt64(); // 10 - relative to start of file // Create file metadatas _r.Position = (long)header_NameTableOffset; _files = new FileMetadata[header_NumFiles]; for (var i = 0; i < header_NumFiles; i++) { var length = _r.ReadUInt16(); var path = _r.ReadASCIIString(length).Replace('\\', '/'); _files[i] = new FileMetadata { Path = path, PathHash = Tes4HashFilePath(path), }; } if (header_Type == "GNRL") // General BA2 Format { _r.Position = 16 + 8; // sizeof(header) + 8 for (var i = 0; i < header_NumFiles; i++) { var info_NameHash = _r.ReadUInt32(); // 00 var info_Ext = _r.ReadASCIIString(4); // 04 - extension var info_DirHash = _r.ReadUInt32(); // 08 var info_Unk0C = _r.ReadUInt32(); // 0C - flags? 00100100 var info_Offset = _r.ReadUInt64(); // 10 - relative to start of file var info_PackedSize = _r.ReadUInt32(); // 18 - packed length (zlib) var info_UnpackedSize = _r.ReadUInt32(); // 1C - unpacked length var info_Unk20 = _r.ReadUInt32(); // 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.Position = 16 + 8; // sizeof(header) + 8 for (var i = 0; i < header_NumFiles; i++) { var fileMetadata = _files[i]; var info_NameHash = _r.ReadUInt32(); // 00 var info_Ext = _r.ReadASCIIString(4); // 04 var info_DirHash = _r.ReadUInt32(); // 08 var info_Unk0C = _r.ReadByte(); // 0C var info_NumChunks = _r.ReadByte(); // 0D var info_ChunkHeaderSize = _r.ReadUInt16(); // 0E - size of one chunk header var info_Height = _r.ReadUInt16(); // 10 var info_Width = _r.ReadUInt16(); // 12 var info_NumMips = _r.ReadByte(); // 14 var info_Format = _r.ReadByte(); // 15 - DXGI_FORMAT var info_Unk16 = _r.ReadUInt16(); // 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.ReadUInt64(), // 00 PackedSize = _r.ReadUInt32(), // 08 UnpackedSize = _r.ReadUInt32(), // 0C StartMip = _r.ReadUInt16(), // 10 EndMip = _r.ReadUInt16(), // 12 Unk14 = _r.ReadUInt32(), // 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.ReadUInt32(); 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.ReadUInt32(); // Offset of beginning of folder records var header_ArchiveFlags = _r.ReadUInt32(); // Archive flags var header_FolderCount = _r.ReadUInt32(); // Total number of folder records (OBBSAFolderInfo) var header_FileCount = _r.ReadUInt32(); // Total number of file records (OBBSAFileInfo) var header_FolderNameLength = _r.ReadUInt32(); // Total length of folder names var header_FileNameLength = _r.ReadUInt32(); // Total length of file names var header_FileFlags = _r.ReadUInt32(); // 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.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()).Replace('\\', '/'); _files[i] = new FileMetadata { Path = path, }; } if (_r.Position != filenamesSectionStartPos + header_FileNameLength) { throw new InvalidOperationException("HEADER FILENAMES"); } // read-all folders _r.Position = header_FolderRecordOffset; var foldersFiles = new uint[header_FolderCount]; for (var i = 0; i < header_FolderCount; i++) { var folder_Hash = _r.ReadUInt64(); // Hash of the folder name var folder_FileCount = _r.ReadUInt32(); // Number of files in folder var folder_Unk = 0U; var folder_Offset = 0UL; if (Version == SSE_BSAHEADER_VERSION) { folder_Unk = _r.ReadUInt32(); folder_Offset = _r.ReadUInt64(); } else { folder_Offset = _r.ReadUInt32(); } 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).Replace('\\', '/'); // BSAReadSizedString var folderFiles = foldersFiles[i]; for (var j = 0; j < folderFiles; j++) { var file_Hash = _r.ReadUInt64(); // Hash of the filename var file_SizeFlags = _r.ReadUInt32(); // Size of the data, possibly with OB_BSAFILE_FLAG_COMPRESS set var file_Offset = _r.ReadUInt32(); // Offset to raw file data var fileMetadata = _files[fileNameIndex++]; fileMetadata.SizeFlags = file_SizeFlags; fileMetadata.Offset = file_Offset; fileMetadata.Path = folder_name + "/" + fileMetadata.Path; fileMetadata.PathHash = Tes4HashFilePath(fileMetadata.Path); } } } else if (Magic == MW_BSAHEADER_FILEID) { // Read the header var header_HashOffset = _r.ReadUInt32(); // Offset of hash table minus header size (12) var header_FileCount = _r.ReadUInt32(); // Number of files in the archive // Calculate some useful values var headerSize = _r.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.ReadUInt32(), Offset = fileDataSectionPostion + _r.ReadUInt32(), } } ; // 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.ReadUInt32(); } // Read filenames var filenamesSectionStartPos = _r.Position; var buf = new List <byte>(64); for (var i = 0; i < header_FileCount; i++) { _r.Position = filenamesSectionStartPos + filenameOffsets[i]; buf.Clear(); byte curCharAsByte; while ((curCharAsByte = _r.ReadByte()) != 0) { buf.Add(curCharAsByte); } _files[i].Path = Encoding.ASCII.GetString(buf.ToArray()).Replace('\\', '/'); } // Read filename hashes _r.Position = hashTablePosition; for (var i = 0; i < header_FileCount; i++) { //_files[i].PathHash = _r.ReadUInt64(); _files[i].PathHash = Tes3HashFilePath(_files[i].Path); } } else { throw new InvalidOperationException("BAD MAGIC"); } // Create the file metadata hash table _filesByHash = _files.ToLookup(x => x.PathHash); } ulong HashFilePath(string filePath) { if (Magic == MW_BSAHEADER_FILEID) { return(Tes3HashFilePath(filePath)); } else { return(Tes4HashFilePath(filePath)); } }
private static void ReadAndDumpField(UpdateField uf, StringBuilder sb, GenericReader gr, UpdateTypes updatetype, StreamWriter data, WoWObject obj) { MemoryStream ms = new MemoryStream(gr.ReadBytes(4)); GenericReader gr2 = new GenericReader(ms); if (updatetype == UpdateTypes.UPDATETYPE_CREATE_OBJECT || updatetype == UpdateTypes.UPDATETYPE_CREATE_OBJECT2) { obj.SetUInt32Value(uf.Identifier, gr2.ReadUInt32()); gr2.BaseStream.Position -= 4; } switch (uf.Type) { // TODO: add data writing /*case 3: * string val1 = gr.ReadSingle().ToString().Replace(",", "."); * if (updatetype == UpdateTypes.UPDATETYPE_CREATE_OBJECT || updatetype == UpdateTypes.UPDATETYPE_CREATE_OBJECT2) * data.WriteLine(uf.Name + " (" + uf.Identifier + "): " + val1); * sb.AppendLine(uf.Name + " (" + index + "): " + val1); * break; * default: * uint val2 = gr.ReadUInt32(); * if (updatetype == UpdateTypes.UPDATETYPE_CREATE_OBJECT || updatetype == UpdateTypes.UPDATETYPE_CREATE_OBJECT2) * data.WriteLine(uf.Name + " (" + uf.Identifier + "): " + val2); * sb.AppendLine(uf.Name + " (" + uf.Identifier + "): " + val2); * break;*/ case 1: // uint32 sb.AppendLine(uf.Name + " (" + uf.Identifier + "): " + gr2.ReadUInt32().ToString("X8")); break; case 2: // uint16+uint16 ushort value1 = gr2.ReadUInt16(); ushort value2 = gr2.ReadUInt16(); sb.AppendLine(uf.Name + " (" + uf.Identifier + "): " + "first " + value1.ToString("X4") + ", second " + value2.ToString("X4")); if (uf.Name.StartsWith("PLAYER_SKILL_INFO_1_")) { int num = uf.Identifier - 858; if ((num % 3) == 0) { ushort skill = value1; ushort flag = value2; string str = String.Format("skill {0}, flag {1}", skill, (ProfessionFlags)flag); sb.AppendLine(str); } else if (((num - 1) % 3) == 0) { ushort minskill = value1; ushort maxskill = value2; string str = String.Format("minskill {0}, maxskill {1}", minskill, maxskill); sb.AppendLine(str); } else { ushort minbonus = value1; ushort maxbonus = value2; string str = String.Format("minbonus {0}, maxbonus {1}", minbonus, maxbonus); sb.AppendLine(str); } } break; case 3: // float sb.AppendLine(uf.Name + " (" + uf.Identifier + "): " + gr2.ReadSingle()); //sb.AppendLine(uf.Name + " (" + uf.Identifier + "): " + gr.ReadSingle().ToString().Replace(",", ".")); break; case 4: // uint64 (can be only low part) sb.AppendLine(uf.Name + " (" + uf.Identifier + "): " + gr2.ReadUInt32().ToString("X8")); break; case 5: // bytes uint value = gr2.ReadUInt32(); sb.AppendLine(uf.Name + " (" + uf.Identifier + "): " + value.ToString("X8")); if (uf.Identifier == 36) // UNIT_FIELD_BYTES_0 { byte[] bytes = BitConverter.GetBytes(value); Races race = (Races)bytes[0]; Class class_ = (Class)bytes[1]; Gender gender = (Gender)bytes[2]; Powers powertype = (Powers)bytes[3]; string str = String.Format("Race: {0}, class: {1}, gender: {2}, powertype: {3}", race, class_, gender, powertype); sb.AppendLine(str); } break; default: sb.AppendLine(uf.Name + " (" + uf.Identifier + "): " + "unknown type " + gr2.ReadUInt32().ToString("X8")); break; } gr2.Close(); }
private uint ParsePacket(GenericReader gr, StreamWriter sw, StreamWriter swe, StreamWriter data) { StringBuilder sb = new StringBuilder(); //MessageBox.Show(br.BaseStream.Position.ToString() + " " + br.BaseStream.Length.ToString()); uint opcode = gr.ReadUInt16(); if (opcode != 0x00A9) { return 2; } sb.AppendLine("Packet offset " + (gr.BaseStream.Position - 2).ToString("X2")); sb.AppendLine("Packet number: " + packet); sb.AppendLine("Opcode: " + opcode.ToString("X4")); uint count = gr.ReadUInt32(); sb.AppendLine("Object count: " + count); uint unk = gr.ReadByte(); sb.AppendLine("Unk: " + unk); for (uint i = 1; i < count+1; i++) { sb.AppendLine("Update block for object " + i + ":"); sb.AppendLine("Block offset " + gr.BaseStream.Position.ToString("X2")); if (!ParseBlock(gr, sb, swe, data)) { sw.WriteLine(sb.ToString()); return 1; } } sw.WriteLine(sb.ToString()); return 0; }