- WIP Asset Browser.
- fix for some modes without textures [`SR`] - AssetMap new mode (Minimal/Full).
This commit is contained in:
@@ -1,11 +0,0 @@
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class AssetEntry
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Container { get; set; }
|
||||
public string Source { get; set; }
|
||||
public long PathID { get; set; }
|
||||
public ClassIDType Type { get; set; }
|
||||
}
|
||||
}
|
||||
38
AssetStudio/AssetIndex.cs
Normal file
38
AssetStudio/AssetIndex.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public record AssetIndex
|
||||
{
|
||||
public Dictionary<string, string> Types { get; set; }
|
||||
public record SubAssetInfo
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public byte PathHashPre { get; set; }
|
||||
public uint PathHashLast { get; set; }
|
||||
}
|
||||
public Dictionary<int, List<SubAssetInfo>> SubAssets { get; set; }
|
||||
public Dictionary<int, List<int>> Dependencies { get; set; }
|
||||
public List<uint> PreloadBlocks { get; set; }
|
||||
public List<uint> PreloadShaderBlocks { get; set; }
|
||||
public record BlockInfo
|
||||
{
|
||||
public byte Language { get; set; }
|
||||
public uint Id { get; set; }
|
||||
public uint Offset { get; set; }
|
||||
}
|
||||
public Dictionary<int, BlockInfo> Assets { get; set; }
|
||||
public List<uint> SortList { get; set; }
|
||||
|
||||
public AssetIndex()
|
||||
{
|
||||
Types = new Dictionary<string, string>();
|
||||
SubAssets = new Dictionary<int, List<SubAssetInfo>>();
|
||||
Dependencies = new Dictionary<int, List<int>>();
|
||||
PreloadBlocks = new List<uint>();
|
||||
PreloadShaderBlocks = new List<uint>();
|
||||
Assets = new Dictionary<int, BlockInfo>();
|
||||
SortList = new List<uint>();
|
||||
}
|
||||
}
|
||||
}
|
||||
35
AssetStudio/AssetMap.cs
Normal file
35
AssetStudio/AssetMap.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using MessagePack;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
[MessagePackObject]
|
||||
public record AssetMap
|
||||
{
|
||||
[Key(0)]
|
||||
public GameType GameType { get; set; }
|
||||
[Key(1)]
|
||||
public AssetEntry[] AssetEntries { get; set; }
|
||||
}
|
||||
[MessagePackObject]
|
||||
public record AssetEntry
|
||||
{
|
||||
[Key(0)]
|
||||
public string Name { get; set; }
|
||||
[Key(1)]
|
||||
public string Container { get; set; }
|
||||
[Key(2)]
|
||||
public string Source { get; set; }
|
||||
[Key(3)]
|
||||
public long PathID { get; set; }
|
||||
[Key(4)]
|
||||
public ClassIDType Type { get; set; }
|
||||
|
||||
public bool Matches(Regex regex) => regex.IsMatch(Name)
|
||||
|| regex.IsMatch(Container)
|
||||
|| regex.IsMatch(Source)
|
||||
|| regex.IsMatch(PathID.ToString())
|
||||
|| regex.IsMatch(Type.ToString());
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="K4os.Compression.LZ4" Version="1.3.4-beta" />
|
||||
<PackageReference Include="MessagePack" Version="2.5.108" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ using Newtonsoft.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml;
|
||||
using System.Text;
|
||||
using MessagePack;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
@@ -16,6 +17,7 @@ namespace AssetStudio
|
||||
{
|
||||
public const string MapName = "Maps";
|
||||
|
||||
public static bool Minimal = true;
|
||||
public static CancellationTokenSource tokenSource = new CancellationTokenSource();
|
||||
|
||||
private static string BaseFolder = "";
|
||||
@@ -34,7 +36,7 @@ namespace AssetStudio
|
||||
{
|
||||
Directory.CreateDirectory(MapName);
|
||||
var files = Directory.GetFiles(MapName, "*.bin", SearchOption.TopDirectoryOnly);
|
||||
return files.Select(x => Path.GetFileNameWithoutExtension(x)).ToArray();
|
||||
return files.Select(Path.GetFileNameWithoutExtension).ToArray();
|
||||
}
|
||||
|
||||
public static void Clear()
|
||||
@@ -132,12 +134,11 @@ namespace AssetStudio
|
||||
Logger.Info("Building CABMap has been cancelled !!");
|
||||
return;
|
||||
}
|
||||
var dependencies = assetsFile.m_Externals.Select(x => x.fileName).ToArray();
|
||||
var entry = new Entry()
|
||||
{
|
||||
Path = relativePath,
|
||||
Offset = assetsFile.offset,
|
||||
Dependencies = dependencies
|
||||
Dependencies = assetsFile.m_Externals.Select(x => x.fileName).ToArray()
|
||||
};
|
||||
|
||||
if (CABMap.ContainsKey(assetsFile.fileName))
|
||||
@@ -192,17 +193,16 @@ namespace AssetStudio
|
||||
var path = reader.ReadString();
|
||||
var offset = reader.ReadInt64();
|
||||
var depCount = reader.ReadInt32();
|
||||
var dependencies = new List<string>();
|
||||
var dependencies = new string[depCount];
|
||||
for (int j = 0; j < depCount; j++)
|
||||
{
|
||||
var dependancy = reader.ReadString();
|
||||
dependencies.Add(dependancy);
|
||||
dependencies[j] = reader.ReadString();
|
||||
}
|
||||
var entry = new Entry()
|
||||
{
|
||||
Path = path,
|
||||
Offset = offset,
|
||||
Dependencies = dependencies.ToArray()
|
||||
Dependencies = dependencies
|
||||
};
|
||||
CABMap.Add(cab, entry);
|
||||
}
|
||||
@@ -230,7 +230,7 @@ namespace AssetStudio
|
||||
|
||||
UpdateContainers(assets, game);
|
||||
|
||||
ExportAssetsMap(assets.ToArray(), mapName, savePath, exportListType, resetEvent);
|
||||
ExportAssetsMap(assets.ToArray(), game, mapName, savePath, exportListType, resetEvent);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
@@ -283,13 +283,13 @@ namespace AssetStudio
|
||||
}
|
||||
obj = null;
|
||||
asset.Name = assetBundle.m_Name;
|
||||
exportable = false;
|
||||
exportable = !Minimal;
|
||||
break;
|
||||
case ClassIDType.GameObject:
|
||||
var gameObject = new GameObject(objectReader);
|
||||
obj = gameObject;
|
||||
asset.Name = gameObject.m_Name;
|
||||
exportable = false;
|
||||
exportable = !Minimal;
|
||||
break;
|
||||
case ClassIDType.Shader when Shader.Parsable:
|
||||
asset.Name = objectReader.ReadAlignedString();
|
||||
@@ -306,7 +306,6 @@ namespace AssetStudio
|
||||
case ClassIDType.MiHoYoBinData:
|
||||
var MiHoYoBinData = new MiHoYoBinData(objectReader);
|
||||
obj = MiHoYoBinData;
|
||||
exportable = true;
|
||||
break;
|
||||
case ClassIDType.IndexObject:
|
||||
var indexObject = new IndexObject(objectReader);
|
||||
@@ -316,6 +315,7 @@ namespace AssetStudio
|
||||
mihoyoBinDataNames.Add((index.Value.Object, index.Key));
|
||||
}
|
||||
asset.Name = "IndexObject";
|
||||
exportable = !Minimal;
|
||||
break;
|
||||
case ClassIDType.Font:
|
||||
case ClassIDType.Material:
|
||||
@@ -329,7 +329,8 @@ namespace AssetStudio
|
||||
asset.Name = objectReader.ReadAlignedString();
|
||||
break;
|
||||
default:
|
||||
exportable = false;
|
||||
asset.Name = objectReader.type.ToString();
|
||||
exportable = !Minimal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -428,7 +429,7 @@ namespace AssetStudio
|
||||
}
|
||||
}
|
||||
|
||||
private static void ExportAssetsMap(AssetEntry[] toExportAssets, string name, string savePath, ExportListType exportListType, ManualResetEvent resetEvent = null)
|
||||
private static void ExportAssetsMap(AssetEntry[] toExportAssets, Game game, string name, string savePath, ExportListType exportListType, ManualResetEvent resetEvent = null)
|
||||
{
|
||||
ThreadPool.QueueUserWorkItem(state =>
|
||||
{
|
||||
@@ -436,13 +437,12 @@ namespace AssetStudio
|
||||
|
||||
Progress.Reset();
|
||||
|
||||
string filename;
|
||||
string filename = Path.Combine(savePath, $"{name}{exportListType.GetExtension()}");
|
||||
switch (exportListType)
|
||||
{
|
||||
case ExportListType.XML:
|
||||
filename = Path.Combine(savePath, $"{name}.xml");
|
||||
var settings = new XmlWriterSettings() { Indent = true };
|
||||
using (XmlWriter writer = XmlWriter.Create(filename, settings))
|
||||
var xmlSettings = new XmlWriterSettings() { Indent = true };
|
||||
using (XmlWriter writer = XmlWriter.Create(filename, xmlSettings))
|
||||
{
|
||||
writer.WriteStartDocument();
|
||||
writer.WriteStartElement("Assets");
|
||||
@@ -466,7 +466,6 @@ namespace AssetStudio
|
||||
}
|
||||
break;
|
||||
case ExportListType.JSON:
|
||||
filename = Path.Combine(savePath, $"{name}.json");
|
||||
using (StreamWriter file = File.CreateText(filename))
|
||||
{
|
||||
var serializer = new JsonSerializer() { Formatting = Newtonsoft.Json.Formatting.Indented };
|
||||
@@ -474,10 +473,20 @@ namespace AssetStudio
|
||||
serializer.Serialize(file, toExportAssets);
|
||||
}
|
||||
break;
|
||||
case ExportListType.MessagePack:
|
||||
using (var file = File.Create(filename))
|
||||
{
|
||||
var assetMap = new AssetMap
|
||||
{
|
||||
GameType = game.Type,
|
||||
AssetEntries = toExportAssets
|
||||
};
|
||||
MessagePackSerializer.Serialize(file, assetMap, MessagePackSerializerOptions.Standard.WithCompression(MessagePackCompression.Lz4BlockArray));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Logger.Info($"Finished exporting asset list with {toExportAssets.Length} items.");
|
||||
Logger.Info($"AssetMap build successfully !!");
|
||||
Logger.Info($"Finished buidling AssetMap with {toExportAssets.Length} assets.");
|
||||
|
||||
resetEvent?.Set();
|
||||
});
|
||||
@@ -501,7 +510,7 @@ namespace AssetStudio
|
||||
DumpCABMap(mapName);
|
||||
|
||||
Logger.Info($"Map build successfully !! {collision} collisions found");
|
||||
ExportAssetsMap(assets.ToArray(), mapName, savePath, exportListType, resetEvent);
|
||||
ExportAssetsMap(assets.ToArray(), game, mapName, savePath, exportListType, resetEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
public enum ExportListType
|
||||
{
|
||||
XML,
|
||||
JSON
|
||||
JSON,
|
||||
MessagePack
|
||||
}
|
||||
|
||||
public static class ExportListTypeExtensions
|
||||
@@ -12,6 +13,7 @@
|
||||
{
|
||||
ExportListType.XML => ".xml",
|
||||
ExportListType.JSON => ".json",
|
||||
ExportListType.MessagePack => ".map",
|
||||
_ => throw new System.NotImplementedException(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
@@ -86,38 +85,4 @@ namespace AssetStudio
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public record AssetIndex
|
||||
{
|
||||
public Dictionary<string, string> Types { get; set; }
|
||||
public record SubAssetInfo
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public byte PathHashPre { get; set; }
|
||||
public uint PathHashLast { get; set; }
|
||||
}
|
||||
public Dictionary<int, List<SubAssetInfo>> SubAssets { get; set; }
|
||||
public Dictionary<int, List<int>> Dependencies { get; set; }
|
||||
public List<uint> PreloadBlocks { get; set; }
|
||||
public List<uint> PreloadShaderBlocks { get; set; }
|
||||
public record BlockInfo
|
||||
{
|
||||
public byte Language { get; set; }
|
||||
public uint Id { get; set; }
|
||||
public uint Offset { get; set; }
|
||||
}
|
||||
public Dictionary<int, BlockInfo> Assets { get; set; }
|
||||
public List<uint> SortList { get; set; }
|
||||
|
||||
public AssetIndex()
|
||||
{
|
||||
Types = new Dictionary<string, string>();
|
||||
SubAssets = new Dictionary<int, List<SubAssetInfo>>();
|
||||
Dependencies = new Dictionary<int, List<int>>();
|
||||
PreloadBlocks = new List<uint>();
|
||||
PreloadShaderBlocks = new List<uint>();
|
||||
Assets = new Dictionary<int, BlockInfo>();
|
||||
SortList = new List<uint>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
37
AssetStudio/ResourceMap.cs
Normal file
37
AssetStudio/ResourceMap.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using MessagePack;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public static class ResourceMap
|
||||
{
|
||||
private static AssetMap Instance;
|
||||
public static AssetEntry[] GetEntries() => Instance.AssetEntries;
|
||||
public static void FromFile(string path)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(path))
|
||||
{
|
||||
Logger.Info(string.Format("Parsing...."));
|
||||
try
|
||||
{
|
||||
using var stream = File.OpenRead(path);
|
||||
Instance = MessagePackSerializer.Deserialize<AssetMap>(stream, MessagePackSerializerOptions.Standard.WithCompression(MessagePackCompression.Lz4BlockArray));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error("AssetMap was not loaded");
|
||||
Console.WriteLine(e.ToString());
|
||||
return;
|
||||
}
|
||||
Logger.Info("Loaded !!");
|
||||
}
|
||||
}
|
||||
|
||||
public static void Clear()
|
||||
{
|
||||
Instance.GameType = GameType.Normal;
|
||||
Instance.AssetEntries = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user