public void Unpack(IProgress <ProgressReport> progress, IProgress <string> errors, CancellationToken cancelToken) { TPUtil.CopyOodle(Game.Type, Game.Settings.GameDirectory); progress.Report(new ProgressReport(0, "Scanning files...")); if (Game.Settings.UnpackSourceEbls) { VirtualFS.LoadEbls(Game); } if (Game.Settings.UnpackSourceUXM) { VirtualFS.LoadFiles(Game.Settings.GameDirectory); } if (Game.Settings.UnpackSourceModEngine) { VirtualFS.LoadFiles(TPUtil.ReadModEngineDirectory(Game.Settings.GameDirectory)); } string[] paths = VirtualFS.Files.Keys .Where(k => TPUtil.HasValidExtension(k) && UnpackFilter.RunFilters(k, Game.Config.MapFilters.Concat(Game.Config.Filters))) .OrderBy(k => k).ToArray(); progress.Report(new ProgressReport(0, $"Unpacking files... (0/{paths.Length})")); var tasks = new Task <int> [paths.Length]; for (int i = 0; i < paths.Length; i++) { VirtualFile vf = VirtualFS.Files[paths[i]]; tasks[i] = Task.Run(() => UnpackVirtualFile(vf, cancelToken)); tasks[i].ContinueWith(task => { Interlocked.Increment(ref FilesCompleted); progress.Report(new ProgressReport((float)FilesCompleted / paths.Length, $"Unpacking files... ({FilesCompleted}/{paths.Length})")); if (task.IsFaulted) { errors.Report($"Error in file \"{vf.Path}\"\n{task.Exception}"); } }); } Task.WaitAll(tasks); int textureCount = tasks.Where(t => t.IsCompleted).Sum(t => t.Result); if (cancelToken.IsCancellationRequested) { progress.Report(new ProgressReport(1, "Unpacking aborted successfully.")); } else { progress.Report(new ProgressReport(1, $"Finished unpacking {textureCount} textures from {paths.Length} files!")); } }
public void Pack(IProgress <ProgressReport> progress, IProgress <string> errors, CancellationToken cancelToken) { TPUtil.CopyOodle(Game.Type, Game.Settings.GameDirectory); progress.Report(new ProgressReport(0, "Scanning files...")); VirtualFS.LoadEbls(Game); if (Game.Settings.PackMode == PackMode.ModEngine) { VirtualFS.LoadFiles(TPUtil.ReadModEngineDirectory(Game.Settings.GameDirectory)); } else if (Game.Settings.PackMode == PackMode.UXM) { VirtualFS.LoadFiles(Game.Settings.GameDirectory); } string[] paths = VirtualFS.Files.Keys.Where(k => { string dir = $@"{Game.Settings.PackDirectory.TrimEnd('\\')}\{TPUtil.GetRelativeOutputDir(k)}"; return(TPUtil.HasValidExtension(k) && Directory.Exists(dir) && Directory.GetFiles(dir, "*.dds").Length > 0); }) .OrderBy(k => k).ToArray(); progress.Report(new ProgressReport(0, $"Checking files... (0/{paths.Length})")); var tasks = new Task <int> [paths.Length]; for (int i = 0; i < paths.Length; i++) { VirtualFile vf = VirtualFS.Files[paths[i]]; tasks[i] = Task.Run(() => PackVirtualFile(vf, cancelToken)); tasks[i].ContinueWith(task => { Interlocked.Increment(ref FilesCompleted); progress.Report(new ProgressReport((float)FilesCompleted / paths.Length, $"Checking files... ({FilesCompleted}/{paths.Length})")); if (task.IsFaulted) { errors.Report($"Error in file \"{vf.Path}\"\n{task.Exception}"); } }); } Task.WaitAll(tasks); int textureCount = tasks.Where(t => t.IsCompleted).Sum(t => t.Result); if (cancelToken.IsCancellationRequested) { progress.Report(new ProgressReport(1, "Packing aborted successfully.")); } else { progress.Report(new ProgressReport(1, $"Finished packing {textureCount} textures in {paths.Length} files!")); } }
private int PackBinder(IBinder binder, string relOutputDir, CancellationToken cancelToken) { int textureCount = 0; foreach (BinderFile file in binder.Files) { if (cancelToken.IsCancellationRequested) { return(textureCount); } if (TPUtil.HasValidExtension(file.Name)) { try { byte[] bytes = file.Bytes; DCX.Type dcxType = DCX.Type.None; if (DCX.Is(bytes)) { bytes = DCX.Decompress(bytes, out dcxType); } if (TPF.IsRead(bytes, out TPF tpf)) { int thisTextureCount = PackTPF(tpf, relOutputDir); if (thisTextureCount > 0) { file.Bytes = tpf.Write(dcxType); } textureCount += thisTextureCount; } else if (BND4.IsRead(bytes, out BND4 bnd)) { int thisTextureCount = PackBinder(bnd, relOutputDir, cancelToken); if (thisTextureCount > 0) { file.Bytes = bnd.Write(dcxType); } textureCount += thisTextureCount; } else { throw new NotSupportedException("Unknown file type."); } } catch (Exception ex) { throw new Exception($"Error in binder file \"{file.Name}\"", ex); } } } return(textureCount); }
public TexPacker(UnpackGame game) { Game = game; VirtualFS = new VirtualFileSystem(); BaseMemoryCommitted = 0; FilesCompleted = 0; if (game.Settings.PackMode == PackMode.ModEngine) { OutputDirectory = TPUtil.ReadModEngineDirectory(Game.Settings.GameDirectory); } else if (game.Settings.PackMode == PackMode.UXM) { OutputDirectory = Game.Settings.GameDirectory; } else { throw new NotImplementedException($"Unknown pack mode {Game.Settings.PackMode}"); } OutputDirectory = OutputDirectory.TrimEnd('\\'); }
private static BHD5 ReadBHD5(string path, string key, BHD5.Game game) { using (FileStream fs = File.OpenRead(path)) { var magic = new byte[4]; fs.Read(magic, 0, 4); fs.Seek(0, SeekOrigin.Begin); bool encrypted = Encoding.ASCII.GetString(magic) != "BHD5"; if (encrypted) { using (var ms = TPUtil.DecryptRsa(fs, key)) { return(BHD5.Read(ms, game)); } } else { return(BHD5.Read(fs, game)); } } }
private int PackVirtualFile(VirtualFile vf, CancellationToken cancelToken) { byte[] bytes; long baseMemory; lock (this) { while (BaseMemoryCommitted > TPUtil.MAX_BASE_MEMORY) { Thread.Sleep(10); } if (cancelToken.IsCancellationRequested) { return(0); } bytes = vf.Load(); baseMemory = bytes.Length; Interlocked.Add(ref BaseMemoryCommitted, baseMemory); } try { string relOutputDir = TPUtil.GetRelativeOutputDir(vf.Path); DCX.Type dcxType = DCX.Type.None; if (DCX.Is(bytes)) { bytes = DCX.Decompress(bytes, out dcxType); } int textureCount; if (TPF.IsRead(bytes, out TPF tpf)) { textureCount = PackTPF(tpf, relOutputDir); if (textureCount > 0) { tpf.Write($@"{OutputDirectory}\{vf.Path}", dcxType); } } else if (BND4.IsRead(bytes, out BND4 bnd)) { textureCount = PackBinder(bnd, relOutputDir, cancelToken); if (textureCount > 0) { bnd.Write($@"{OutputDirectory}\{vf.Path}", dcxType); } } else if (BXF4.IsBDT(bytes)) { string ext = Path.GetExtension(vf.Path).Replace("bdt", "bhd"); string bhdPath = Path.ChangeExtension(vf.Path, ext); VirtualFile vfHeader = VirtualFS.Files[bhdPath]; byte[] bhdBytes = vfHeader.Load(); var bxf = BXF4.Read(bhdBytes, bytes); textureCount = PackBinder(bxf, relOutputDir, cancelToken); if (textureCount > 0) { bxf.Write($@"{OutputDirectory}\{vfHeader.Path}", $@"{OutputDirectory}\{vf.Path}"); } } else { throw new NotSupportedException("Unknown file type."); } return(textureCount); } finally { Interlocked.Add(ref BaseMemoryCommitted, -baseMemory); } }
private int UnpackVirtualFile(VirtualFile vf, CancellationToken cancelToken) { byte[] bytes; long baseMemory; lock (this) { while (BaseMemoryCommitted > TPUtil.MAX_BASE_MEMORY) { Thread.Sleep(10); } if (cancelToken.IsCancellationRequested) { return(0); } bytes = vf.Load(); baseMemory = bytes.Length; Interlocked.Add(ref BaseMemoryCommitted, baseMemory); } try { string relOutputDir = TPUtil.GetRelativeOutputDir(vf.Path); if (DCX.Is(bytes)) { bytes = DCX.Decompress(bytes); } int textureCount; var report = new UnpackReport(); if (TPF.IsRead(bytes, out TPF tpf)) { textureCount = UnpackTPF(tpf, relOutputDir, report); } else if (BND4.IsRead(bytes, out BND4 bnd)) { textureCount = UnpackBinder(bnd, relOutputDir, report, cancelToken); } else if (BXF4.IsBDT(bytes)) { string ext = Path.GetExtension(vf.Path).Replace("bdt", "bhd"); string bhdPath = Path.ChangeExtension(vf.Path, ext); VirtualFile vfHeader = VirtualFS.Files[bhdPath]; byte[] bhdBytes = vfHeader.Load(); var bxf = BXF4.Read(bhdBytes, bytes); textureCount = UnpackBinder(bxf, relOutputDir, report, cancelToken); } else { throw new NotSupportedException("Unknown file type."); } if (report.Files.Count > 0) { File.WriteAllText($@"{Game.Settings.UnpackDirectory.TrimEnd('\\')}\{relOutputDir}\_report.txt", report.Write()); } return(textureCount); } finally { Interlocked.Add(ref BaseMemoryCommitted, -baseMemory); } }