diff --git a/.gitmodules b/.gitmodules index 481aa1bbc..84173518f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "submodules/CUE4Parse"] path = submodules/CUE4Parse url = https://github.com/FabianFG/CUE4Parse +[submodule "submodules/UAssetAPI"] + path = submodules/UAssetAPI + url = https://github.com/atenfyr/UAssetAPI diff --git a/.vscode/settings.json b/.vscode/settings.json index 95df9096c..524f1bc4e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -144,6 +144,7 @@ "playerachievements", "playerinfo", "playform", + "Playtest", "pngjs", "POSITIVEX", "POSITIVEY", @@ -197,6 +198,7 @@ "TYPELESS", "uasset", "ubjson", + "uexp", "Unicum", "UNLOCALIZED", "UNORM", diff --git a/package.json b/package.json index d59e296d9..44195650a 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "prunestrings": "cd packages/scripts && bun prunestrings", "dev:cli:unpack": "cd src/BlitzKit.CLI && dotnet run unpack \"C:/Program Files (x86)/Steam/steamapps/common/World of Tanks Blitz Playtest\" --no-overwrite", "mangle": "cd src/BlitzKit.CLI && dotnet run mangle", + "mangle2": "cd src/BlitzKit.CLI && dotnet run mangle2", "api": "cd src/BlitzKit.CLI && dotnet run api", "dev:api": "cd src/BlitzKit.CLI && dotnet watch run api" }, diff --git a/src/BlitzKit.CLI/BlitzKit.CLI.csproj b/src/BlitzKit.CLI/BlitzKit.CLI.csproj index 6ed9c6fa1..564960ff1 100644 --- a/src/BlitzKit.CLI/BlitzKit.CLI.csproj +++ b/src/BlitzKit.CLI/BlitzKit.CLI.csproj @@ -9,6 +9,7 @@ + diff --git a/src/BlitzKit.CLI/Functions/Mangler.cs b/src/BlitzKit.CLI/Functions/Mangler.cs index 0d246788f..141adc326 100644 --- a/src/BlitzKit.CLI/Functions/Mangler.cs +++ b/src/BlitzKit.CLI/Functions/Mangler.cs @@ -218,7 +218,7 @@ namespace BlitzKit.CLI.Functions async Task MangleTank(VFS tankDir) { var pdaName = $"PDA_{tankDir.Name}"; - var pda = provider.LoadObject($"{tankDir.Path}/{pdaName}.{pdaName}"); + var pda = provider.LoadPackageObject($"{tankDir.Path}/{pdaName}.{pdaName}"); var id = pda.Get("TankId").Text; var name = GetString($"TankEntity__{id.ToLowerInvariant()}__Short_Name"); diff --git a/src/BlitzKit.CLI/Functions/Mangler2.cs b/src/BlitzKit.CLI/Functions/Mangler2.cs new file mode 100644 index 000000000..13b867084 --- /dev/null +++ b/src/BlitzKit.CLI/Functions/Mangler2.cs @@ -0,0 +1,21 @@ +using BlitzKit.CLI.Models; +using UAssetAPI; +using UAssetAPI.ExportTypes; +using UAssetAPI.PropertyTypes.Objects; +using UAssetAPI.UnrealTypes; +using UAssetAPI.Unversioned; + +namespace BlitzKit.CLI.Functions +{ + public partial class Mangler2(string[] args) + { + readonly BlitzProvider2 provider = new(); + + public void Mangle() + { + var assetPath = "Blitz/Content/Tanks/USSR/R45_IS_7/PDA_R45_IS_7"; + + Console.WriteLine(provider.Asset(assetPath)); + } + } +} diff --git a/src/BlitzKit.CLI/Functions/Unpacker.cs b/src/BlitzKit.CLI/Functions/Unpacker.cs index 117ce8137..379a16cea 100644 --- a/src/BlitzKit.CLI/Functions/Unpacker.cs +++ b/src/BlitzKit.CLI/Functions/Unpacker.cs @@ -28,11 +28,12 @@ namespace BlitzKit.CLI.Functions DefaultFileProvider provider0 = new( directory: new DirectoryInfo(pak0Path), searchOption: SearchOption.TopDirectoryOnly, - versions: new(EGame.GAME_UE5_3) + versions: new(EGame.GAME_UE5_3), + pathComparer: StringComparer.OrdinalIgnoreCase ); provider0.Initialize(); provider0.Mount(); - provider0.TryFindGameFile("Blitz/Config/DefaultDlc.ini", out var defaultDlcGameFile); + provider0.TryGetGameFile("Blitz/Config/DefaultDlc.ini", out var defaultDlcGameFile); if (defaultDlcGameFile is not FPakEntry) throw new Exception("Failed to find DefaultDlc.ini"); diff --git a/src/BlitzKit.CLI/Models/BlitzProvider.cs b/src/BlitzKit.CLI/Models/BlitzProvider.cs index a068aab72..685081126 100644 --- a/src/BlitzKit.CLI/Models/BlitzProvider.cs +++ b/src/BlitzKit.CLI/Models/BlitzProvider.cs @@ -21,7 +21,8 @@ namespace BlitzKit.CLI.Models directory: new DirectoryInfo(depot ? DEPOT_CONTAINERS_PATH : LOCAL_BUNDLED_CONTAINERS_PATH), extraDirectories: depot ? [] : [new(LOCAL_DLC_CONTAINERS_PATH)], searchOption: SearchOption.TopDirectoryOnly, - versions: new(EGame.GAME_UE5_3) + versions: new(EGame.GAME_UE5_3), + pathComparer: StringComparer.OrdinalIgnoreCase ) { RootDirectory = new() diff --git a/src/BlitzKit.CLI/Models/BlitzProvider2.cs b/src/BlitzKit.CLI/Models/BlitzProvider2.cs new file mode 100644 index 000000000..4883e2f25 --- /dev/null +++ b/src/BlitzKit.CLI/Models/BlitzProvider2.cs @@ -0,0 +1,92 @@ +using System.Text.Json; +using Org.BouncyCastle.Tls.Crypto.Impl.BC; +using UAssetAPI; +using UAssetAPI.UnrealTypes; +using UAssetAPI.Unversioned; + +namespace BlitzKit.CLI.Models +{ + public class BlitzProvider2 : IDisposable + { + readonly EngineVersion Version = EngineVersion.VER_UE5_3; + + readonly string BUNDLED_CONTAINERS_DIR = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), + "Steam", + "steamapps", + "common", + "World of Tanks Blitz Playtest", + "Blitz", + "Content", + "Paks" + ); + readonly string DLC_CONTAINERS_DIR = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), + "Blitz", + "Saved", + "PersistentDownloadDir", + "Dlc", + "PakCache" + ); + readonly Usmap Map = new("../../submodules/blitzkit-closed/blitz.usmap"); + + readonly Dictionary FileMap = []; + readonly List Readers = []; + + public BlitzProvider2() + { + var containers = new List( + Directory.GetFiles(BUNDLED_CONTAINERS_DIR, "*.pak", SearchOption.TopDirectoryOnly) + ); + + var localManifest = + JsonSerializer.Deserialize( + File.ReadAllText(Path.Combine(DLC_CONTAINERS_DIR, "LocalManifest.json")) + ) ?? throw new Exception("Failed to deserialize LocalManifest.json"); + + containers.AddRange( + localManifest.PakFiles.Keys.Select(file => Path.Combine(DLC_CONTAINERS_DIR, file)) + ); + + foreach (string container in containers) + { + using var stream = File.OpenRead(container); + var reader = + new PakBuilder().Reader(stream) ?? throw new Exception("Failed to create PakReader"); + + Readers.Add(reader); + + foreach (var file in reader.Files()) + { + FileMap[file] = (reader, stream); + } + } + } + + public UAsset Asset(string path) + { + var assetPath = $"{path}.uasset"; + var expPath = $"{path}.uexp"; + + var (reader, stream) = FileMap[assetPath]; + + byte[] assetBytes = reader.Get(stream, assetPath); + byte[] uexpBytes = reader.Get(stream, expPath); + + MemoryStream assetStream = new([.. assetBytes, .. uexpBytes]); + AssetBinaryReader assetReader = new(assetStream); + + return new(assetReader, Version, Map); + } + + public void Dispose() + { + foreach (var reader in Readers) + { + reader.Dispose(); + } + + GC.SuppressFinalize(this); + } + } +} diff --git a/src/BlitzKit.CLI/Models/MonoGltf.cs b/src/BlitzKit.CLI/Models/MonoGltf.cs index 85e9da58a..3bc9f4dc8 100644 --- a/src/BlitzKit.CLI/Models/MonoGltf.cs +++ b/src/BlitzKit.CLI/Models/MonoGltf.cs @@ -254,14 +254,14 @@ namespace BlitzKit.CLI.Models int[] indices ) { - var uvs1 = new List() { vert1.UV }; - var uvs2 = new List() { vert2.UV }; - var uvs3 = new List() { vert3.UV }; + var uvs1 = new List() { (Vector2)vert1.UV }; + var uvs2 = new List() { (Vector2)vert2.UV }; + var uvs3 = new List() { (Vector2)vert3.UV }; foreach (var uv in uvs) { - uvs1.Add(uv[indices[0]]); - uvs2.Add(uv[indices[1]]); - uvs3.Add(uv[indices[2]]); + uvs1.Add((Vector2)uv[indices[0]]); + uvs2.Add((Vector2)uv[indices[1]]); + uvs3.Add((Vector2)uv[indices[2]]); } return (uvs1, uvs2, uvs3); diff --git a/src/BlitzKit.CLI/Program.cs b/src/BlitzKit.CLI/Program.cs index 41af977f4..fb6c871bf 100644 --- a/src/BlitzKit.CLI/Program.cs +++ b/src/BlitzKit.CLI/Program.cs @@ -16,16 +16,23 @@ namespace BlitzKit.CLI switch (args[0]) { - case "unpack": - { - await Unpacker.Unpack(args); - break; - } + // case "unpack": + // { + // await Unpacker.Unpack(args); + // break; + // } - case "mangle": + // case "mangle": + // { + // Mangler mangler = new(args); + // await mangler.Mangle(); + // break; + // } + + case "mangle2": { - Mangler mangler = new(args); - await mangler.Mangle(); + Mangler2 mangler2 = new(args); + mangler2.Mangle(); break; } diff --git a/src/BlitzKit.CLI/repak_bind.dll b/src/BlitzKit.CLI/repak_bind.dll new file mode 100644 index 000000000..3e015f3e7 Binary files /dev/null and b/src/BlitzKit.CLI/repak_bind.dll differ diff --git a/submodules/CUE4Parse b/submodules/CUE4Parse index 624e07c8c..920dc1682 160000 --- a/submodules/CUE4Parse +++ b/submodules/CUE4Parse @@ -1 +1 @@ -Subproject commit 624e07c8c396724b3ae72d4e1e2854fdc5269e24 +Subproject commit 920dc1682278d70ee738383b6fbd3a1e9b7523ea diff --git a/submodules/UAssetAPI b/submodules/UAssetAPI new file mode 160000 index 000000000..c380bf3d6 --- /dev/null +++ b/submodules/UAssetAPI @@ -0,0 +1 @@ +Subproject commit c380bf3d6d7b5e4b913459c9111774cbbec05a16