diff --git a/CodeWalker.Core/GameFiles/RpfFile.cs b/CodeWalker.Core/GameFiles/RpfFile.cs index 53d8e78..c430d96 100644 --- a/CodeWalker.Core/GameFiles/RpfFile.cs +++ b/CodeWalker.Core/GameFiles/RpfFile.cs @@ -1436,21 +1436,50 @@ namespace CodeWalker.GameFiles } - public long GetDefragmentedFileSize() + public long GetDefragmentedFileSize(bool recursive = true) { //this represents the size the file would be when fully defragmented. - uint blockcount = GetHeaderBlockCount(); - foreach (var entry in AllEntries) + if (!recursive) { - var fentry = entry as RpfFileEntry; - if (fentry != null) - { - blockcount += GetBlockCount(fentry.GetFileSize()); - } - } + uint blockcount = GetHeaderBlockCount(); - return (long)blockcount * 512; + + foreach (var entry in AllEntries) + { + var fentry = entry as RpfFileEntry; + if (fentry != null) + { + blockcount += GetBlockCount(fentry.GetFileSize()); + } + } + + return (long)blockcount * 512; + } + else + { + uint blockcount = GetHeaderBlockCount(); + long childRpfsSize = 0; + + foreach (var entry in AllEntries) + { + var fentry = entry as RpfFileEntry; + if (fentry != null) + { + var childRpf = this.FindChildArchive(fentry); + if (childRpf == null) + { + blockcount += GetBlockCount(fentry.GetFileSize()); + } + else + { + childRpfsSize += childRpf.GetDefragmentedFileSize(true); + } + } + } + + return (long)blockcount * 512 + childRpfsSize; + } } @@ -1914,10 +1943,25 @@ namespace CodeWalker.GameFiles } - public static void Defragment(RpfFile file, Action progress = null) + public static void Defragment(RpfFile file, Action progress = null, bool recursive = true) { if (file?.AllEntries == null) return; + if (recursive) + { + foreach (var entry in file?.AllEntries) + { + if (entry is RpfFileEntry) + { + var childRpf = file.FindChildArchive(entry as RpfFileEntry); + if (childRpf != null) + { + Defragment(childRpf, null, true); + } + } + } + } + string fpath = file.GetPhysicalFilePath(); using (var fstream = File.Open(fpath, FileMode.Open, FileAccess.ReadWrite)) { diff --git a/CodeWalker/ExploreForm.cs b/CodeWalker/ExploreForm.cs index 0044ba9..92d134a 100644 --- a/CodeWalker/ExploreForm.cs +++ b/CodeWalker/ExploreForm.cs @@ -3170,7 +3170,7 @@ namespace CodeWalker Form form = new Form() { Width = 450, - Height = 250, + Height = 290, FormBorderStyle = FormBorderStyle.FixedDialog, Text = "Defragment RPF Archive - CodeWalker by dexyfex", StartPosition = FormStartPosition.CenterParent, @@ -3181,14 +3181,19 @@ namespace CodeWalker var addLabel = new Func((y, t) => { return addCtrl(new Label() { Left = 30, Top = y, Width = 370, Height = 20, Text = t }); }); + var addCheckbox = new Func((y, t, defaultVal) => + { + return addCtrl(new CheckBox() { Left = 33, Top = y, Width = 370, Height = 20, Text = t, Checked = defaultVal }); + }); var rpfNameLabel = addLabel(20, "Archive: " + rpf.Path); var curSizeLabel = addLabel(40, string.Empty); var newSizeLabel = addLabel(60, string.Empty); var redSizeLabel = addLabel(80, string.Empty); var statusLabel = addLabel(110, string.Empty); - var progressBar = addCtrl(new ProgressBar() { Left = 30, Top = 130, Width = 370, Height = 20, Minimum = 0, Maximum = 1000, MarqueeAnimationSpeed = 50 }) as ProgressBar; - var beginButton = addCtrl(new Button() { Text = "Begin Defragment", Left = 30, Top = 170, Width = 120 }) as Button; - var closeButton = addCtrl(new Button() { Text = "Close", Left = 320, Top = 170, Width = 80 }) as Button; + CheckBox recursiveCheckbox = addCheckbox(130, "Recursive", true) as CheckBox; + var progressBar = addCtrl(new ProgressBar() { Left = 30, Top = 180, Width = 370, Height = 20, Minimum = 0, Maximum = 1000, MarqueeAnimationSpeed = 50 }) as ProgressBar; + var beginButton = addCtrl(new Button() { Text = "Begin Defragment", Left = 30, Top = 210, Width = 120 }) as Button; + var closeButton = addCtrl(new Button() { Text = "Close", Left = 320, Top = 210, Width = 80 }) as Button; var inProgress = false; var updateProgress = new Action((s, p) => { form.Invoke(new Action(() => { statusLabel.Text = s; @@ -3196,7 +3201,7 @@ namespace CodeWalker }));}); var updateSizeLabels = new Action((init) => { var curSize = rpf.FileSize; - var newSize = rpf.GetDefragmentedFileSize(); + var newSize = rpf.GetDefragmentedFileSize(recursiveCheckbox.Checked); var redSize = curSize - newSize; curSizeLabel.Text = "Archive current size: " + TextUtil.GetBytesReadable(curSize); newSizeLabel.Text = "Defragmented size: " + TextUtil.GetBytesReadable(newSize); @@ -3212,7 +3217,7 @@ namespace CodeWalker if (!EnsureRpfValidEncryption(rpf)) return; inProgress = true; enableUi(false); - RpfFile.Defragment(rpf, updateProgress); + RpfFile.Defragment(rpf, updateProgress, recursiveCheckbox.Checked); updateProgress("Defragment complete.", 1.0f); enableUi(true); form.Invoke(new Action(() => { updateSizeLabels(false); })); @@ -3221,6 +3226,7 @@ namespace CodeWalker updateSizeLabels(true); beginButton.Click += (sender, e) => { defragment(); }; closeButton.Click += (sender, e) => { form.Close(); }; + recursiveCheckbox.Click += (sender, e) => { updateSizeLabels(false); }; form.FormClosing += (s, e) => { e.Cancel = inProgress; }; form.ShowDialog(this); RefreshMainListView();