Skip to content

Commit

Permalink
Add support for viewing Decompressed NSRs (nsr_raw)
Browse files Browse the repository at this point in the history
Updated Zone 1021 "Wasteland" to include production name "Broken Peninsula".
Improved error handling.
Began adding support for eventually allowing merging NSR Index files back into NSR Content files. Game client already supports this.
  • Loading branch information
ThiconZ committed Aug 2, 2020
1 parent 8a91949 commit ac78ee9
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 15 deletions.
2 changes: 1 addition & 1 deletion NSRViewer/NSRViewer/NSR/MetaHeader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -631,7 +631,7 @@ public struct MetaHeader
{ 1017, "Edward_Bowman_test_map" },
{ 1018, "DO NOT USE - Marketing - Antarctica" },
{ 1019, "Adrian's test spawn" },
{ 1021, "Wasteland" },
{ 1021, "Wasteland [Broken Peninsula]" },
{ 1022, "Boss - Wormasaurus" },
{ 1023, "ArcTest" },
{ 1024, "First 5 Experience - Intro to Firefall" },
Expand Down
10 changes: 5 additions & 5 deletions NSRViewer/NSRViewer/Viewer.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

66 changes: 57 additions & 9 deletions NSRViewer/NSRViewer/Viewer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ public void LoadNSRDirectory(string nsrDirectory)
ReplayFileListBox.Items.Add(file);
}
}

foreach (string file in Directory.GetFiles(nsrDirectory, "*.nsr_raw", SearchOption.TopDirectoryOnly))
{
ReplayFileListBox.Items.Add(file);
}
}

public string GetNSRDirectory()
Expand Down Expand Up @@ -74,7 +79,16 @@ public bool LoadNSRPreview(BinaryReader binaryReader, ref NSR.NSR nsrFile)
// matrix_fury::RequestGhosts->Headers

// description header
char[] nsrDescription = binaryReader.ReadChars(4);
try
{
char[] nsrDescription = binaryReader.ReadChars(4);
}
catch (InvalidDataException ex)
{
// file is either corrupt or not a valid NSR file
return false;
}

nsrFile.DescriptionHeader.Version = binaryReader.ReadUInt32();
nsrFile.DescriptionHeader.HeaderLength = binaryReader.ReadUInt32();
nsrFile.DescriptionHeader.MetaLength = binaryReader.ReadUInt32();
Expand Down Expand Up @@ -140,6 +154,34 @@ public bool LoadNSRPreview(BinaryReader binaryReader, ref NSR.NSR nsrFile)
return true;
}

public bool LoadNSRIndexHeader(BinaryReader binaryReader, ref NSR.NSR nsrFile)
{
// binaryReader is to a filename.*.nsr.index stream

char[] nsrIndex = binaryReader.ReadChars(4);

nsrFile.IndexHeader.Version = binaryReader.ReadUInt32();
nsrFile.IndexHeader.Unk0 = binaryReader.ReadUInt32();
nsrFile.IndexHeader.Unk1 = binaryReader.ReadUInt32();
nsrFile.IndexHeader.Count = binaryReader.ReadUInt32();
nsrFile.IndexHeader.IndexOffset = binaryReader.ReadUInt32();
nsrFile.IndexHeader.Offsets = new uint[nsrFile.IndexHeader.Count];

for (int i = 0; i < nsrFile.IndexHeader.Count; i++)
{
nsrFile.IndexHeader.Offsets[i] = binaryReader.ReadUInt32();
}

// TODO: Provide option to update DescriptionHeader.HeaderLength to include IndexHeader length
// This would ultimately merge the standalone index file into the base nsr file.
if (false)
{
nsrFile.DescriptionHeader.HeaderLength += nsrFile.IndexHeader.IndexOffset + (nsrFile.IndexHeader.Count * 4);
}

return true;
}

