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