Update TSCB methods

FromBytes replaces ReadFile & uses a byte array instead of filename. GetBytes is renamed to ToBytes.
This commit is contained in:
Chev 2021-01-16 22:49:36 -08:00
parent 6d6e9f4749
commit f19f94f459
2 changed files with 132 additions and 139 deletions

View file

@ -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));
}
}

View file

@ -52,168 +52,161 @@ namespace BOTWToolset.IO.TSCB
/// </summary>
/// <param name="file">The .tscb file.</param>
/// <returns></returns>
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;
}
/// <summary>
@ -221,7 +214,7 @@ namespace BOTWToolset.IO.TSCB
/// </summary>
/// <param name="tscb"><see cref="TSCB"/> that contains data to write.</param>
/// <returns>Byte array containing the TSCB data.</returns>
public static byte[] GetBytes(TSCB tscb)
public static byte[] ToBytes(TSCB tscb)
{
List<byte> b = new List<byte>();