public bool LoadNSR(BinaryReader binaryReader, ref NSR.NSR nsrFile)
{
LoadNSRPreview(binaryReader, ref nsrFile);
Expand Down Expand Up @@ -253,12 +295,12 @@ private void ReplayFileListBox_SelectedIndexChanged(object sender, EventArgs e)
compressedStreamPreview.Position = 0;

using (GZipStream decompressedStream = new GZipStream(compressedStreamPreview, CompressionMode.Decompress))
using (BinaryReader b = new BinaryReader(decompressedStream, Encoding.UTF8))
using (BinaryReader b = (ReplayFileListBox.SelectedItem.ToString().EndsWith(".nsr_raw") ? new BinaryReader(compressedStreamPreview, Encoding.UTF8) : new BinaryReader(decompressedStream, Encoding.UTF8)))
{
NSR.NSR nsrFile = new NSR.NSR();
if (!LoadNSRPreview(b, ref nsrFile))
{
MessageBox.Show("Error loading Network Stream Replay.");
MessageBox.Show("Error loading Network Stream Replay.", "Network Stream Replay Viewer", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}

Expand Down Expand Up @@ -286,6 +328,12 @@ private void ExportDecompressedFileBtn_Click(object sender, EventArgs e)
return;
}

if (ReplayFileListBox.SelectedItem.ToString().EndsWith(".nsr_raw"))
{
MessageBox.Show("The selected Replay File already is in a decompressed format.", "Network Stream Replay Viewer", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}

SaveFileDialog saveFileDialog = new SaveFileDialog
{
Filter = "Decompressed NSR Files (*.nsr_raw)|*.nsr_raw",
Expand All @@ -300,7 +348,7 @@ private void ExportDecompressedFileBtn_Click(object sender, EventArgs e)
byte[] compressedFile = File.ReadAllBytes(ReplayFileListBox.SelectedItem.ToString());
byte[] decompressedBytes = Decompress(compressedFile);
File.WriteAllBytes(saveFileDialog.FileName, decompressedBytes);
MessageBox.Show("Export Complete.", "Export Complete", MessageBoxButtons.OK, MessageBoxIcon.Information);
MessageBox.Show("Export Complete.", "Network Stream Replay Viewer", MessageBoxButtons.OK, MessageBoxIcon.Information);
}

private void CopyInfoBtn_Click(object sender, EventArgs e)
Expand All @@ -323,7 +371,7 @@ private void CopyInfoBtn_Click(object sender, EventArgs e)
clipboardString += "File Size: " + FileSizeValLabel.Text + Environment.NewLine;

Clipboard.SetText(clipboardString);
MessageBox.Show("Information Copied to Clipboard!", "Information Copied", MessageBoxButtons.OK, MessageBoxIcon.Information);
MessageBox.Show("Information Copied to Clipboard!", "Network Stream Replay Viewer", MessageBoxButtons.OK, MessageBoxIcon.Information);
}

private void ViewGhostsBtn_Click(object sender, EventArgs e)
Expand All @@ -336,7 +384,7 @@ private void ViewGhostsBtn_Click(object sender, EventArgs e)
// Display data collected from matrix_fury::RequestGhosts
// Full Load NSR
byte[] compressedFile = File.ReadAllBytes(ReplayFileListBox.SelectedItem.ToString()); // loads compressed size into memory
byte[] decompressedBytes = Decompress(compressedFile); // loads raw size 2x into memory
byte[] decompressedBytes = ReplayFileListBox.SelectedItem.ToString().EndsWith(".nsr_raw") ? compressedFile : Decompress(compressedFile); // loads raw size 2x into memory

// Done using compressed data now
compressedFile = null;
Expand All @@ -347,7 +395,7 @@ private void ViewGhostsBtn_Click(object sender, EventArgs e)
NSR.NSR nsrFile = new NSR.NSR();
if (LoadNSR(decompressedReader, ref nsrFile) == false) // loads raw size 2x into memory
{
MessageBox.Show("Error loading Network Stream Replay.");
MessageBox.Show("Error loading Network Stream Replay.", "Network Stream Replay Viewer", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else
{
Expand Down Expand Up @@ -397,7 +445,7 @@ private void ViewInFirefallBtn_Click(object sender, EventArgs e)
startInfo.FileName = clientInfo.Name;
startInfo.Arguments = $"--open=\"{ReplayFileListBox.SelectedItem}\"";
System.Diagnostics.Process.Start(startInfo);
MessageBox.Show("Firefall Launched");
MessageBox.Show("Firefall Launched", "Network Stream Replay Viewer", MessageBoxButtons.OK);
}

private void ReplayFileListBox_DragEnter(object sender, DragEventArgs e)
Expand All @@ -420,7 +468,7 @@ private void ReplayFileListBox_DragDrop(object sender, DragEventArgs e)
fileDirectoryPath = files[0];
}

if (MessageBox.Show($"Open directory [{fileDirectoryPath}] ?", "Open NSR Directory", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
if (MessageBox.Show($"Open directory [{fileDirectoryPath}] ?", "Network Stream Replay Viewer", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
LoadNSRDirectory(fileDirectoryPath);
ReplayFileListBox.Focus();
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ Features:

* Export Decompressed NSR Files
* View Keyframe GHOSTS of Network Stream Replays
* View Keyframe GHOSTS of Decompressed NSR Files (nsr_raw)
* Launch Firefall directly into selected NSR File

0 comments on commit ac78ee9

Please sign in to comment.