From e58baa79f43d63d79c8d0def02cc57ea9e60c2b0 Mon Sep 17 00:00:00 2001 From: dexyfex Date: Wed, 28 Feb 2018 03:46:06 +1100 Subject: [PATCH] RPF Explorer drag & drop folders, delete folders with items, render bug fix --- CodeWalker.Core/GameFiles/RpfFile.cs | 14 +- ExploreForm.Designer.cs | 1 - ExploreForm.cs | 191 +++++++++++++++++++++++---- ExploreForm.resx | 22 +-- Rendering/Utils/GpuBuffers.cs | 10 +- 5 files changed, 190 insertions(+), 48 deletions(-) diff --git a/CodeWalker.Core/GameFiles/RpfFile.cs b/CodeWalker.Core/GameFiles/RpfFile.cs index 52d292f..3373759 100644 --- a/CodeWalker.Core/GameFiles/RpfFile.cs +++ b/CodeWalker.Core/GameFiles/RpfFile.cs @@ -1717,7 +1717,7 @@ namespace CodeWalker.GameFiles { //delete this entry from the RPF header. //also remove any references to this item in its parent directory... - //if this is a directory entry, make sure it is empty first + //if this is a directory entry, this will delete the contents first RpfFile parent = entry.File; string fpath = parent.GetPhysicalFilePath(); @@ -1731,11 +1731,15 @@ namespace CodeWalker.GameFiles if (entryasdir != null) { - var dircount = entryasdir.Directories?.Count ?? 0; - var filecount = entryasdir.Files?.Count ?? 0; - if ((dircount + filecount) > 0) + var deldirs = entryasdir.Directories.ToArray(); + var delfiles = entryasdir.Files.ToArray(); + foreach(var deldir in deldirs) { - throw new Exception("RPF directory is not empty! Please delete its contents first."); + DeleteEntry(deldir); + } + foreach (var delfile in delfiles) + { + DeleteEntry(delfile); } } diff --git a/ExploreForm.Designer.cs b/ExploreForm.Designer.cs index 1a5f5c3..2fff1c0 100644 --- a/ExploreForm.Designer.cs +++ b/ExploreForm.Designer.cs @@ -728,7 +728,6 @@ this.MainListView.RetrieveVirtualItem += new System.Windows.Forms.RetrieveVirtualItemEventHandler(this.MainListView_RetrieveVirtualItem); this.MainListView.DragDrop += new System.Windows.Forms.DragEventHandler(this.MainListView_DragDrop); this.MainListView.DragEnter += new System.Windows.Forms.DragEventHandler(this.MainListView_DragEnter); - this.MainListView.DragLeave += new System.EventHandler(this.MainListView_DragLeave); this.MainListView.KeyDown += new System.Windows.Forms.KeyEventHandler(this.MainListView_KeyDown); this.MainListView.KeyUp += new System.Windows.Forms.KeyEventHandler(this.MainListView_KeyUp); this.MainListView.MouseUp += new System.Windows.Forms.MouseEventHandler(this.MainListView_MouseUp); diff --git a/ExploreForm.cs b/ExploreForm.cs index 4d81e60..797c4ed 100644 --- a/ExploreForm.cs +++ b/ExploreForm.cs @@ -941,22 +941,45 @@ namespace CodeWalker //an RPF file was imported. add its structure to the UI! var rootpath = GTAFolder.GetCurrentGTAFolderWithTrailingSlash(); var tnf = CreateRpfTreeFolder(newrpf, newrpf.Path, rootpath + newrpf.Path); - if (CurrentFolder.Children != null) + CurrentFolder.AddChildToHierarchy(tnf); + var pfolder = tnf.Parent; + if (pfolder.Children != null) { //make sure any existing (replaced!) one is removed first! - foreach (var child in CurrentFolder.Children) + foreach (var child in pfolder.Children) { - if (child.Path == tnf.Path) + if ((child != tnf) && (child.Path == tnf.Path)) { - CurrentFolder.Children.Remove(child); + pfolder.Children.Remove(child); child.TreeNode.Remove(); break; } } } - CurrentFolder.AddChildToHierarchy(tnf); RecurseMainTreeViewRPF(tnf, AllRpfs); - RecurseAddMainTreeViewNodes(tnf, CurrentFolder.TreeNode); + RecurseAddMainTreeViewNodes(tnf, pfolder.TreeNode); + } + private void EnsureImportedFolder(RpfDirectoryEntry entry, RpfDirectoryEntry parentrpffldr) + { + if ((entry == null) || (parentrpffldr == null)) return; + + var rootpath = GTAFolder.GetCurrentGTAFolderWithTrailingSlash(); + var tnf = CreateRpfDirTreeFolder(entry, entry.Path, rootpath + entry.Path); + CurrentFolder.AddChildToHierarchy(tnf); + + if (tnf.Parent.TreeNode != null) + { + RecurseAddMainTreeViewNodes(tnf, tnf.Parent.TreeNode); + } + + foreach (var subdir in entry.Directories) + { + EnsureImportedFolder(subdir, entry); + } + foreach (var subfile in entry.Files) + { + EnsureImportedRpf(subfile, entry); + } } private void RefreshMainListView() @@ -2204,7 +2227,70 @@ namespace CodeWalker if (!EnsureRpfValidEncryption()) return; } + var filelist = new List(); + var dirdict = new Dictionary(); foreach (var fpath in fpaths) + { + try + { + if (File.Exists(fpath)) + { + filelist.Add(fpath); + } + else if (Directory.Exists(fpath)) //create imported directory structure in the RPF. + { + //create the first directory entry. + var fdi = new DirectoryInfo(fpath); + var direntry = RpfFile.CreateDirectory(parentrpffldr, fdi.Name); + dirdict[fpath] = direntry; + var dirpaths = Directory.GetFileSystemEntries(fpath, "*", SearchOption.AllDirectories); + var newfiles = new List(); + foreach (var dirpath in dirpaths) + { + if (File.Exists(dirpath)) + { + newfiles.Add(dirpath); + } + else if (Directory.Exists(dirpath)) + { + var cdi = new DirectoryInfo(dirpath); + RpfDirectoryEntry pdirentry; + if (!dirdict.TryGetValue(cdi.Parent.FullName, out pdirentry)) + { + pdirentry = direntry;//fallback, shouldn't get here + } + if (pdirentry != null) + { + var cdirentry = RpfFile.CreateDirectory(pdirentry, cdi.Name); + dirdict[dirpath] = cdirentry; + } + } + } + foreach (var newfile in newfiles) + { + var nfi = new FileInfo(newfile); + RpfDirectoryEntry ndirentry; + if (!dirdict.TryGetValue(nfi.DirectoryName, out ndirentry)) + { + ndirentry = direntry;//fallback, shouldn't get here + } + filelist.Add(newfile); + dirdict[newfile] = ndirentry; + } + + EnsureImportedFolder(direntry, parentrpffldr); + } + else + { } //nothing to see here! + } + catch (Exception ex) + { + MessageBox.Show(ex.Message, "Unable to import folder"); + } + } + + + foreach (var fpath in filelist) { try { @@ -2226,9 +2312,16 @@ namespace CodeWalker byte[] data = File.ReadAllBytes(fpath); - var entry = RpfFile.CreateFile(parentrpffldr, fname, data); - EnsureImportedRpf(entry, parentrpffldr); //make sure structure is created if an RPF was imported + var rpffldr = parentrpffldr; + if (dirdict.ContainsKey(fpath)) + { + rpffldr = dirdict[fpath]; + } + + var entry = RpfFile.CreateFile(rpffldr, fname, data); + + EnsureImportedRpf(entry, rpffldr); //make sure structure is created if an RPF was imported Cursor = Cursors.Default; } @@ -2425,6 +2518,14 @@ namespace CodeWalker return; } } + else if ((item.Folder?.GetItemCount() ?? 0) > 0) + { + //confirm deletion of non-empty folders, just to be friendly. + if (MessageBox.Show("Are you sure you want to delete this folder and all its contents?\n" + item.Path, "Confirm delete folder", MessageBoxButtons.YesNo) != DialogResult.Yes) + { + return; + } + } var parent = item.Parent; if (parent.RpfFolder != null) @@ -2844,6 +2945,29 @@ namespace CodeWalker Cursor = Cursors.WaitCursor; + var writeFile = new Action((file, outdir, addfilename) => + { + if (file.FileSize > 0x6400000) //100MB + { + errors.Add(file.Name + " is greater than 100MB, drag-drop for large files is disabled."); + return; + } + try + { + var data = GetFileDataCompressResources(file); + var filename = Path.Combine(outdir, file.Name); + File.WriteAllBytes(filename, data); + if (addfilename) + { + filenames.Add(filename); + } + } + catch (Exception ex) + { + errors.Add(ex.ToString()); + } + }); + for (int i = 0; i < MainListView.SelectedIndices.Count; i++) { var idx = MainListView.SelectedIndices[i]; @@ -2851,22 +2975,38 @@ namespace CodeWalker var file = CurrentFiles[idx]; if ((file.Folder == null) || (file.Folder.RpfFile != null)) { - if (file.FileSize > 0x6400000) //100MB + //item is a file (or RPF archive). + writeFile(file, dir, true); + } + else + { + //item is a folder. + var parentpath = file.Parent.Path; + var folderstack = new Stack(); + folderstack.Push(file.Folder); + while (folderstack.Count > 0) { - errors.Add(file.Name + " is greater than 100MB, drag-drop for large files is disabled."); - continue; - } - try - { - var data = GetFileDataCompressResources(file); - var filename = Path.Combine(dir, file.Name); - File.WriteAllBytes(filename, data); - filenames.Add(filename); - } - catch (Exception ex) - { - errors.Add(ex.ToString()); + var folder = folderstack.Pop(); + var folderitems = folder.GetListItems(); + var relpath = folder.Path.Replace(parentpath, ""); + var abspath = dir + relpath; + if (!Directory.Exists(abspath)) + { + Directory.CreateDirectory(abspath); //create the temp directory... + } + foreach (var item in folderitems) + { + if ((item.Folder == null) || (item.Folder.RpfFile != null)) + { + writeFile(item, abspath, false); + } + else + { + folderstack.Push(item.Folder); + } + } } + filenames.Add(dir + "\\" + file.Name); } } @@ -2887,11 +3027,6 @@ namespace CodeWalker } - private void MainListView_DragLeave(object sender, EventArgs e) - { - - } - private void MainListView_DragEnter(object sender, DragEventArgs e) { if (!EditMode) return; @@ -3327,7 +3462,7 @@ namespace CodeWalker if (parent.Children == null) break; foreach (var tc in parent.Children) { - if (tc.Name == pname) + if (tc.Name.Equals(pname, StringComparison.InvariantCultureIgnoreCase)) { parent = tc; break; diff --git a/ExploreForm.resx b/ExploreForm.resx index 6cf195f..168121f 100644 --- a/ExploreForm.resx +++ b/ExploreForm.resx @@ -271,16 +271,6 @@ e2d2SZBn3BDEyPiVG5X23Ap3LtwYqxPDuBkxUEmGNWnPzTCEn1GZjBBcYawROqpiopbZ8v/CtN9mmB+9 1vZY1yV7KT9+37JAwB1LBeyfTv8N11OX0LGtniroCF2hd2L+f3A9qqp2iWbL30hjPP3/CJi+jvVtWwLw A4Rmgl76+inbAAAAAElFTkSuQmCC - - - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADVSURBVDhPpVIxDoMwDORJfQN7pI5hz1pmytSJ7/EFhrYZ - MqSVgDXlIhslaoga9aQTsn1nOyFVDsuynNd1HTe6gCPyJDnGJrpN0+T6vnd1Xe9EjDzqJP0GJkAkhIjM - TOSpSXoTrMmTu+7qHvene9m3/7aX1udRh44sMXBWnsZmJmKuQUeWGFiPRaGZKaXMN/hrg3meTygopbyo - 6A7IbIdh2KekmPwLR+amaaI4+Q6OzDiGMcafNWD8EnNmrbVFnaRppBr8bGaETYrNDG4CFpsZMJaZq+oD - NQar60zqQI0AAAAASUVORK5CYII= @@ -300,6 +290,16 @@ lVY67e7NJiI/2QxXrEetVVZsAY5938U5NzUbthbgknMW7735iOnYsB0AqBXXlJL5jOnYsDUBqA1uMcbh mYyuz6aAU/M9hKDP3GR0ffYegNrwXEpRADdZr5+aAlB7UAB3j1V/Anh1j1UD4Fub4YrN8HPL9gAVE1vf J6IiRgAAAABJRU5ErkJggg== + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADVSURBVDhPpVIxDoMwDORJfQN7pI5hz1pmytSJ7/EFhrYZ + MqSVgDXlIhslaoga9aQTsn1nOyFVDsuynNd1HTe6gCPyJDnGJrpN0+T6vnd1Xe9EjDzqJP0GJkAkhIjM + TOSpSXoTrMmTu+7qHvene9m3/7aX1udRh44sMXBWnsZmJmKuQUeWGFiPRaGZKaXMN/hrg3meTygopbyo + 6A7IbIdh2KekmPwLR+amaaI4+Q6OzDiGMcafNWD8EnNmrbVFnaRppBr8bGaETYrNDG4CFpsZMJaZq+oD + NQar60zqQI0AAAAASUVORK5CYII= @@ -313,7 +313,7 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAADo - HwAAAk1TRnQBSQFMAgEBGAEAAfABAAHwAQABEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo + HwAAAk1TRnQBSQFMAgEBGAEAAfgBAAH4AQABEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo AwABQAMAAXADAAEBAQABCAYAARwYAAGAAgABgAMAAoABAAGAAwABgAEAAYABAAKAAgADwAEAAcAB3AHA AQAB8AHKAaYBAAEzBQABMwEAATMBAAEzAQACMwIAAxYBAAMcAQADIgEAAykBAANVAQADTQEAA0IBAAM5 AQABgAF8Af8BAAJQAf8BAAGTAQAB1gEAAf8B7AHMAQABxgHWAe8BAAHWAucBAAGQAakBrQIAAf8BMwMA diff --git a/Rendering/Utils/GpuBuffers.cs b/Rendering/Utils/GpuBuffers.cs index a900145..5300b45 100644 --- a/Rendering/Utils/GpuBuffers.cs +++ b/Rendering/Utils/GpuBuffers.cs @@ -34,9 +34,13 @@ namespace CodeWalker.Rendering } public void Update(DeviceContext context) { - var dataBox = context.MapSubresource(Buffer, 0, MapMode.WriteDiscard, MapFlags.None); - Utilities.Write(dataBox.DataPointer, ref Vars); - context.UnmapSubresource(Buffer, 0); + try + { + var dataBox = context.MapSubresource(Buffer, 0, MapMode.WriteDiscard, MapFlags.None); + Utilities.Write(dataBox.DataPointer, ref Vars); + context.UnmapSubresource(Buffer, 0); + } + catch { } //not much we can do about this except ignore it.. } public void SetVSCBuffer(DeviceContext context, int slot) {