From f19f94f45953a562b586261bea9ddb7ad1ad9e37 Mon Sep 17 00:00:00 2001 From: Chev <11602755+chev2@users.noreply.github.com> Date: Sat, 16 Jan 2021 22:49:36 -0800 Subject: [PATCH] Update TSCB methods FromBytes replaces ReadFile & uses a byte array instead of filename. GetBytes is renamed to ToBytes. --- botw-toolset/Control/TabTSCB.xaml.cs | 4 +- botw-toolset/IO/TSCB/TSCB.cs | 267 +++++++++++++-------------- 2 files changed, 132 insertions(+), 139 deletions(-) diff --git a/botw-toolset/Control/TabTSCB.xaml.cs b/botw-toolset/Control/TabTSCB.xaml.cs index 9ce25fd..18b9450 100644 --- a/botw-toolset/Control/TabTSCB.xaml.cs +++ b/botw-toolset/Control/TabTSCB.xaml.cs @@ -306,7 +306,7 @@ namespace BOTWToolset.Control BOTWConsole.Log("Opening file"); - TSCB t = TSCB.ReadFile(openFileDialog.FileName); + TSCB t = TSCB.FromBytes(File.ReadAllBytes(openFileDialog.FileName)); // Set the current file location to the chosen file's location fileLocation = openFileDialog.FileName; @@ -365,7 +365,7 @@ namespace BOTWToolset.Control if ((bool)saveFileDialog.ShowDialog()) { - File.WriteAllBytes(saveFileDialog.FileName, TSCB.GetBytes(currentTSCB)); + File.WriteAllBytes(saveFileDialog.FileName, TSCB.ToBytes(currentTSCB)); } } diff --git a/botw-toolset/IO/TSCB/TSCB.cs b/botw-toolset/IO/TSCB/TSCB.cs index 5a9674e..18a36a9 100644 --- a/botw-toolset/IO/TSCB/TSCB.cs +++ b/botw-toolset/IO/TSCB/TSCB.cs @@ -52,168 +52,161 @@ namespace BOTWToolset.IO.TSCB /// /// The .tscb file. /// - public static TSCB ReadFile(string file) + public static TSCB FromBytes(byte[] bytes) { - if (File.Exists(file)) + TSCB t = new TSCB(); + + // Use big-endian + using (var r = new BinaryReaderBig(new MemoryStream(bytes))) { - TSCB t = new TSCB(); + // Set header info from file on the new TSCBInfo + t.Signature = new string(r.ReadChars(4)); + t.Version = r.ReadByte(); - // Use big-endian - using (var r = new BinaryReaderBig(File.Open(file, FileMode.Open))) + // Skip the 3 extra version bytes + r.BaseStream.Seek(3, SeekOrigin.Current); + + // Skip 4 bytes of "00 00 00 01" + r.BaseStream.Seek(4, SeekOrigin.Current); + + t.FileBaseOffset = r.ReadUInt32(); + t.WorldScale = r.ReadSingle(); + t.TerrainMaxHeight = r.ReadSingle(); + t.MaterialInfoLength = r.ReadUInt32(); + t.AreaArrayLength = r.ReadUInt32(); + + // Skip 8 bytes of padding + r.Advance(8); + + t.TileSize = r.ReadSingle(); + + // Skip 4 bytes of "00 00 00 08" + r.Advance(4); + + // Read mat info offsets + t.MaterialInfoOffsets = r.ReadBytes((int)((t.MaterialInfoLength * 4) + 4)); + + BOTWConsole.Log($"Offset before material iteration: {r.BaseStream.Position}"); + + // Initialize mat info array with provided length + t.MaterialInfo = new MaterialInfo[t.MaterialInfoLength]; + + // Initialize every mat info, then add to the array + for (int i = 0; i < t.MaterialInfoLength; i++) { - // Set header info from file on the new TSCBInfo - t.Signature = new string(r.ReadChars(4)); - t.Version = r.ReadByte(); + uint index = r.ReadUInt32(); + float tex_u = r.ReadSingle(); + float tex_v = r.ReadSingle(); + float unk_1 = r.ReadSingle(); + float unk_2 = r.ReadSingle(); - // Skip the 3 extra version bytes - r.BaseStream.Seek(3, SeekOrigin.Current); + MaterialInfo matInfo = new MaterialInfo(index, tex_u, tex_v, unk_1, unk_2); - // Skip 4 bytes of "00 00 00 01" - r.BaseStream.Seek(4, SeekOrigin.Current); + t.MaterialInfo[i] = matInfo; + } - t.FileBaseOffset = r.ReadUInt32(); - t.WorldScale = r.ReadSingle(); - t.TerrainMaxHeight = r.ReadSingle(); - t.MaterialInfoLength = r.ReadUInt32(); - t.AreaArrayLength = r.ReadUInt32(); + BOTWConsole.Log($"Offset before area offset iteration: {r.BaseStream.Position}"); - // Skip 8 bytes of padding - r.Advance(8); + // Read area offsets + t.AreaArrayOffsets = r.ReadBytes((int)(t.AreaArrayLength * 4)); - t.TileSize = r.ReadSingle(); + BOTWConsole.Log($"Offset before area iteration: {r.BaseStream.Position}"); - // Skip 4 bytes of "00 00 00 08" - r.Advance(4); + t.AreaInfo = new AreaInfo[t.AreaArrayLength]; - // Read mat info offsets - t.MaterialInfoOffsets = r.ReadBytes((int)((t.MaterialInfoLength * 4) + 4)); + // Read every area info entry + for (int i = 0; i < t.AreaArrayLength; i++) + { + uint offset = (uint)r.BaseStream.Position; - BOTWConsole.Log($"Offset before material iteration: {r.BaseStream.Position}"); + float xpos = r.ReadSingle(); + float zpos = r.ReadSingle(); + float area_size = r.ReadSingle(); + float min_terrain_height = r.ReadSingle(); + float max_terrain_height = r.ReadSingle(); + float min_water_height = r.ReadSingle(); + float max_water_height = r.ReadSingle(); + uint unk_1 = r.ReadUInt32(); - // Initialize mat info array with provided length - t.MaterialInfo = new MaterialInfo[t.MaterialInfoLength]; + if (unk_1 == 0) + { // If this unknown is equal to 0, skip the extra byte coming after it + uint next_val = r.ReadUInt32(); - // Initialize every mat info, then add to the array - for (int i = 0; i < t.MaterialInfoLength; i++) - { - uint index = r.ReadUInt32(); - float tex_u = r.ReadSingle(); - float tex_v = r.ReadSingle(); - float unk_1 = r.ReadSingle(); - float unk_2 = r.ReadSingle(); - - MaterialInfo matInfo = new MaterialInfo(index, tex_u, tex_v, unk_1, unk_2); - - t.MaterialInfo[i] = matInfo; - } - - BOTWConsole.Log($"Offset before area offset iteration: {r.BaseStream.Position}"); - - // Read area offsets - t.AreaArrayOffsets = r.ReadBytes((int)(t.AreaArrayLength * 4)); - - BOTWConsole.Log($"Offset before area iteration: {r.BaseStream.Position}"); - - t.AreaInfo = new AreaInfo[t.AreaArrayLength]; - - // Read every area info entry - for (int i = 0; i < t.AreaArrayLength; i++) - { - uint offset = (uint)r.BaseStream.Position; - - float xpos = r.ReadSingle(); - float zpos = r.ReadSingle(); - float area_size = r.ReadSingle(); - float min_terrain_height = r.ReadSingle(); - float max_terrain_height = r.ReadSingle(); - float min_water_height = r.ReadSingle(); - float max_water_height = r.ReadSingle(); - uint unk_1 = r.ReadUInt32(); - - if (unk_1 == 0) - { // If this unknown is equal to 0, skip the extra byte coming after it - uint next_val = r.ReadUInt32(); - - if (next_val != 1) // If the next value isn't extra unneeded info - { - r.Advance(-4); - } - } - - uint file_base = r.ReadUInt32(); - uint unk_2 = r.ReadUInt32(); - uint unk_3 = r.ReadUInt32(); - uint ref_extra = r.ReadUInt32(); - - AreaInfo areaInfo = new AreaInfo - { - PositionX = xpos, - PositionZ = zpos, - AreaSize = area_size, - MinTerrainHeight = min_terrain_height, - MaxTerrainHeight = max_terrain_height, - MinWaterHeight = min_water_height, - MaxWaterHeight = max_water_height, - Unknown1 = unk_1, - FileBase = file_base, - Unknown2 = unk_2, - Unknown3 = unk_3, - ReferenceExtra = ref_extra, - Offset = offset - }; - - areaInfo.ExtraInfoLength = r.ReadUInt32(); //Usually 0, 4, or 8 - - if (ref_extra == 4) - { - if (areaInfo.ExtraInfoLength == 8) - { //Skip the extra "20" after the 8, as well as the extra info - areaInfo.HasGrass = true; - areaInfo.HasWater = true; - r.Advance(36); - } - else //If the length is 4 - { - var bytes = r.ReadBytes(16).ToArray(); - if (bytes[7] == 0) //If byte 7 equals 0 - areaInfo.HasGrass = true; - else //Else if the 2nd byte should be anything else (should always be 1) - areaInfo.HasWater = true; - } - } - else //If the extra info flags aren't set, go back 4 + if (next_val != 1) // If the next value isn't extra unneeded info { r.Advance(-4); } - - t.AreaInfo[i] = areaInfo; } - BOTWConsole.Log($"Offset after area iteration: {r.BaseStream.Position} (should be {t.FileBaseOffset + 16})"); + uint file_base = r.ReadUInt32(); + uint unk_2 = r.ReadUInt32(); + uint unk_3 = r.ReadUInt32(); + uint ref_extra = r.ReadUInt32(); - //Get the number of filenames by getting how many bytes they take up out of the entire file size - var filenames_count = (r.BaseStream.Length - (t.FileBaseOffset + 16)) / 12; - - BOTWConsole.Log($"Filename count: {filenames_count} (should be {t.AreaArrayLength})"); - - t.FileNames = new string[filenames_count]; - - r.BaseStream.Seek(t.FileBaseOffset + 16, SeekOrigin.Begin); // TODO: change this to 'current' later, or maybe even remove - - for (int i = 0; i < filenames_count; i++) + AreaInfo areaInfo = new AreaInfo { - string filename = new string(r.ReadChars(12)); + PositionX = xpos, + PositionZ = zpos, + AreaSize = area_size, + MinTerrainHeight = min_terrain_height, + MaxTerrainHeight = max_terrain_height, + MinWaterHeight = min_water_height, + MaxWaterHeight = max_water_height, + Unknown1 = unk_1, + FileBase = file_base, + Unknown2 = unk_2, + Unknown3 = unk_3, + ReferenceExtra = ref_extra, + Offset = offset + }; - t.FileNames[i] = filename; + areaInfo.ExtraInfoLength = r.ReadUInt32(); //Usually 0, 4, or 8 + + if (ref_extra == 4) + { + if (areaInfo.ExtraInfoLength == 8) + { //Skip the extra "20" after the 8, as well as the extra info + areaInfo.HasGrass = true; + areaInfo.HasWater = true; + r.Advance(36); + } + else //If the length is 4 + { + var areabytes = r.ReadBytes(16).ToArray(); + if (areabytes[7] == 0) //If byte 7 equals 0 + areaInfo.HasGrass = true; + else //Else if the 2nd byte should be anything else (should always be 1) + areaInfo.HasWater = true; + } } + else //If the extra info flags aren't set, go back 4 + { + r.Advance(-4); + } + + t.AreaInfo[i] = areaInfo; } - return t; - } - else - { - throw new FileNotFoundException("Cannot find .tscb file to read."); + BOTWConsole.Log($"Offset after area iteration: {r.BaseStream.Position} (should be {t.FileBaseOffset + 16})"); + + //Get the number of filenames by getting how many bytes they take up out of the entire file size + var filenames_count = (r.BaseStream.Length - (t.FileBaseOffset + 16)) / 12; + + BOTWConsole.Log($"Filename count: {filenames_count} (should be {t.AreaArrayLength})"); + + t.FileNames = new string[filenames_count]; + + r.BaseStream.Seek(t.FileBaseOffset + 16, SeekOrigin.Begin); // TODO: change this to 'current' later, or maybe even remove + + for (int i = 0; i < filenames_count; i++) + { + string filename = new string(r.ReadChars(12)); + + t.FileNames[i] = filename; + } } + + return t; } /// @@ -221,7 +214,7 @@ namespace BOTWToolset.IO.TSCB /// /// that contains data to write. /// Byte array containing the TSCB data. - public static byte[] GetBytes(TSCB tscb) + public static byte[] ToBytes(TSCB tscb) { List b = new List();