using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Drawing; using System.IO; using System.Linq; using System.Net; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace PatchDownloader { public partial class fPatchDownloader : Form { private string _patchListURL = "http://patch.cdn.gamigo.com/fous/gdp/PatchHive.txt"; public fPatchDownloader() { InitializeComponent(); } private void bDownload_Click(object sender, EventArgs e) { BackgroundWorker backgroundWorker = new BackgroundWorker(); backgroundWorker.WorkerReportsProgress = true; backgroundWorker.DoWork += DownloadPatches; backgroundWorker.ProgressChanged += (doWorkSender, doWorkEventArgs) => { if (doWorkEventArgs.UserState != null) { if (doWorkEventArgs.UserState is string) { lStatus.Text = (string)doWorkEventArgs.UserState; } pbDownloading.Value = doWorkEventArgs.ProgressPercentage; } }; backgroundWorker.RunWorkerAsync(); } private void tbDownloadDirectory_Click(object sender, EventArgs e) { ChooseDownloadDirectory(); } private void bChooseDownloadDirectory_Click(object sender, EventArgs e) { ChooseDownloadDirectory(); } private void bExtractAll_Click(object sender, EventArgs e) { BackgroundWorker backgroundWorker = new BackgroundWorker(); backgroundWorker.WorkerReportsProgress = true; backgroundWorker.DoWork += ExtractAllPatches; backgroundWorker.ProgressChanged += (doWorkSender, doWorkEventArgs) => { if (doWorkEventArgs.UserState != null) { if (doWorkEventArgs.UserState is string) { lStatus.Text = (string)doWorkEventArgs.UserState; } pbDownloading.Value = doWorkEventArgs.ProgressPercentage; } }; backgroundWorker.RunWorkerAsync(); } private void bCopyBins_Click(object sender, EventArgs e) { CopyBins(); } private void bCheckPDB_Click(object sender, EventArgs e) { CheckPDB(); } private void DownloadPatches(object sender, DoWorkEventArgs args) { BackgroundWorker backgroundWorker = (BackgroundWorker)sender; using (WebClient webClient = new WebClient()) { Version minVersion = new Version(); if (tbMinVersion.Text.Length > 0) { minVersion = new Version(tbMinVersion.Text); } string rootURL = null; List patches = new List(); string patchList = webClient.DownloadString(_patchListURL); string[] patchListLines = patchList.Split(new[] { '\r', '\n' }); foreach (string patchListLine in patchListLines) { if (patchListLine.StartsWith("#ROOT")) { string[] patchListLineParts = patchListLine.Split('\t'); if (patchListLineParts.Length > 1) { rootURL = patchListLineParts[1]; } } else if (patchListLine.StartsWith("#PATCH")) { string[] patchListLineParts = patchListLine.Split('\t'); if (patchListLineParts.Length > 2) { Version version = new Version(patchListLineParts[1]); if (version.CompareTo(minVersion) > 0) { patches.Add(patchListLineParts[2]); } } } } if (rootURL == null) { backgroundWorker.ReportProgress(0, "Failed to download patches"); } else if (patches.Count == 0) { backgroundWorker.ReportProgress(100, "No patches to download"); } else { backgroundWorker.ReportProgress(0, "Starting downloads..."); for (Int32 i = 0; i < patches.Count; i++) { try { webClient.DownloadFile($"{rootURL}//{patches[i]}", $"{tbDownloadDirectory.Text}\\{patches[i]}"); } catch { } backgroundWorker.ReportProgress((Int32)(((double)i / (double)patches.Count) * 100), $"Downloading Patch {i}/{patches.Count}"); } backgroundWorker.ReportProgress(100, "Finished"); } } } private void ChooseDownloadDirectory() { FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog(); if (folderBrowserDialog.ShowDialog() == DialogResult.OK) { tbDownloadDirectory.Text = folderBrowserDialog.SelectedPath; bDownload.Enabled = true; } } private void ExtractAllPatches(object sender, DoWorkEventArgs args) { BackgroundWorker backgroundWorker = (BackgroundWorker)sender; string[] filePaths = Directory.GetFiles(tbDownloadDirectory.Text, "*.gdp", SearchOption.TopDirectoryOnly); for (Int32 i = 0; i < filePaths.Length; i++) { backgroundWorker.ReportProgress((Int32)(((double)i / (double)filePaths.Length) * 100), filePaths[i]); string to = $"{filePaths[i]}"; to = to.TrimEnd(".gdp".ToArray()); using (FileStream fileStream = new FileStream(filePaths[i], FileMode.Open)) using (BinaryReader binaryReader = new BinaryReader(fileStream)) { byte[] hType = binaryReader.ReadBytes(3); if (Encoding.ASCII.GetString(hType) == "GDP") { byte[] hUnk = binaryReader.ReadBytes(5); byte[] hHead = binaryReader.ReadBytes(260); string sHead = Encoding.ASCII.GetString(hHead.Where(x => x > 0x00).ToArray()); uint GDPUnk = binaryReader.ReadUInt32(); uint GDPSpaceCount = binaryReader.ReadUInt32(); byte[] GDPUnk2 = binaryReader.ReadBytes(40); Dictionary GDPFiles = new Dictionary(); for (int x = 0; x < GDPSpaceCount; x++) { long type = binaryReader.ReadInt64(); if (type != 2) continue; GDPFiles.Add(x, new GDPFile() { Type = type, ApplyLocation = Encoding.ASCII.GetString(binaryReader.ReadBytes(264).Where(y => y > 0x00).ToArray()), Position = binaryReader.ReadInt64(), DataLengthA = binaryReader.ReadInt64(), DataLengthB = binaryReader.ReadInt64(), Unk1 = binaryReader.ReadBytes(20), }); long CPos = binaryReader.BaseStream.Position; binaryReader.BaseStream.Position = GDPFiles[x].Position; string extension = Path.GetExtension(GDPFiles[x].ApplyLocation); if (extension != String.Empty) { string dir = Path.GetDirectoryName(GDPFiles[x].ApplyLocation); if (!Directory.Exists(to + dir)) Directory.CreateDirectory(to + dir); using (BinaryWriter binaryWriter = new BinaryWriter(File.Create(to + GDPFiles[x].ApplyLocation))) { long c = GDPFiles[x].DataLengthA; while (c > 0) { if (c > 2147483647) { binaryWriter.Write(binaryReader.ReadBytes(2147483647)); c -= 2147483647; } else { binaryWriter.Write(binaryReader.ReadBytes((int)c)); c = 0; } } } } binaryReader.BaseStream.Position = CPos; } } else { MessageBox.Show($"The file {filePaths[i]} isn't a GDP file"); } } } MessageBox.Show($"Done extracting all GDPs"); } private void CopyBins() { string[] patchDirectories = Directory.GetDirectories(tbDownloadDirectory.Text, "*", SearchOption.TopDirectoryOnly); if (!Directory.Exists($"{tbDownloadDirectory.Text}\\Bins")) { Directory.CreateDirectory($"{tbDownloadDirectory.Text}\\Bins"); } if (patchDirectories.Length > 0) { foreach (string patchDirectory in patchDirectories) { string directoryName = Path.GetFileName(patchDirectory); if (File.Exists($"{patchDirectory}\\Fiesta.bin")) { File.Copy($"{patchDirectory}\\Fiesta.bin", $"{tbDownloadDirectory.Text}\\Bins\\Fiesta.{directoryName}.bin"); } } } } private void CheckPDB() { string binsDirectory = $"{tbDownloadDirectory.Text}\\Bins"; if (Directory.Exists(binsDirectory) && File.Exists($"{binsDirectory}\\ChkMatch.exe")) { string[] binFiles = Directory.GetFiles(binsDirectory, "*.bin", SearchOption.TopDirectoryOnly); if (binFiles.Length > 0) { using (StreamWriter streamWriter = File.AppendText($"{binsDirectory}\\Log.txt")) { foreach (string binFile in binFiles) { string binFileName = Path.GetFileName(binFile); Process process = new Process(); process.StartInfo.WorkingDirectory = binsDirectory; process.StartInfo.FileName = $"{binsDirectory}\\ChkMatch.exe"; process.StartInfo.Arguments = $"-c {binFileName} Fiesta.pdb"; process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardOutput = true; process.Start(); string output = process.StandardOutput.ReadToEnd(); process.WaitForExit(); streamWriter.WriteLine($"Output for {binFileName}"); streamWriter.WriteLine(output); streamWriter.WriteLine(); } } } } } private class GDPFile { public Int64 Type; public string ApplyLocation; public Int64 Position; public Int64 DataLengthA; public Int64 DataLengthB; public byte[] Unk1; } private void cbLocale_SelectedValueChanged(object sender, EventArgs e) { switch (cbLocale.Text) { case "US": _patchListURL = "http://patch.cdn.gamigo.com/fous/gdp/PatchHive.txt"; break; case "DE": case "EN": case "FR": case "ES": _patchListURL = $"http://patch.cdn.gamigo.com/fo/{cbLocale.Text.ToLower()}/PatchHive.txt?"; break; } } } }