diff --git a/AssetStudio/AssetsHelper.cs b/AssetStudio/AssetsHelper.cs index 811b765..37ac488 100644 --- a/AssetStudio/AssetsHelper.cs +++ b/AssetStudio/AssetsHelper.cs @@ -16,23 +16,17 @@ namespace AssetStudio public const string CABMapName = "Maps"; public static CancellationTokenSource tokenSource = new CancellationTokenSource(); - public static AssetsManager assetsManager = new AssetsManager() { Silent = true, SkipProcess = true, ResolveDependencies = false }; - public static string BaseFolder = ""; - public static Dictionary CABMap = new Dictionary(StringComparer.OrdinalIgnoreCase); - public static Dictionary> Offsets = new Dictionary>(); + private static string BaseFolder = ""; + private static Dictionary CABMap = new Dictionary(StringComparer.OrdinalIgnoreCase); + private static Dictionary> Offsets = new Dictionary>(); + private static AssetsManager assetsManager = new AssetsManager() { Silent = true, SkipProcess = true, ResolveDependencies = false }; - public static void Clear() + public record Entry { - CABMap.Clear(); - Offsets.Clear(); - BaseFolder = ""; - - tokenSource.Dispose(); - tokenSource = new CancellationTokenSource(); - - GC.WaitForPendingFinalizers(); - GC.Collect(); + public string Path { get; set; } + public long Offset { get; set; } + public string[] Dependencies { get; set; } } public static string[] GetMaps() @@ -42,12 +36,57 @@ namespace AssetStudio return files.Select(x => Path.GetFileNameWithoutExtension(x)).ToArray(); } + public static void Clear() + { + CABMap.Clear(); + Offsets.Clear(); + BaseFolder = string.Empty; + + tokenSource.Dispose(); + tokenSource = new CancellationTokenSource(); + + GC.WaitForPendingFinalizers(); + GC.Collect(); + } + + public static void ClearOffsets() => Offsets.Clear(); + + public static void Remove(string path) => Offsets.Remove(path); + + public static bool TryAdd(string name, out string path) + { + if (CABMap.TryGetValue(name, out var entry)) + { + path = Path.Combine(BaseFolder, entry.Path); + if (!Offsets.ContainsKey(path)) + { + Offsets.Add(path, new HashSet()); + } + Offsets[path].Add(entry.Offset); + return true; + } + path = string.Empty; + return false; + } + + public static bool TryGet(string path, out long[] offsets) + { + if (Offsets.TryGetValue(path, out var list)) + { + offsets = list.ToArray(); + return true; + } + offsets = Array.Empty(); + return false; + } + public static void BuildCABMap(string[] files, string mapName, string baseFolder, Game game) { Logger.Info($"Processing..."); try { CABMap.Clear(); + var collision = 0; BaseFolder = baseFolder; assetsManager.Game = game; for (int i = 0; i < files.Length; i++) @@ -72,8 +111,11 @@ namespace AssetStudio Dependencies = dependencies }; - CABMap.TryAdd(assetsFile.fileName, new()); - CABMap[assetsFile.fileName] = entry; + if (CABMap.ContainsKey(assetsFile.fileName)) + { + collision++; + } + CABMap.Add(assetsFile.fileName, entry); } Logger.Info($"Processed {Path.GetFileName(file)}"); } @@ -81,11 +123,11 @@ namespace AssetStudio } CABMap = CABMap.OrderBy(pair => pair.Key).ToDictionary(pair => pair.Key, pair => pair.Value, StringComparer.OrdinalIgnoreCase); - var outputFile = new FileInfo(Path.Combine(CABMapName, $"{mapName}.bin")); + var outputFile = Path.Combine(CABMapName, $"{mapName}.bin"); - outputFile.Directory.Create(); + Directory.CreateDirectory(Path.GetDirectoryName(outputFile)); - using (var binaryFile = outputFile.Create()) + using (var binaryFile = File.OpenWrite(outputFile)) using (var writer = new BinaryWriter(binaryFile)) { writer.Write(BaseFolder); @@ -103,11 +145,11 @@ namespace AssetStudio } } - Logger.Info($"CABMap build successfully !!"); + Logger.Info($"CABMap build successfully !! {collision} collisions found"); } catch (Exception e) { - Logger.Warning($"CABMap was not build, {e.Message}{e.StackTrace}"); + Logger.Warning($"CABMap was not build, {e}"); } } @@ -147,7 +189,7 @@ namespace AssetStudio } catch (Exception e) { - Logger.Warning($"{mapName} was not loaded, {e.Message}"); + Logger.Warning($"{mapName} was not loaded, {e}"); } } @@ -357,80 +399,5 @@ namespace AssetStudio Logger.Info($"AssetMap build successfully !!"); }); } - - public static void AddCABOffsets(string[] path, List cabs) - { - for (int i = 0; i < cabs.Count; i++) - { - var cab = cabs[i]; - if (CABMap.TryGetValue(cab, out var entry)) - { - if (!path.Contains(entry.Path)) - { - var fullPath = Path.Combine(BaseFolder, entry.Path); - if (!Offsets.ContainsKey(fullPath)) - { - Offsets.Add(fullPath, new HashSet()); - } - Offsets[fullPath].Add(entry.Offset); - } - foreach (var dep in entry.Dependencies) - { - if (!cabs.Contains(dep)) - cabs.Add(dep); - } - } - } - } - - public static bool FindCAB(string path, out List cabs) - { - cabs = new List(); - var relativePath = Path.GetRelativePath(BaseFolder, path); - foreach (var kv in CABMap) - { - if (kv.Value.Path.Equals(relativePath)) - { - cabs.Add(kv.Key); - } - } - return cabs.Count != 0; - } - - public static string[] ProcessFiles(string[] files) - { - foreach (var file in files) - { - if (!Offsets.ContainsKey(file)) - { - Offsets.Add(file, new HashSet()); - } - if (FindCAB(file, out var cabs)) - { - AddCABOffsets(files, cabs); - } - } - return Offsets.Keys.ToArray(); - } - - public static string[] ProcessDependencies(string[] files) - { - if (CABMap.Count == 0) - { - Logger.Warning("CABMap is not build, skip resolving dependencies..."); - } - else - { - Logger.Info("Resolving Dependencies..."); - files = ProcessFiles(files); - } - return files; - } - public record Entry - { - public string Path { get; set; } - public long Offset { get; set; } - public string[] Dependencies { get; set; } - } } } diff --git a/AssetStudio/AssetsManager.cs b/AssetStudio/AssetsManager.cs index f7e5881..56f2db0 100644 --- a/AssetStudio/AssetsManager.cs +++ b/AssetStudio/AssetsManager.cs @@ -39,8 +39,6 @@ namespace AssetStudio var path = Path.GetDirectoryName(Path.GetFullPath(files[0])); MergeSplitAssets(path); var toReadFile = ProcessingSplitFiles(files.ToList()); - if (ResolveDependencies) - toReadFile = AssetsHelper.ProcessDependencies(toReadFile); Load(toReadFile); if (Silent) @@ -95,6 +93,7 @@ namespace AssetStudio importFilesHash.Clear(); noexistFiles.Clear(); assetsFileListHash.Clear(); + AssetsHelper.ClearOffsets(); if (!SkipProcess && !tokenSource.IsCancellationRequested) { @@ -138,9 +137,6 @@ namespace AssetStudio case FileType.BlkFile: LoadBlkFile(reader); break; - case FileType.Mhy0File: - LoadMhy0File(reader); - break; } } @@ -218,6 +214,38 @@ namespace AssetStudio CheckStrippedVersion(assetsFile); assetsFileList.Add(assetsFile); assetsFileListHash.Add(assetsFile.fileName); + + if (ResolveDependencies) + { + foreach (var sharedFile in assetsFile.m_Externals) + { + var sharedFileName = sharedFile.fileName; + + if (!importFilesHash.Contains(sharedFileName)) + { + var sharedFilePath = Path.Combine(Path.GetDirectoryName(originalPath), sharedFileName); + if (!noexistFiles.Contains(sharedFilePath)) + { + if (AssetsHelper.TryAdd(sharedFileName, out var path)) + { + sharedFilePath = path; + } + if (File.Exists(sharedFilePath)) + { + if (!importFiles.Contains(sharedFilePath)) + { + importFiles.Add(sharedFilePath); + } + importFilesHash.Add(sharedFileName); + } + else + { + noexistFiles.Add(sharedFilePath); + } + } + } + } + } } catch (Exception e) { @@ -409,9 +437,8 @@ namespace AssetStudio Logger.Info("Loading " + reader.FullPath); try { - var offsets = AssetsHelper.Offsets.TryGetValue(reader.FullPath, out var list) ? list.ToArray() : Array.Empty(); using var stream = new BlockStream(reader.BaseStream, 0); - if (!offsets.IsNullOrEmpty()) + if (AssetsHelper.TryGet(reader.FullPath, out var offsets)) { foreach (var offset in offsets) { @@ -420,6 +447,7 @@ namespace AssetStudio var subReader = new FileReader(dummyPath, stream, true); LoadBundleFile(subReader, reader.FullPath, offset); } + AssetsHelper.Remove(reader.FullPath); } else { @@ -446,9 +474,8 @@ namespace AssetStudio Logger.Info("Loading " + reader.FullPath); try { - var offsets = AssetsHelper.Offsets.TryGetValue(reader.FullPath, out var list) ? list.ToArray() : Array.Empty(); using var stream = BlkUtils.Decrypt(reader, (Blk)Game); - if (!offsets.IsNullOrEmpty()) + if (AssetsHelper.TryGet(reader.FullPath, out var offsets)) { foreach (var offset in offsets) { @@ -465,6 +492,7 @@ namespace AssetStudio break; } } + AssetsHelper.Remove(reader.FullPath); } else { diff --git a/AssetStudioGUI/AssetStudioGUIForm.cs b/AssetStudioGUI/AssetStudioGUIForm.cs index 64328c1..70f64c6 100644 --- a/AssetStudioGUI/AssetStudioGUIForm.cs +++ b/AssetStudioGUI/AssetStudioGUIForm.cs @@ -193,6 +193,7 @@ namespace AssetStudioGUI ResetForm(); openDirectoryBackup = Path.GetDirectoryName(openFileDialog1.FileNames[0]); assetsManager.SpecifyUnityVersion = specifyUnityVersion.Text; + assetsManager.Game = Studio.Game; await Task.Run(() => assetsManager.LoadFiles(openFileDialog1.FileNames)); BuildAssetStructures(); } @@ -1933,6 +1934,8 @@ namespace AssetStudioGUI { ResetForm(); AssetsHelper.Clear(); + assetsManager.SpecifyUnityVersion = specifyUnityVersion.Text; + assetsManager.Game = Studio.Game; } private void enableConsole_CheckedChanged(object sender, EventArgs e)