diff --git a/src/CLI/Functions/Unpacker.cs b/src/CLI/Functions/Unpacker.cs index 9f7bd605b..21ff85462 100644 --- a/src/CLI/Functions/Unpacker.cs +++ b/src/CLI/Functions/Unpacker.cs @@ -1,19 +1,23 @@ +using System.Text.Json; +using CLI.Models; using CLI.Utils; using CUE4Parse.FileProvider.Objects; using CUE4Parse.UE4.Pak; namespace CLI.Functions { - class Unpacker + public static class Unpacker { - private const string contentGroup = "p14y73c7_p5e_b10gg3RS_big_play"; - private const string vfs = "../../temp/vfs/"; + private const string CONTENT_GROUP = "p14y73c7_p5e_b10gg3RS_big_play"; + private const string VFS_PATH = "../../temp/vfs/"; // this may be different from the one provided in args so check this and not args[1] // we don't wanna delete my local installation of the game when debugging haha! - public static string tempDepotsDir = "../../temp/depot/"; + private const string TEMP_DEPOT_DIR = "../../temp/depot/"; + private const string WG_DLC_DOMAIN = "http://dl-wotblitz-gc.wargaming.net"; + private const string BUILD_MANIFEST_OS = "Windows"; - public static void Unpack(string[] args) + public static async Task Unpack(string[] args) { if (args.Length < 2) { @@ -23,12 +27,12 @@ public static void Unpack(string[] args) AgnosticZlibHelper.Initialize(); UnpackDepot(args[1]); - UnpackDLC(); + await UnpackDLC(); } - private static void UnpackDLC() + private static async Task UnpackDLC() { - string defaultDlcPath = Path.Combine(vfs, "Blitz/Config/DefaultDlc.ini"); + string defaultDlcPath = Path.Combine(VFS_PATH, "Blitz/Config/DefaultDlc.ini"); IniParser iniParser = new(defaultDlcPath); string? contentBuildId = iniParser.GetString("DefaultContentBuildId"); @@ -37,7 +41,32 @@ private static void UnpackDLC() throw new Exception("Failed to read content build id from DefaultDlc.ini"); } - Console.WriteLine($"Exploring DLC {contentBuildId} within group {contentGroup}"); + Console.WriteLine($"Exploring DLC {contentBuildId} within group {CONTENT_GROUP}"); + + using HttpClient httpClient = new(); + DlcManifest manifest = await FetchManifest(CONTENT_GROUP, contentBuildId); + + foreach (var pakFile in manifest.PakFiles) + { + Console.WriteLine($"{pakFile.FileName} downloading exergy..."); + + string url = $"{WG_DLC_DOMAIN}/dlc/{CONTENT_GROUP}/dlc/{pakFile.RelativeUrl}"; + + // TODO: load to memory and write exergy to disk + } + } + + public static async Task FetchManifest(string group, string build) + { + string url = + $"{WG_DLC_DOMAIN}/dlc/{group}/dlc/BuildManifest-{BUILD_MANIFEST_OS}-{build}.json"; + using HttpClient client = new(); + string jsonString = await client.GetStringAsync(url); + DlcManifest manifest = + JsonSerializer.Deserialize(jsonString) + ?? throw new Exception("Failed to deserialize manifest"); + + return manifest; } private static void UnpackDepot(string workingDirectory) @@ -50,10 +79,10 @@ private static void UnpackDepot(string workingDirectory) Exergy(container); } - if (Directory.Exists(tempDepotsDir)) + if (Directory.Exists(TEMP_DEPOT_DIR)) { Console.WriteLine("Deleting temp depots directory..."); - Directory.Delete(tempDepotsDir, true); + Directory.Delete(TEMP_DEPOT_DIR, true); } } @@ -75,7 +104,7 @@ private static void Exergy(string container) continue; } - string writePath = Path.Combine(vfs, gameFile.Path); + string writePath = Path.Combine(VFS_PATH, gameFile.Path); if (File.Exists(writePath)) { diff --git a/src/CLI/Models/DLCManifest.cs b/src/CLI/Models/DLCManifest.cs new file mode 100644 index 000000000..272eb1109 --- /dev/null +++ b/src/CLI/Models/DLCManifest.cs @@ -0,0 +1,61 @@ +using System.Text.Json.Serialization; + +namespace CLI.Models +{ + public partial class DlcManifest + { + [JsonPropertyName("contentBuildId")] + public string ContentBuildId { get; set; } + + [JsonPropertyName("pakFiles")] + public List PakFiles { get; set; } + + [JsonPropertyName("chunkTags")] + public Dictionary ChunkTags { get; set; } + + [JsonPropertyName("chunkDependencies")] + public List ChunkDependencies { get; set; } + } + + public partial class ChunkDependency + { + [JsonPropertyName("chunkId")] + public long ChunkId { get; set; } + + [JsonPropertyName("parentChunkId")] + public long ParentChunkId { get; set; } + } + + public partial class ChunkTag + { + [JsonPropertyName("gameplayTags")] + public List GameplayTags { get; set; } + } + + public partial class GameplayTag + { + [JsonPropertyName("tagName")] + public string TagName { get; set; } + } + + public partial class PakFile + { + [JsonPropertyName("fileName")] + public string FileName { get; set; } + + [JsonPropertyName("fileSize")] + public long FileSize { get; set; } + + [JsonPropertyName("fileVersion")] + public string FileVersion { get; set; } + + [JsonPropertyName("chunkId")] + public long ChunkId { get; set; } + + [JsonPropertyName("relativeUrl")] + public string RelativeUrl { get; set; } + + [JsonPropertyName("availabilityMask")] + public long AvailabilityMask { get; set; } + } +} diff --git a/src/CLI/Program.cs b/src/CLI/Program.cs index cb70fa3af..59ab12a15 100644 --- a/src/CLI/Program.cs +++ b/src/CLI/Program.cs @@ -4,13 +4,13 @@ namespace CLI { class Program { - static void Main(string[] args) + static async Task Main(string[] args) { switch (args[0]) { case "unpack": { - Unpacker.Unpack(args); + await Unpacker.Unpack(args); break; } diff --git a/src/CLI/Utils/AgnosticZlibHelper.cs b/src/CLI/Utils/AgnosticZlibHelper.cs index 4c3519be8..64a21ef35 100644 --- a/src/CLI/Utils/AgnosticZlibHelper.cs +++ b/src/CLI/Utils/AgnosticZlibHelper.cs @@ -5,8 +5,8 @@ namespace CLI.Utils { public static class AgnosticZlibHelper { - public const string ZlibRootPath = "../../temp/"; - public const string ZlibBinariesPrefix = + public const string ZLIB_BINARY_DIR = "../../temp/"; + public const string ZLIB_BINARY_URL_PREFIX = "https://github.com/NotOfficer/Zlib-ng.NET/releases/download/1.0.0"; public static void Initialize() @@ -16,12 +16,12 @@ public static void Initialize() if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - binariesUrl = $"{ZlibBinariesPrefix}/zlib-ng2.dll"; + binariesUrl = $"{ZLIB_BINARY_URL_PREFIX}/zlib-ng2.dll"; fileExtension = "dll"; } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { - binariesUrl = $"{ZlibBinariesPrefix}/libz-ng.so"; + binariesUrl = $"{ZLIB_BINARY_URL_PREFIX}/libz-ng.so"; fileExtension = "so"; } else @@ -30,7 +30,7 @@ public static void Initialize() } string fileName = $"zlib.{fileExtension}"; - string filePath = Path.Combine(ZlibRootPath, fileName); + string filePath = Path.Combine(ZLIB_BINARY_DIR, fileName); if (File.Exists(filePath)) {