v0.90.10
This commit is contained in:
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||||
<Version>0.90.00</Version>
|
<Version>0.90.10</Version>
|
||||||
<AssemblyVersion>0.90.00</AssemblyVersion>
|
<AssemblyVersion>0.90.10</AssemblyVersion>
|
||||||
<FileVersion>0.90.00</FileVersion>
|
<FileVersion>0.90.10</FileVersion>
|
||||||
<Copyright>Copyright © Perfare 2020-2022; Copyright © hozuki 2020</Copyright>
|
<Copyright>Copyright © Perfare 2020-2022; Copyright © hozuki 2020</Copyright>
|
||||||
<DebugType>embedded</DebugType>
|
<DebugType>embedded</DebugType>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -2,15 +2,15 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||||
<Version>0.90.00</Version>
|
<Version>0.90.10</Version>
|
||||||
<AssemblyVersion>0.90.00</AssemblyVersion>
|
<AssemblyVersion>0.90.10</AssemblyVersion>
|
||||||
<FileVersion>0.90.00</FileVersion>
|
<FileVersion>0.90.10</FileVersion>
|
||||||
<Copyright>Copyright © Razmoth 2022; Copyright © Perfare 2018-2022</Copyright>
|
<Copyright>Copyright © Razmoth 2022; Copyright © Perfare 2018-2022</Copyright>
|
||||||
<DebugType>embedded</DebugType>
|
<DebugType>embedded</DebugType>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="K4os.Compression.LZ4" Version="1.3.5" />
|
<PackageReference Include="K4os.Compression.LZ4" Version="1.3.6" />
|
||||||
<PackageReference Include="MessagePack" Version="2.6.100-alpha" />
|
<PackageReference Include="MessagePack" Version="2.6.100-alpha" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="ZstdSharp.Port" Version="0.7.2" />
|
<PackageReference Include="ZstdSharp.Port" Version="0.7.2" />
|
||||||
|
|||||||
@@ -36,7 +36,9 @@ namespace AssetStudio
|
|||||||
{
|
{
|
||||||
Directory.CreateDirectory(MapName);
|
Directory.CreateDirectory(MapName);
|
||||||
var files = Directory.GetFiles(MapName, "*.bin", SearchOption.TopDirectoryOnly);
|
var files = Directory.GetFiles(MapName, "*.bin", SearchOption.TopDirectoryOnly);
|
||||||
return files.Select(Path.GetFileNameWithoutExtension).ToArray();
|
var mapNames = files.Select(Path.GetFileNameWithoutExtension).ToArray();
|
||||||
|
Logger.Verbose($"Found {mapNames.Length} CABMaps under Maps folder");
|
||||||
|
return mapNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Clear()
|
public static void Clear()
|
||||||
@@ -48,34 +50,20 @@ namespace AssetStudio
|
|||||||
tokenSource.Dispose();
|
tokenSource.Dispose();
|
||||||
tokenSource = new CancellationTokenSource();
|
tokenSource = new CancellationTokenSource();
|
||||||
|
|
||||||
GC.WaitForPendingFinalizers();
|
Logger.Verbose("Cleared AssetsHelper successfully !!");
|
||||||
GC.Collect();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ClearOffsets() => Offsets.Clear();
|
public static void ClearOffsets()
|
||||||
|
|
||||||
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))
|
Offsets.Clear();
|
||||||
{
|
Logger.Verbose("Cleared cached offsets");
|
||||||
path = Path.Combine(BaseFolder, entry.Path);
|
|
||||||
if (!Offsets.ContainsKey(path))
|
|
||||||
{
|
|
||||||
Offsets.Add(path, new HashSet<long>());
|
|
||||||
}
|
|
||||||
Offsets[path].Add(entry.Offset);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
path = string.Empty;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool TryGet(string path, out long[] offsets)
|
public static bool TryGet(string path, out long[] offsets)
|
||||||
{
|
{
|
||||||
if (Offsets.TryGetValue(path, out var list))
|
if (Offsets.TryGetValue(path, out var list) && list.Count > 0)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Found {list.Count} offsets for path {path}");
|
||||||
offsets = list.ToArray();
|
offsets = list.ToArray();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -83,6 +71,67 @@ namespace AssetStudio
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void AddCABOffsets(string[] paths, List<string> cabs)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < cabs.Count; i++)
|
||||||
|
{
|
||||||
|
var cab = cabs[i];
|
||||||
|
if (CABMap.TryGetValue(cab, out var entry))
|
||||||
|
{
|
||||||
|
var fullPath = Path.Combine(BaseFolder, entry.Path);
|
||||||
|
Logger.Verbose($"Found {cab} in {fullPath}");
|
||||||
|
if (!paths.Contains(fullPath))
|
||||||
|
{
|
||||||
|
Offsets.TryAdd(fullPath, new HashSet<long>());
|
||||||
|
Offsets[fullPath].Add(entry.Offset);
|
||||||
|
Logger.Verbose($"Added {fullPath} to Offsets, at offset {entry.Offset}");
|
||||||
|
}
|
||||||
|
foreach (var dep in entry.Dependencies)
|
||||||
|
{
|
||||||
|
if (!cabs.Contains(dep))
|
||||||
|
cabs.Add(dep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool FindCAB(string path, out List<string> cabs)
|
||||||
|
{
|
||||||
|
var relativePath = Path.GetRelativePath(BaseFolder, path);
|
||||||
|
cabs = CABMap.AsParallel().Where(x => x.Value.Path.Equals(relativePath, StringComparison.OrdinalIgnoreCase)).Select(x => x.Key).Distinct().ToList();
|
||||||
|
Logger.Verbose($"Found {cabs.Count} that belongs to {relativePath}");
|
||||||
|
return cabs.Count != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string[] ProcessFiles(string[] files)
|
||||||
|
{
|
||||||
|
foreach (var file in files)
|
||||||
|
{
|
||||||
|
Offsets.TryAdd(file, new HashSet<long>());
|
||||||
|
Logger.Verbose($"Added {file} to Offsets dictionary");
|
||||||
|
if (FindCAB(file, out var cabs))
|
||||||
|
{
|
||||||
|
AddCABOffsets(files, cabs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Logger.Verbose($"Finished resolving dependncies, the original {files.Length} files will be loaded entirely, and the {Offsets.Count - files.Length} dependicnes will be loaded from cached offsets only");
|
||||||
|
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 static void BuildCABMap(string[] files, string mapName, string baseFolder, Game game)
|
public static void BuildCABMap(string[] files, string mapName, string baseFolder, Game game)
|
||||||
{
|
{
|
||||||
Logger.Info("Building CABMap...");
|
Logger.Info("Building CABMap...");
|
||||||
@@ -220,6 +269,7 @@ namespace AssetStudio
|
|||||||
CABMap.Add(cab, entry);
|
CABMap.Add(cab, entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Logger.Verbose($"Initialized CABMap with {CABMap.Count} entries");
|
||||||
Logger.Info($"Loaded {mapName} !!");
|
Logger.Info($"Loaded {mapName} !!");
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@@ -342,7 +392,7 @@ namespace AssetStudio
|
|||||||
case ClassIDType.Texture2D:
|
case ClassIDType.Texture2D:
|
||||||
case ClassIDType.VideoClip:
|
case ClassIDType.VideoClip:
|
||||||
case ClassIDType.AudioClip:
|
case ClassIDType.AudioClip:
|
||||||
case ClassIDType.AnimationClip:
|
case ClassIDType.AnimationClip when AnimationClip.Parsable:
|
||||||
asset.Name = objectReader.ReadAlignedString();
|
asset.Name = objectReader.ReadAlignedString();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -56,6 +56,8 @@ namespace AssetStudio
|
|||||||
var path = Path.GetDirectoryName(Path.GetFullPath(files[0]));
|
var path = Path.GetDirectoryName(Path.GetFullPath(files[0]));
|
||||||
MergeSplitAssets(path);
|
MergeSplitAssets(path);
|
||||||
var toReadFile = ProcessingSplitFiles(files.ToList());
|
var toReadFile = ProcessingSplitFiles(files.ToList());
|
||||||
|
if (ResolveDependencies)
|
||||||
|
toReadFile = AssetsHelper.ProcessDependencies(toReadFile);
|
||||||
Load(toReadFile);
|
Load(toReadFile);
|
||||||
|
|
||||||
if (Silent)
|
if (Silent)
|
||||||
@@ -89,6 +91,7 @@ namespace AssetStudio
|
|||||||
{
|
{
|
||||||
foreach (var file in files)
|
foreach (var file in files)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"caching {file} path and name to filter out duplicates");
|
||||||
importFiles.Add(file);
|
importFiles.Add(file);
|
||||||
importFilesHash.Add(Path.GetFileName(file));
|
importFilesHash.Add(Path.GetFileName(file));
|
||||||
}
|
}
|
||||||
@@ -171,6 +174,7 @@ namespace AssetStudio
|
|||||||
|
|
||||||
foreach (var sharedFile in assetsFile.m_Externals)
|
foreach (var sharedFile in assetsFile.m_Externals)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"{assetsFile.fileName} needs external file {sharedFile.fileName}, attempting to look it up...");
|
||||||
var sharedFileName = sharedFile.fileName;
|
var sharedFileName = sharedFile.fileName;
|
||||||
|
|
||||||
if (!importFilesHash.Contains(sharedFileName))
|
if (!importFilesHash.Contains(sharedFileName))
|
||||||
@@ -183,6 +187,7 @@ namespace AssetStudio
|
|||||||
var findFiles = Directory.GetFiles(Path.GetDirectoryName(reader.FullPath), sharedFileName, SearchOption.AllDirectories);
|
var findFiles = Directory.GetFiles(Path.GetDirectoryName(reader.FullPath), sharedFileName, SearchOption.AllDirectories);
|
||||||
if (findFiles.Length > 0)
|
if (findFiles.Length > 0)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Found {findFiles.Length} matching files, picking first file {findFiles[0]} !!");
|
||||||
sharedFilePath = findFiles[0];
|
sharedFilePath = findFiles[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -193,6 +198,7 @@ namespace AssetStudio
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Logger.Verbose("Nothing was found, caching into non existant files to avoid repeated searching !!");
|
||||||
noexistFiles.Add(sharedFilePath);
|
noexistFiles.Add(sharedFilePath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -214,6 +220,7 @@ namespace AssetStudio
|
|||||||
|
|
||||||
private void LoadAssetsFromMemory(FileReader reader, string originalPath, string unityVersion = null, long originalOffset = 0)
|
private void LoadAssetsFromMemory(FileReader reader, string originalPath, string unityVersion = null, long originalOffset = 0)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Loading asset file {reader.FileName} with version {unityVersion} from {originalPath} at offset 0x{originalOffset:X8}");
|
||||||
if (!assetsFileListHash.Contains(reader.FileName))
|
if (!assetsFileListHash.Contains(reader.FileName))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -228,38 +235,6 @@ namespace AssetStudio
|
|||||||
CheckStrippedVersion(assetsFile);
|
CheckStrippedVersion(assetsFile);
|
||||||
assetsFileList.Add(assetsFile);
|
assetsFileList.Add(assetsFile);
|
||||||
assetsFileListHash.Add(assetsFile.fileName);
|
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)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@@ -290,6 +265,7 @@ namespace AssetStudio
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Logger.Verbose("Caching resource stream");
|
||||||
resourceFileReaders[file.fileName] = subReader; //TODO
|
resourceFileReaders[file.fileName] = subReader; //TODO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -335,6 +311,7 @@ namespace AssetStudio
|
|||||||
LoadWebFile(subReader);
|
LoadWebFile(subReader);
|
||||||
break;
|
break;
|
||||||
case FileType.ResourceFile:
|
case FileType.ResourceFile:
|
||||||
|
Logger.Verbose("Caching resource stream");
|
||||||
resourceFileReaders[file.fileName] = subReader; //TODO
|
resourceFileReaders[file.fileName] = subReader; //TODO
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -358,8 +335,7 @@ namespace AssetStudio
|
|||||||
using (ZipArchive archive = new ZipArchive(reader.BaseStream, ZipArchiveMode.Read))
|
using (ZipArchive archive = new ZipArchive(reader.BaseStream, ZipArchiveMode.Read))
|
||||||
{
|
{
|
||||||
List<string> splitFiles = new List<string>();
|
List<string> splitFiles = new List<string>();
|
||||||
// register all files before parsing the assets so that the external references can be found
|
Logger.Verbose("Register all files before parsing the assets so that the external references can be found and find split files");
|
||||||
// and find split files
|
|
||||||
foreach (ZipArchiveEntry entry in archive.Entries)
|
foreach (ZipArchiveEntry entry in archive.Entries)
|
||||||
{
|
{
|
||||||
if (entry.Name.Contains(".split"))
|
if (entry.Name.Contains(".split"))
|
||||||
@@ -378,7 +354,7 @@ namespace AssetStudio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// merge split files and load the result
|
Logger.Verbose("Merge split files and load the result");
|
||||||
foreach (string basePath in splitFiles)
|
foreach (string basePath in splitFiles)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -406,15 +382,14 @@ namespace AssetStudio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// load all entries
|
Logger.Verbose("Load all entries");
|
||||||
|
Logger.Verbose($"Found {archive.Entries.Count} entries");
|
||||||
foreach (ZipArchiveEntry entry in archive.Entries)
|
foreach (ZipArchiveEntry entry in archive.Entries)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string dummyPath = Path.Combine(Path.GetDirectoryName(reader.FullPath), reader.FileName, entry.FullName);
|
string dummyPath = Path.Combine(Path.GetDirectoryName(reader.FullPath), reader.FileName, entry.FullName);
|
||||||
// create a new stream
|
Logger.Verbose("Create a new stream to store the deflated stream in and keep the data for later extraction");
|
||||||
// - to store the deflated stream in
|
|
||||||
// - to keep the data for later extraction
|
|
||||||
Stream streamReader = new MemoryStream();
|
Stream streamReader = new MemoryStream();
|
||||||
using (Stream entryStream = entry.Open())
|
using (Stream entryStream = entry.Open())
|
||||||
{
|
{
|
||||||
@@ -429,6 +404,7 @@ namespace AssetStudio
|
|||||||
entryReader.Position = 0;
|
entryReader.Position = 0;
|
||||||
if (!resourceFileReaders.ContainsKey(entry.Name))
|
if (!resourceFileReaders.ContainsKey(entry.Name))
|
||||||
{
|
{
|
||||||
|
Logger.Verbose("Caching resource file");
|
||||||
resourceFileReaders.Add(entry.Name, entryReader);
|
resourceFileReaders.Add(entry.Name, entryReader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -459,27 +435,14 @@ namespace AssetStudio
|
|||||||
{
|
{
|
||||||
foreach (var offset in offsets)
|
foreach (var offset in offsets)
|
||||||
{
|
{
|
||||||
var name = offset.ToString("X8");
|
LoadBlockSubFile(reader.FullPath, stream, offset);
|
||||||
Logger.Info($"Loading Block {name}");
|
|
||||||
|
|
||||||
stream.Offset = offset;
|
|
||||||
var dummyPath = Path.Combine(Path.GetDirectoryName(reader.FullPath), name);
|
|
||||||
var subReader = new FileReader(dummyPath, stream, true);
|
|
||||||
LoadBundleFile(subReader, reader.FullPath, offset, false);
|
|
||||||
}
|
}
|
||||||
AssetsHelper.Remove(reader.FullPath);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
var name = stream.AbsolutePosition.ToString("X8");
|
LoadBlockSubFile(reader.FullPath, stream, stream.AbsolutePosition);
|
||||||
Logger.Info($"Loading Block {name}");
|
|
||||||
|
|
||||||
stream.Offset = stream.AbsolutePosition;
|
|
||||||
var dummyPath = Path.Combine(Path.GetDirectoryName(reader.FullPath), name);
|
|
||||||
var subReader = new FileReader(dummyPath, stream, true);
|
|
||||||
LoadBundleFile(subReader, reader.FullPath, stream.AbsolutePosition, false);
|
|
||||||
} while (stream.Remaining > 0);
|
} while (stream.Remaining > 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -492,20 +455,27 @@ namespace AssetStudio
|
|||||||
reader.Dispose();
|
reader.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private void LoadBlockSubFile(string path, OffsetStream stream, long offset)
|
||||||
|
{
|
||||||
|
var name = offset.ToString("X8");
|
||||||
|
Logger.Info($"Loading Block {name}");
|
||||||
|
|
||||||
|
stream.Offset = offset;
|
||||||
|
var dummyPath = Path.Combine(Path.GetDirectoryName(path), name);
|
||||||
|
var subReader = new FileReader(dummyPath, stream, true);
|
||||||
|
LoadBundleFile(subReader, path, offset, false);
|
||||||
|
}
|
||||||
private void LoadBlkFile(FileReader reader)
|
private void LoadBlkFile(FileReader reader)
|
||||||
{
|
{
|
||||||
Logger.Info("Loading " + reader.FullPath);
|
Logger.Info("Loading " + reader.FullPath);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using var stream = BlkUtils.Decrypt(reader, (Blk)Game);
|
using var stream = BlkUtils.Decrypt(reader, (Blk)Game);
|
||||||
if (AssetsHelper.TryGet(reader.FullPath, out var offsets))
|
foreach (var offset in stream.GetOffsets(reader.FullPath))
|
||||||
{
|
|
||||||
foreach (var offset in offsets)
|
|
||||||
{
|
{
|
||||||
var name = offset.ToString("X8");
|
var name = offset.ToString("X8");
|
||||||
Logger.Info($"Loading Block {name}");
|
Logger.Info($"Loading Block {name}");
|
||||||
|
|
||||||
stream.Offset = offset;
|
|
||||||
var dummyPath = Path.Combine(Path.GetDirectoryName(reader.FullPath), name);
|
var dummyPath = Path.Combine(Path.GetDirectoryName(reader.FullPath), name);
|
||||||
var subReader = new FileReader(dummyPath, stream, true);
|
var subReader = new FileReader(dummyPath, stream, true);
|
||||||
switch (subReader.FileType)
|
switch (subReader.FileType)
|
||||||
@@ -518,30 +488,6 @@ namespace AssetStudio
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AssetsHelper.Remove(reader.FullPath);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
|
||||||
var name = stream.AbsolutePosition.ToString("X8");
|
|
||||||
Logger.Info($"Loading Block {name}");
|
|
||||||
|
|
||||||
var dummyPath = Path.Combine(Path.GetDirectoryName(reader.FullPath), name);
|
|
||||||
var subReader = new FileReader(dummyPath, stream, true);
|
|
||||||
switch (subReader.FileType)
|
|
||||||
{
|
|
||||||
case FileType.BundleFile:
|
|
||||||
LoadBundleFile(subReader, reader.FullPath, stream.AbsolutePosition, false);
|
|
||||||
break;
|
|
||||||
case FileType.Mhy0File:
|
|
||||||
LoadMhy0File(subReader, reader.FullPath, stream.AbsolutePosition, false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
stream.Offset = stream.AbsolutePosition;
|
|
||||||
} while (stream.Remaining > 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (InvalidCastException)
|
catch (InvalidCastException)
|
||||||
{
|
{
|
||||||
@@ -565,6 +511,7 @@ namespace AssetStudio
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var mhy0File = new Mhy0File(reader, reader.FullPath, (Mhy0)Game);
|
var mhy0File = new Mhy0File(reader, reader.FullPath, (Mhy0)Game);
|
||||||
|
Logger.Verbose($"mhy0 total size: {mhy0File.TotalSize:X8}");
|
||||||
foreach (var file in mhy0File.fileList)
|
foreach (var file in mhy0File.fileList)
|
||||||
{
|
{
|
||||||
var dummyPath = Path.Combine(Path.GetDirectoryName(reader.FullPath), file.fileName);
|
var dummyPath = Path.Combine(Path.GetDirectoryName(reader.FullPath), file.fileName);
|
||||||
@@ -575,6 +522,7 @@ namespace AssetStudio
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Logger.Verbose("Caching resource stream");
|
||||||
resourceFileReaders[file.fileName] = cabReader; //TODO
|
resourceFileReaders[file.fileName] = cabReader; //TODO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -612,6 +560,8 @@ namespace AssetStudio
|
|||||||
|
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
|
Logger.Verbose("Cleaning up...");
|
||||||
|
|
||||||
foreach (var assetsFile in assetsFileList)
|
foreach (var assetsFile in assetsFileList)
|
||||||
{
|
{
|
||||||
assetsFile.Objects.Clear();
|
assetsFile.Objects.Clear();
|
||||||
@@ -653,103 +603,40 @@ namespace AssetStudio
|
|||||||
var objectReader = new ObjectReader(assetsFile.reader, assetsFile, objectInfo, Game);
|
var objectReader = new ObjectReader(assetsFile.reader, assetsFile, objectInfo, Game);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Object obj;
|
Object obj = objectReader.type switch
|
||||||
switch (objectReader.type)
|
|
||||||
{
|
{
|
||||||
case ClassIDType.Animation:
|
ClassIDType.Animation => new Animation(objectReader),
|
||||||
obj = new Animation(objectReader);
|
ClassIDType.AnimationClip when AnimationClip.Parsable => new AnimationClip(objectReader),
|
||||||
break;
|
ClassIDType.Animator => new Animator(objectReader),
|
||||||
case ClassIDType.AnimationClip:
|
ClassIDType.AnimatorController => new AnimatorController(objectReader),
|
||||||
obj = new AnimationClip(objectReader);
|
ClassIDType.AnimatorOverrideController => new AnimatorOverrideController(objectReader),
|
||||||
break;
|
ClassIDType.AssetBundle => new AssetBundle(objectReader),
|
||||||
case ClassIDType.Animator:
|
ClassIDType.AudioClip => new AudioClip(objectReader),
|
||||||
obj = new Animator(objectReader);
|
ClassIDType.Avatar => new Avatar(objectReader),
|
||||||
break;
|
ClassIDType.Font => new Font(objectReader),
|
||||||
case ClassIDType.AnimatorController:
|
ClassIDType.GameObject => new GameObject(objectReader),
|
||||||
obj = new AnimatorController(objectReader);
|
ClassIDType.IndexObject => new IndexObject(objectReader),
|
||||||
break;
|
ClassIDType.Material => new Material(objectReader),
|
||||||
case ClassIDType.AnimatorOverrideController:
|
ClassIDType.Mesh => new Mesh(objectReader),
|
||||||
obj = new AnimatorOverrideController(objectReader);
|
ClassIDType.MeshFilter => new MeshFilter(objectReader),
|
||||||
break;
|
ClassIDType.MeshRenderer when Renderer.Parsable => new MeshRenderer(objectReader),
|
||||||
case ClassIDType.AssetBundle:
|
ClassIDType.MiHoYoBinData => new MiHoYoBinData(objectReader),
|
||||||
obj = new AssetBundle(objectReader);
|
ClassIDType.MonoBehaviour => new MonoBehaviour(objectReader),
|
||||||
break;
|
ClassIDType.MonoScript => new MonoScript(objectReader),
|
||||||
case ClassIDType.AudioClip:
|
ClassIDType.MovieTexture => new MovieTexture(objectReader),
|
||||||
obj = new AudioClip(objectReader);
|
ClassIDType.PlayerSettings => new PlayerSettings(objectReader),
|
||||||
break;
|
ClassIDType.RectTransform => new RectTransform(objectReader),
|
||||||
case ClassIDType.Avatar:
|
ClassIDType.Shader when Shader.Parsable => new Shader(objectReader),
|
||||||
obj = new Avatar(objectReader);
|
ClassIDType.SkinnedMeshRenderer when Renderer.Parsable => new SkinnedMeshRenderer(objectReader),
|
||||||
break;
|
ClassIDType.Sprite => new Sprite(objectReader),
|
||||||
case ClassIDType.Font:
|
ClassIDType.SpriteAtlas => new SpriteAtlas(objectReader),
|
||||||
obj = new Font(objectReader);
|
ClassIDType.TextAsset => new TextAsset(objectReader),
|
||||||
break;
|
ClassIDType.Texture2D => new Texture2D(objectReader),
|
||||||
case ClassIDType.GameObject:
|
ClassIDType.Transform => new Transform(objectReader),
|
||||||
obj = new GameObject(objectReader);
|
ClassIDType.VideoClip => new VideoClip(objectReader),
|
||||||
break;
|
ClassIDType.ResourceManager => new ResourceManager(objectReader),
|
||||||
case ClassIDType.IndexObject:
|
_ => new Object(objectReader),
|
||||||
obj = new IndexObject(objectReader);
|
};
|
||||||
break;
|
|
||||||
case ClassIDType.Material:
|
|
||||||
obj = new Material(objectReader);
|
|
||||||
break;
|
|
||||||
case ClassIDType.Mesh:
|
|
||||||
obj = new Mesh(objectReader);
|
|
||||||
break;
|
|
||||||
case ClassIDType.MeshFilter:
|
|
||||||
obj = new MeshFilter(objectReader);
|
|
||||||
break;
|
|
||||||
case ClassIDType.MeshRenderer when Renderer.Parsable:
|
|
||||||
obj = new MeshRenderer(objectReader);
|
|
||||||
break;
|
|
||||||
case ClassIDType.MiHoYoBinData:
|
|
||||||
obj = new MiHoYoBinData(objectReader);
|
|
||||||
break;
|
|
||||||
case ClassIDType.MonoBehaviour:
|
|
||||||
obj = new MonoBehaviour(objectReader);
|
|
||||||
break;
|
|
||||||
case ClassIDType.MonoScript:
|
|
||||||
obj = new MonoScript(objectReader);
|
|
||||||
break;
|
|
||||||
case ClassIDType.MovieTexture:
|
|
||||||
obj = new MovieTexture(objectReader);
|
|
||||||
break;
|
|
||||||
case ClassIDType.PlayerSettings:
|
|
||||||
obj = new PlayerSettings(objectReader);
|
|
||||||
break;
|
|
||||||
case ClassIDType.RectTransform:
|
|
||||||
obj = new RectTransform(objectReader);
|
|
||||||
break;
|
|
||||||
case ClassIDType.Shader when Shader.Parsable:
|
|
||||||
obj = new Shader(objectReader);
|
|
||||||
break;
|
|
||||||
case ClassIDType.SkinnedMeshRenderer when Renderer.Parsable:
|
|
||||||
obj = new SkinnedMeshRenderer(objectReader);
|
|
||||||
break;
|
|
||||||
case ClassIDType.Sprite:
|
|
||||||
obj = new Sprite(objectReader);
|
|
||||||
break;
|
|
||||||
case ClassIDType.SpriteAtlas:
|
|
||||||
obj = new SpriteAtlas(objectReader);
|
|
||||||
break;
|
|
||||||
case ClassIDType.TextAsset:
|
|
||||||
obj = new TextAsset(objectReader);
|
|
||||||
break;
|
|
||||||
case ClassIDType.Texture2D:
|
|
||||||
obj = new Texture2D(objectReader);
|
|
||||||
break;
|
|
||||||
case ClassIDType.Transform:
|
|
||||||
obj = new Transform(objectReader);
|
|
||||||
break;
|
|
||||||
case ClassIDType.VideoClip:
|
|
||||||
obj = new VideoClip(objectReader);
|
|
||||||
break;
|
|
||||||
case ClassIDType.ResourceManager:
|
|
||||||
obj = new ResourceManager(objectReader);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
obj = new Object(objectReader);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
assetsFile.AddObject(obj);
|
assetsFile.AddObject(obj);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@@ -784,6 +671,7 @@ namespace AssetStudio
|
|||||||
}
|
}
|
||||||
if (obj is GameObject m_GameObject)
|
if (obj is GameObject m_GameObject)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"GameObject with {m_GameObject.m_PathID} in file {m_GameObject.assetsFile.fileName} has {m_GameObject.m_Components.Length} components, Attempting to fetch them...");
|
||||||
foreach (var pptr in m_GameObject.m_Components)
|
foreach (var pptr in m_GameObject.m_Components)
|
||||||
{
|
{
|
||||||
if (pptr.TryGet(out var m_Component))
|
if (pptr.TryGet(out var m_Component))
|
||||||
@@ -791,21 +679,27 @@ namespace AssetStudio
|
|||||||
switch (m_Component)
|
switch (m_Component)
|
||||||
{
|
{
|
||||||
case Transform m_Transform:
|
case Transform m_Transform:
|
||||||
|
Logger.Verbose($"Fetched Transform component with {m_Transform.m_PathID} in file {m_Transform.assetsFile.fileName}, assigning to GameObject components...");
|
||||||
m_GameObject.m_Transform = m_Transform;
|
m_GameObject.m_Transform = m_Transform;
|
||||||
break;
|
break;
|
||||||
case MeshRenderer m_MeshRenderer:
|
case MeshRenderer m_MeshRenderer:
|
||||||
|
Logger.Verbose($"Fetched MeshRenderer component with {m_MeshRenderer.m_PathID} in file {m_MeshRenderer.assetsFile.fileName}, assigning to GameObject components...");
|
||||||
m_GameObject.m_MeshRenderer = m_MeshRenderer;
|
m_GameObject.m_MeshRenderer = m_MeshRenderer;
|
||||||
break;
|
break;
|
||||||
case MeshFilter m_MeshFilter:
|
case MeshFilter m_MeshFilter:
|
||||||
|
Logger.Verbose($"Fetched MeshFilter component with {m_MeshFilter.m_PathID} in file {m_MeshFilter.assetsFile.fileName}, assigning to GameObject components...");
|
||||||
m_GameObject.m_MeshFilter = m_MeshFilter;
|
m_GameObject.m_MeshFilter = m_MeshFilter;
|
||||||
break;
|
break;
|
||||||
case SkinnedMeshRenderer m_SkinnedMeshRenderer:
|
case SkinnedMeshRenderer m_SkinnedMeshRenderer:
|
||||||
|
Logger.Verbose($"Fetched SkinnedMeshRenderer component with {m_SkinnedMeshRenderer.m_PathID} in file {m_SkinnedMeshRenderer.assetsFile.fileName}, assigning to GameObject components...");
|
||||||
m_GameObject.m_SkinnedMeshRenderer = m_SkinnedMeshRenderer;
|
m_GameObject.m_SkinnedMeshRenderer = m_SkinnedMeshRenderer;
|
||||||
break;
|
break;
|
||||||
case Animator m_Animator:
|
case Animator m_Animator:
|
||||||
|
Logger.Verbose($"Fetched Animator component with {m_Animator.m_PathID} in file {m_Animator.assetsFile.fileName}, assigning to GameObject components...");
|
||||||
m_GameObject.m_Animator = m_Animator;
|
m_GameObject.m_Animator = m_Animator;
|
||||||
break;
|
break;
|
||||||
case Animation m_Animation:
|
case Animation m_Animation:
|
||||||
|
Logger.Verbose($"Fetched Animation component with {m_Animation.m_PathID} in file {m_Animation.assetsFile.fileName}, assigning to GameObject components...");
|
||||||
m_GameObject.m_Animation = m_Animation;
|
m_GameObject.m_Animation = m_Animation;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -816,12 +710,14 @@ namespace AssetStudio
|
|||||||
{
|
{
|
||||||
if (m_SpriteAtlas.m_RenderDataMap.Count > 0)
|
if (m_SpriteAtlas.m_RenderDataMap.Count > 0)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"SpriteAtlas with {m_SpriteAtlas.m_PathID} in file {m_SpriteAtlas.assetsFile.fileName} has {m_SpriteAtlas.m_PackedSprites.Length} packed sprites, Attempting to fetch them...");
|
||||||
foreach (var m_PackedSprite in m_SpriteAtlas.m_PackedSprites)
|
foreach (var m_PackedSprite in m_SpriteAtlas.m_PackedSprites)
|
||||||
{
|
{
|
||||||
if (m_PackedSprite.TryGet(out var m_Sprite))
|
if (m_PackedSprite.TryGet(out var m_Sprite))
|
||||||
{
|
{
|
||||||
if (m_Sprite.m_SpriteAtlas.IsNull)
|
if (m_Sprite.m_SpriteAtlas.IsNull)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Fetched Sprite with {m_Sprite.m_PathID} in file {m_Sprite.assetsFile.fileName}, assigning to parent SpriteAtlas...");
|
||||||
m_Sprite.m_SpriteAtlas.Set(m_SpriteAtlas);
|
m_Sprite.m_SpriteAtlas.Set(m_SpriteAtlas);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -829,6 +725,7 @@ namespace AssetStudio
|
|||||||
m_Sprite.m_SpriteAtlas.TryGet(out var m_SpriteAtlaOld);
|
m_Sprite.m_SpriteAtlas.TryGet(out var m_SpriteAtlaOld);
|
||||||
if (m_SpriteAtlaOld.m_IsVariant)
|
if (m_SpriteAtlaOld.m_IsVariant)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Fetched Sprite with {m_Sprite.m_PathID} in file {m_Sprite.assetsFile.fileName} has a variant of the origianl SpriteAtlas, disposing of the variant and assinging to the parent SpriteAtlas...");
|
||||||
m_Sprite.m_SpriteAtlas.Set(m_SpriteAtlas);
|
m_Sprite.m_SpriteAtlas.Set(m_SpriteAtlas);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using System.Data;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace AssetStudio
|
namespace AssetStudio
|
||||||
{
|
{
|
||||||
@@ -49,6 +50,20 @@ namespace AssetStudio
|
|||||||
public uint compressedBlocksInfoSize;
|
public uint compressedBlocksInfoSize;
|
||||||
public uint uncompressedBlocksInfoSize;
|
public uint uncompressedBlocksInfoSize;
|
||||||
public ArchiveFlags flags;
|
public ArchiveFlags flags;
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.Append($"signature: {signature} | ");
|
||||||
|
sb.Append($"version: {version} | ");
|
||||||
|
sb.Append($"unityVersion: {unityVersion} | ");
|
||||||
|
sb.Append($"unityRevision: {unityRevision} | ");
|
||||||
|
sb.Append($"size: 0x{size:X8} | ");
|
||||||
|
sb.Append($"compressedBlocksInfoSize: 0x{compressedBlocksInfoSize:X8} | ");
|
||||||
|
sb.Append($"uncompressedBlocksInfoSize: 0x{uncompressedBlocksInfoSize:X8} | ");
|
||||||
|
sb.Append($"flags: 0x{(int)flags:X8}");
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class StorageBlock
|
public class StorageBlock
|
||||||
@@ -56,6 +71,15 @@ namespace AssetStudio
|
|||||||
public uint compressedSize;
|
public uint compressedSize;
|
||||||
public uint uncompressedSize;
|
public uint uncompressedSize;
|
||||||
public StorageBlockFlags flags;
|
public StorageBlockFlags flags;
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.Append($"compressedSize: 0x{compressedSize:X8} | ");
|
||||||
|
sb.Append($"uncompressedSize: 0x{uncompressedSize:X8} | ");
|
||||||
|
sb.Append($"flags: 0x{(int)flags:X8}");
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Node
|
public class Node
|
||||||
@@ -64,6 +88,16 @@ namespace AssetStudio
|
|||||||
public long size;
|
public long size;
|
||||||
public uint flags;
|
public uint flags;
|
||||||
public string path;
|
public string path;
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.Append($"offset: 0x{offset:X8} | ");
|
||||||
|
sb.Append($"size: 0x{size:X8} | ");
|
||||||
|
sb.Append($"flags: {flags} | ");
|
||||||
|
sb.Append($"path: {path}");
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Game Game;
|
private Game Game;
|
||||||
@@ -121,6 +155,7 @@ namespace AssetStudio
|
|||||||
{
|
{
|
||||||
Header header = new Header();
|
Header header = new Header();
|
||||||
header.signature = reader.ReadStringToNull(20);
|
header.signature = reader.ReadStringToNull(20);
|
||||||
|
Logger.Verbose($"Parsed signature {header.signature}");
|
||||||
switch (header.signature)
|
switch (header.signature)
|
||||||
{
|
{
|
||||||
case "UnityFS":
|
case "UnityFS":
|
||||||
@@ -129,6 +164,7 @@ namespace AssetStudio
|
|||||||
var version = reader.ReadUInt32();
|
var version = reader.ReadUInt32();
|
||||||
if (version > 11)
|
if (version > 11)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Encrypted bundle header with key {version}");
|
||||||
XORShift128.InitSeed(version);
|
XORShift128.InitSeed(version);
|
||||||
header.version = 6;
|
header.version = 6;
|
||||||
header.unityVersion = "5.x.x";
|
header.unityVersion = "5.x.x";
|
||||||
@@ -205,6 +241,7 @@ namespace AssetStudio
|
|||||||
{
|
{
|
||||||
Stream blocksStream;
|
Stream blocksStream;
|
||||||
var uncompressedSizeSum = m_BlocksInfo.Sum(x => x.uncompressedSize);
|
var uncompressedSizeSum = m_BlocksInfo.Sum(x => x.uncompressedSize);
|
||||||
|
Logger.Verbose($"Total size of decompressed blocks: {uncompressedSizeSum}");
|
||||||
if (uncompressedSizeSum >= int.MaxValue)
|
if (uncompressedSizeSum >= int.MaxValue)
|
||||||
{
|
{
|
||||||
/*var memoryMappedFile = MemoryMappedFile.CreateNew(null, uncompressedSizeSum);
|
/*var memoryMappedFile = MemoryMappedFile.CreateNew(null, uncompressedSizeSum);
|
||||||
@@ -220,26 +257,25 @@ namespace AssetStudio
|
|||||||
|
|
||||||
private void ReadBlocksAndDirectory(FileReader reader, Stream blocksStream)
|
private void ReadBlocksAndDirectory(FileReader reader, Stream blocksStream)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Writing block and directory to blocks stream...");
|
||||||
|
|
||||||
var isCompressed = m_Header.signature == "UnityWeb";
|
var isCompressed = m_Header.signature == "UnityWeb";
|
||||||
foreach (var blockInfo in m_BlocksInfo)
|
foreach (var blockInfo in m_BlocksInfo)
|
||||||
{
|
{
|
||||||
var uncompressedBytes = reader.ReadBytes((int)blockInfo.compressedSize);
|
var uncompressedBytes = reader.ReadBytes((int)blockInfo.compressedSize);
|
||||||
if (isCompressed)
|
if (isCompressed)
|
||||||
{
|
{
|
||||||
using (var memoryStream = new MemoryStream(uncompressedBytes))
|
using var memoryStream = new MemoryStream(uncompressedBytes);
|
||||||
{
|
using var decompressStream = SevenZipHelper.StreamDecompress(memoryStream);
|
||||||
using (var decompressStream = SevenZipHelper.StreamDecompress(memoryStream))
|
|
||||||
{
|
|
||||||
uncompressedBytes = decompressStream.ToArray();
|
uncompressedBytes = decompressStream.ToArray();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
blocksStream.Write(uncompressedBytes, 0, uncompressedBytes.Length);
|
blocksStream.Write(uncompressedBytes, 0, uncompressedBytes.Length);
|
||||||
}
|
}
|
||||||
blocksStream.Position = 0;
|
blocksStream.Position = 0;
|
||||||
var blocksReader = new EndianBinaryReader(blocksStream);
|
var blocksReader = new EndianBinaryReader(blocksStream);
|
||||||
var nodesCount = blocksReader.ReadInt32();
|
var nodesCount = blocksReader.ReadInt32();
|
||||||
m_DirectoryInfo = new Node[nodesCount];
|
m_DirectoryInfo = new Node[nodesCount];
|
||||||
|
Logger.Verbose($"Directory count: {nodesCount}");
|
||||||
for (int i = 0; i < nodesCount; i++)
|
for (int i = 0; i < nodesCount; i++)
|
||||||
{
|
{
|
||||||
m_DirectoryInfo[i] = new Node
|
m_DirectoryInfo[i] = new Node
|
||||||
@@ -253,6 +289,8 @@ namespace AssetStudio
|
|||||||
|
|
||||||
public void ReadFiles(Stream blocksStream, string path)
|
public void ReadFiles(Stream blocksStream, string path)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Writing files from blocks stream...");
|
||||||
|
|
||||||
fileList = new StreamFile[m_DirectoryInfo.Length];
|
fileList = new StreamFile[m_DirectoryInfo.Length];
|
||||||
for (int i = 0; i < m_DirectoryInfo.Length; i++)
|
for (int i = 0; i < m_DirectoryInfo.Length; i++)
|
||||||
{
|
{
|
||||||
@@ -286,6 +324,7 @@ namespace AssetStudio
|
|||||||
m_Header.uncompressedBlocksInfoSize ^= XORShift128.NextDecryptUInt();
|
m_Header.uncompressedBlocksInfoSize ^= XORShift128.NextDecryptUInt();
|
||||||
m_Header.compressedBlocksInfoSize ^= XORShift128.NextDecryptUInt();
|
m_Header.compressedBlocksInfoSize ^= XORShift128.NextDecryptUInt();
|
||||||
XORShift128.Init = false;
|
XORShift128.Init = false;
|
||||||
|
Logger.Verbose($"Bundle header decrypted");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ReadHeader(FileReader reader)
|
private void ReadHeader(FileReader reader)
|
||||||
@@ -317,10 +356,13 @@ namespace AssetStudio
|
|||||||
m_Header.compressedBlocksInfoSize -= 0xCA;
|
m_Header.compressedBlocksInfoSize -= 0xCA;
|
||||||
m_Header.uncompressedBlocksInfoSize -= 0xCA;
|
m_Header.uncompressedBlocksInfoSize -= 0xCA;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger.Verbose($"Bundle header Info: {m_Header}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ReadUnityCN(EndianBinaryReader reader)
|
private void ReadUnityCN(FileReader reader)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Attempting to decrypt file {reader.FileName} with UnityCN encryption");
|
||||||
ArchiveFlags mask;
|
ArchiveFlags mask;
|
||||||
|
|
||||||
var version = ParseVersion();
|
var version = ParseVersion();
|
||||||
@@ -339,8 +381,11 @@ namespace AssetStudio
|
|||||||
HasBlockInfoNeedPaddingAtStart = true;
|
HasBlockInfoNeedPaddingAtStart = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger.Verbose($"Mask set to 0x{mask:X8}");
|
||||||
|
|
||||||
if ((m_Header.flags & mask) != 0)
|
if ((m_Header.flags & mask) != 0)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Encryption flag exist, file is encrypted, attempting to decrypt");
|
||||||
UnityCN = new UnityCN(reader);
|
UnityCN = new UnityCN(reader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -367,6 +412,7 @@ namespace AssetStudio
|
|||||||
var blocksInfoBytesSpan = blocksInfoBytes.AsSpan();
|
var blocksInfoBytesSpan = blocksInfoBytes.AsSpan();
|
||||||
var uncompressedSize = m_Header.uncompressedBlocksInfoSize;
|
var uncompressedSize = m_Header.uncompressedBlocksInfoSize;
|
||||||
var compressionType = (CompressionType)(m_Header.flags & ArchiveFlags.CompressionTypeMask);
|
var compressionType = (CompressionType)(m_Header.flags & ArchiveFlags.CompressionTypeMask);
|
||||||
|
Logger.Verbose($"BlockInfo compression type: {compressionType}");
|
||||||
switch (compressionType) //kArchiveCompressionTypeMask
|
switch (compressionType) //kArchiveCompressionTypeMask
|
||||||
{
|
{
|
||||||
case CompressionType.None: //None
|
case CompressionType.None: //None
|
||||||
@@ -399,6 +445,7 @@ namespace AssetStudio
|
|||||||
case CompressionType.Lz4Mr0k: //Lz4Mr0k
|
case CompressionType.Lz4Mr0k: //Lz4Mr0k
|
||||||
if (Mr0kUtils.IsMr0k(blocksInfoBytesSpan))
|
if (Mr0kUtils.IsMr0k(blocksInfoBytesSpan))
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Header encrypted with mr0k, decrypting...");
|
||||||
blocksInfoBytesSpan = Mr0kUtils.Decrypt(blocksInfoBytesSpan, (Mr0k)Game).ToArray();
|
blocksInfoBytesSpan = Mr0kUtils.Decrypt(blocksInfoBytesSpan, (Mr0k)Game).ToArray();
|
||||||
}
|
}
|
||||||
goto case CompressionType.Lz4HC;
|
goto case CompressionType.Lz4HC;
|
||||||
@@ -413,6 +460,7 @@ namespace AssetStudio
|
|||||||
}
|
}
|
||||||
var blocksInfoCount = blocksInfoReader.ReadInt32();
|
var blocksInfoCount = blocksInfoReader.ReadInt32();
|
||||||
m_BlocksInfo = new StorageBlock[blocksInfoCount];
|
m_BlocksInfo = new StorageBlock[blocksInfoCount];
|
||||||
|
Logger.Verbose($"Blocks count: {blocksInfoCount}");
|
||||||
for (int i = 0; i < blocksInfoCount; i++)
|
for (int i = 0; i < blocksInfoCount; i++)
|
||||||
{
|
{
|
||||||
m_BlocksInfo[i] = new StorageBlock
|
m_BlocksInfo[i] = new StorageBlock
|
||||||
@@ -421,10 +469,13 @@ namespace AssetStudio
|
|||||||
compressedSize = blocksInfoReader.ReadUInt32(),
|
compressedSize = blocksInfoReader.ReadUInt32(),
|
||||||
flags = (StorageBlockFlags)blocksInfoReader.ReadUInt16()
|
flags = (StorageBlockFlags)blocksInfoReader.ReadUInt16()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Logger.Verbose($"Block {i} Info: {m_BlocksInfo[i]}");
|
||||||
}
|
}
|
||||||
|
|
||||||
var nodesCount = blocksInfoReader.ReadInt32();
|
var nodesCount = blocksInfoReader.ReadInt32();
|
||||||
m_DirectoryInfo = new Node[nodesCount];
|
m_DirectoryInfo = new Node[nodesCount];
|
||||||
|
Logger.Verbose($"Directory count: {nodesCount}");
|
||||||
for (int i = 0; i < nodesCount; i++)
|
for (int i = 0; i < nodesCount; i++)
|
||||||
{
|
{
|
||||||
m_DirectoryInfo[i] = new Node
|
m_DirectoryInfo[i] = new Node
|
||||||
@@ -434,6 +485,8 @@ namespace AssetStudio
|
|||||||
flags = blocksInfoReader.ReadUInt32(),
|
flags = blocksInfoReader.ReadUInt32(),
|
||||||
path = blocksInfoReader.ReadStringToNull(),
|
path = blocksInfoReader.ReadStringToNull(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Logger.Verbose($"Directory {i} Info: {m_DirectoryInfo[i]}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (HasBlockInfoNeedPaddingAtStart && (m_Header.flags & ArchiveFlags.BlockInfoNeedPaddingAtStart) != 0)
|
if (HasBlockInfoNeedPaddingAtStart && (m_Header.flags & ArchiveFlags.BlockInfoNeedPaddingAtStart) != 0)
|
||||||
@@ -444,10 +497,14 @@ namespace AssetStudio
|
|||||||
|
|
||||||
private void ReadBlocks(FileReader reader, Stream blocksStream)
|
private void ReadBlocks(FileReader reader, Stream blocksStream)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Writing block to blocks stream...");
|
||||||
|
|
||||||
for (int i = 0; i < m_BlocksInfo.Length; i++)
|
for (int i = 0; i < m_BlocksInfo.Length; i++)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Reading block {i}...");
|
||||||
var blockInfo = m_BlocksInfo[i];
|
var blockInfo = m_BlocksInfo[i];
|
||||||
var compressionType = (CompressionType)(blockInfo.flags & StorageBlockFlags.CompressionTypeMask);
|
var compressionType = (CompressionType)(blockInfo.flags & StorageBlockFlags.CompressionTypeMask);
|
||||||
|
Logger.Verbose($"Block compression type {compressionType}");
|
||||||
switch (compressionType) //kStorageBlockCompressionTypeMask
|
switch (compressionType) //kStorageBlockCompressionTypeMask
|
||||||
{
|
{
|
||||||
case CompressionType.None: //None
|
case CompressionType.None: //None
|
||||||
@@ -470,10 +527,12 @@ namespace AssetStudio
|
|||||||
var compressedBytesSpan = compressedBytes.AsSpan(0, compressedSize);
|
var compressedBytesSpan = compressedBytes.AsSpan(0, compressedSize);
|
||||||
if (compressionType == CompressionType.Lz4Mr0k && Mr0kUtils.IsMr0k(compressedBytes))
|
if (compressionType == CompressionType.Lz4Mr0k && Mr0kUtils.IsMr0k(compressedBytes))
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Block encrypted with mr0k, decrypting...");
|
||||||
compressedBytesSpan = Mr0kUtils.Decrypt(compressedBytesSpan, (Mr0k)Game);
|
compressedBytesSpan = Mr0kUtils.Decrypt(compressedBytesSpan, (Mr0k)Game);
|
||||||
}
|
}
|
||||||
if (Game.Type.IsUnityCN() && ((int)blockInfo.flags & 0x100) != 0)
|
if (Game.Type.IsUnityCN() && ((int)blockInfo.flags & 0x100) != 0)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Decrypting block with UnityCN...");
|
||||||
UnityCN.DecryptBlock(compressedBytes, compressedSize, i);
|
UnityCN.DecryptBlock(compressedBytes, compressedSize, i);
|
||||||
}
|
}
|
||||||
if (Game.Type.IsNetEase() && i == 0)
|
if (Game.Type.IsNetEase() && i == 0)
|
||||||
|
|||||||
@@ -965,6 +965,8 @@ namespace AssetStudio
|
|||||||
|
|
||||||
public sealed class AnimationClip : NamedObject
|
public sealed class AnimationClip : NamedObject
|
||||||
{
|
{
|
||||||
|
public static bool Parsable;
|
||||||
|
|
||||||
public AnimationType m_AnimationType;
|
public AnimationType m_AnimationType;
|
||||||
public bool m_Legacy;
|
public bool m_Legacy;
|
||||||
public bool m_Compressed;
|
public bool m_Compressed;
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ namespace AssetStudio
|
|||||||
serializedType = reader.serializedType;
|
serializedType = reader.serializedType;
|
||||||
byteSize = reader.byteSize;
|
byteSize = reader.byteSize;
|
||||||
|
|
||||||
|
Logger.Verbose($"Attempting to read object {type} with {m_PathID} in file {assetsFile.fileName}, starting from offset 0x{reader.byteStart:X8} with expected size of 0x{byteSize:X8} !!");
|
||||||
|
|
||||||
if (platform == BuildTarget.NoTarget)
|
if (platform == BuildTarget.NoTarget)
|
||||||
{
|
{
|
||||||
var m_ObjectHideFlags = reader.ReadUInt32();
|
var m_ObjectHideFlags = reader.ReadUInt32();
|
||||||
@@ -81,6 +83,7 @@ namespace AssetStudio
|
|||||||
|
|
||||||
public byte[] GetRawData()
|
public byte[] GetRawData()
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Dumping raw bytes of the object with {m_PathID} in file {assetsFile.fileName}...");
|
||||||
reader.Reset();
|
reader.Reset();
|
||||||
return reader.ReadBytes((int)byteSize);
|
return reader.ReadBytes((int)byteSize);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ namespace AssetStudio
|
|||||||
var m_ReadAllowed = reader.ReadBoolean();
|
var m_ReadAllowed = reader.ReadBoolean();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (version[0] > 2018 || (version[0] == 2018 && version[1] >= 2) || reader.Game.Type.IsGI()) //2018.2 and up
|
if (version[0] > 2018 || (version[0] == 2018 && version[1] >= 2)) //2018.2 and up
|
||||||
{
|
{
|
||||||
var m_StreamingMipmaps = reader.ReadBoolean();
|
var m_StreamingMipmaps = reader.ReadBoolean();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Buffers.Binary;
|
using System.Buffers.Binary;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace AssetStudio
|
namespace AssetStudio
|
||||||
{
|
{
|
||||||
@@ -8,16 +10,20 @@ namespace AssetStudio
|
|||||||
private const int DataOffset = 0x2A;
|
private const int DataOffset = 0x2A;
|
||||||
private const int KeySize = 0x1000;
|
private const int KeySize = 0x1000;
|
||||||
private const int SeedBlockSize = 0x800;
|
private const int SeedBlockSize = 0x800;
|
||||||
|
private const int BufferSize = 0x10000;
|
||||||
|
|
||||||
public static XORStream Decrypt(FileReader reader, Blk blk)
|
public static XORStream Decrypt(FileReader reader, Blk blk)
|
||||||
{
|
{
|
||||||
reader.Endian = EndianType.LittleEndian;
|
reader.Endian = EndianType.LittleEndian;
|
||||||
|
|
||||||
var signature = reader.ReadStringToNull();
|
var signature = reader.ReadStringToNull();
|
||||||
|
Logger.Verbose($"Signature: {signature}");
|
||||||
var count = reader.ReadInt32();
|
var count = reader.ReadInt32();
|
||||||
|
Logger.Verbose($"Key size: {count}");
|
||||||
var key = reader.ReadBytes(count);
|
var key = reader.ReadBytes(count);
|
||||||
reader.Position += count;
|
reader.Position += count;
|
||||||
var seedSize = Math.Min(reader.ReadInt16(), blk.SBox.IsNullOrEmpty() ? SeedBlockSize : SeedBlockSize * 2);
|
var seedSize = Math.Min(reader.ReadInt16(), blk.SBox.IsNullOrEmpty() ? SeedBlockSize : SeedBlockSize * 2);
|
||||||
|
Logger.Verbose($"Seed size: 0x{seedSize:X8}");
|
||||||
|
|
||||||
if (!blk.SBox.IsNullOrEmpty() && blk.Type.IsGI())
|
if (!blk.SBox.IsNullOrEmpty() && blk.Type.IsGI())
|
||||||
{
|
{
|
||||||
@@ -47,6 +53,8 @@ namespace AssetStudio
|
|||||||
var keyHigh = BinaryPrimitives.ReadUInt64LittleEndian(key.AsSpan(8, 8));
|
var keyHigh = BinaryPrimitives.ReadUInt64LittleEndian(key.AsSpan(8, 8));
|
||||||
var seed = keyLow ^ keyHigh ^ keySeed ^ blk.InitSeed;
|
var seed = keyLow ^ keyHigh ^ keySeed ^ blk.InitSeed;
|
||||||
|
|
||||||
|
Logger.Verbose($"Seed: 0x{seed:X8}");
|
||||||
|
|
||||||
var mt64 = new MT19937_64(seed);
|
var mt64 = new MT19937_64(seed);
|
||||||
var xorpad = new byte[KeySize];
|
var xorpad = new byte[KeySize];
|
||||||
for (int i = 0; i < KeySize; i += 8)
|
for (int i = 0; i < KeySize; i += 8)
|
||||||
@@ -56,5 +64,48 @@ namespace AssetStudio
|
|||||||
|
|
||||||
return new XORStream(reader.BaseStream, DataOffset, xorpad);
|
return new XORStream(reader.BaseStream, DataOffset, xorpad);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<long> GetOffsets(this XORStream stream, string path)
|
||||||
|
{
|
||||||
|
if (AssetsHelper.TryGet(path, out var offsets))
|
||||||
|
{
|
||||||
|
foreach(var offset in offsets)
|
||||||
|
{
|
||||||
|
stream.Offset = offset;
|
||||||
|
yield return offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
using var reader = new FileReader(path, stream, true);
|
||||||
|
var signature = reader.FileType switch
|
||||||
|
{
|
||||||
|
FileType.BundleFile => "UnityFS\x00",
|
||||||
|
FileType.Mhy0File => "mhy0",
|
||||||
|
_ => throw new InvalidOperationException()
|
||||||
|
};
|
||||||
|
|
||||||
|
Logger.Verbose($"Prased signature: {signature}");
|
||||||
|
|
||||||
|
var signatureBytes = Encoding.UTF8.GetBytes(signature);
|
||||||
|
var buffer = BigArrayPool<byte>.Shared.Rent(BufferSize);
|
||||||
|
while (stream.Remaining > 0)
|
||||||
|
{
|
||||||
|
var index = 0;
|
||||||
|
var absOffset = stream.AbsolutePosition;
|
||||||
|
var read = stream.Read(buffer);
|
||||||
|
while (index < read)
|
||||||
|
{
|
||||||
|
index = buffer.AsSpan(0, read).Search(signatureBytes, index);
|
||||||
|
if (index == -1) break;
|
||||||
|
var offset = absOffset + index;
|
||||||
|
stream.Offset = offset;
|
||||||
|
yield return offset;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BigArrayPool<byte>.Shared.Return(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -21,6 +21,7 @@ namespace AssetStudio
|
|||||||
|
|
||||||
var encryptedBlockSize = Math.Min(0x10 * ((data.Length - 0x94) >> 7), BlockSize);
|
var encryptedBlockSize = Math.Min(0x10 * ((data.Length - 0x94) >> 7), BlockSize);
|
||||||
|
|
||||||
|
Logger.Verbose($"Encrypted block size: {encryptedBlockSize}");
|
||||||
if (!mr0k.InitVector.IsNullOrEmpty())
|
if (!mr0k.InitVector.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
for (int i = 0; i < mr0k.InitVector.Length; i++)
|
for (int i = 0; i < mr0k.InitVector.Length; i++)
|
||||||
@@ -47,6 +48,8 @@ namespace AssetStudio
|
|||||||
var seed2 = BinaryPrimitives.ReadUInt64LittleEndian(key3);
|
var seed2 = BinaryPrimitives.ReadUInt64LittleEndian(key3);
|
||||||
var seed = seed2 ^ seed1 ^ (seed1 + (uint)data.Length - 20);
|
var seed = seed2 ^ seed1 ^ (seed1 + (uint)data.Length - 20);
|
||||||
|
|
||||||
|
Logger.Verbose($"Seed: 0x{seed:X8}");
|
||||||
|
|
||||||
var encryptedBlock = data.Slice(0x94, encryptedBlockSize);
|
var encryptedBlock = data.Slice(0x94, encryptedBlockSize);
|
||||||
var seedSpan = BitConverter.GetBytes(seed);
|
var seedSpan = BitConverter.GetBytes(seed);
|
||||||
for (var i = 0; i < encryptedBlockSize; i++)
|
for (var i = 0; i < encryptedBlockSize; i++)
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ namespace AssetStudio
|
|||||||
private static readonly byte[] Signature = new byte[] { 0xEE, 0xDD };
|
private static readonly byte[] Signature = new byte[] { 0xEE, 0xDD };
|
||||||
public static void Decrypt(Span<byte> bytes)
|
public static void Decrypt(Span<byte> bytes)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Attempting to decrypt block with NetEase encryption...");
|
||||||
|
|
||||||
var (encryptedOffset, encryptedSize) = ReadHeader(bytes);
|
var (encryptedOffset, encryptedSize) = ReadHeader(bytes);
|
||||||
var encrypted = bytes.Slice(encryptedOffset, encryptedSize);
|
var encrypted = bytes.Slice(encryptedOffset, encryptedSize);
|
||||||
var encryptedInts = MemoryMarshal.Cast<byte, int>(encrypted);
|
var encryptedInts = MemoryMarshal.Cast<byte, int>(encrypted);
|
||||||
@@ -77,7 +79,7 @@ namespace AssetStudio
|
|||||||
}
|
}
|
||||||
private static (int, int) ReadHeader(Span<byte> bytes)
|
private static (int, int) ReadHeader(Span<byte> bytes)
|
||||||
{
|
{
|
||||||
var index = bytes.Search(Signature, 0);
|
var index = bytes.Search(Signature);
|
||||||
if (index == -1 || index >= 0x40)
|
if (index == -1 || index >= 0x40)
|
||||||
{
|
{
|
||||||
throw new Exception("Header not found !!");
|
throw new Exception("Header not found !!");
|
||||||
@@ -127,6 +129,7 @@ namespace AssetStudio
|
|||||||
throw new Exception("Unsupported version");
|
throw new Exception("Unsupported version");
|
||||||
}
|
}
|
||||||
var versionString = version.ToString("X4");
|
var versionString = version.ToString("X4");
|
||||||
|
Logger.Verbose($"Bundle version: {versionString}");
|
||||||
Encoding.UTF8.GetBytes(versionString, bytes);
|
Encoding.UTF8.GetBytes(versionString, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ namespace AssetStudio
|
|||||||
|
|
||||||
public static void Decrypt(Span<byte> data, string path)
|
public static void Decrypt(Span<byte> data, string path)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Attempting to decrypt block with OPFP encryption...");
|
||||||
if (IsEncryptionBundle(path, out var key, out var version))
|
if (IsEncryptionBundle(path, out var key, out var version))
|
||||||
{
|
{
|
||||||
switch (version)
|
switch (version)
|
||||||
@@ -41,30 +42,39 @@ namespace AssetStudio
|
|||||||
{
|
{
|
||||||
if (V1_Prefixes.Any(prefix => relativePath.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)))
|
if (V1_Prefixes.Any(prefix => relativePath.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)))
|
||||||
{
|
{
|
||||||
|
Logger.Verbose("Path matches with V1 prefixes, generatring key...");
|
||||||
key = (byte)Path.GetFileName(relativePath).Length;
|
key = (byte)Path.GetFileName(relativePath).Length;
|
||||||
version = 1;
|
version = 1;
|
||||||
|
Logger.Verbose($"version: {version}, key: {key}");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (V0_Prefixes.Any(prefix => relativePath.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)))
|
else if (V0_Prefixes.Any(prefix => relativePath.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)))
|
||||||
{
|
{
|
||||||
|
Logger.Verbose("Path matches with V2 prefixes, generatring key...");
|
||||||
|
|
||||||
key = (byte)relativePath.Length;
|
key = (byte)relativePath.Length;
|
||||||
version = 0;
|
version = 0;
|
||||||
|
Logger.Verbose($"version: {version}, key: {key}");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Logger.Verbose($"Unknown encryption type");
|
||||||
key = 0x00;
|
key = 0x00;
|
||||||
version = 0;
|
version = 0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
private static bool IsFixedPath(string path, out string fixedPath)
|
private static bool IsFixedPath(string path, out string fixedPath)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Fixing path before checking...");
|
||||||
var dirs = path.Split(Path.DirectorySeparatorChar);
|
var dirs = path.Split(Path.DirectorySeparatorChar);
|
||||||
if (dirs.Contains(BaseFolder))
|
if (dirs.Contains(BaseFolder))
|
||||||
{
|
{
|
||||||
var idx = Array.IndexOf(dirs, BaseFolder);
|
var idx = Array.IndexOf(dirs, BaseFolder);
|
||||||
|
Logger.Verbose($"Seperator found at index {idx}");
|
||||||
fixedPath = string.Join(Path.DirectorySeparatorChar, dirs[(idx+1)..]).Replace("\\", "/");
|
fixedPath = string.Join(Path.DirectorySeparatorChar, dirs[(idx+1)..]).Replace("\\", "/");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
Logger.Verbose($"Unknown path");
|
||||||
fixedPath = string.Empty;
|
fixedPath = string.Empty;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,8 +28,11 @@ namespace AssetStudio
|
|||||||
DecryptKey(signatureKey, signatureBytes);
|
DecryptKey(signatureKey, signatureBytes);
|
||||||
|
|
||||||
var str = Encoding.UTF8.GetString(signatureBytes);
|
var str = Encoding.UTF8.GetString(signatureBytes);
|
||||||
|
Logger.Verbose($"Decrypted signature is {str}");
|
||||||
if (str != Signature)
|
if (str != Signature)
|
||||||
throw new Exception("Invalid Signature !!");
|
{
|
||||||
|
throw new Exception($"Invalid Signature, Expected {Signature} but found {str} instead");
|
||||||
|
}
|
||||||
|
|
||||||
DecryptKey(infoKey, infoBytes);
|
DecryptKey(infoKey, infoBytes);
|
||||||
|
|
||||||
@@ -41,19 +44,20 @@ namespace AssetStudio
|
|||||||
var idx = (i % 4 * 4) + (i / 4);
|
var idx = (i % 4 * 4) + (i / 4);
|
||||||
Sub[idx] = subBytes[i];
|
Sub[idx] = subBytes[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool SetKey(Entry entry)
|
public static bool SetKey(Entry entry)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Initializing decryptor with key {entry.Key}");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (var aes = Aes.Create())
|
using var aes = Aes.Create();
|
||||||
{
|
|
||||||
aes.Mode = CipherMode.ECB;
|
aes.Mode = CipherMode.ECB;
|
||||||
aes.Key = Convert.FromHexString(entry.Key);
|
aes.Key = Convert.FromHexString(entry.Key);
|
||||||
|
|
||||||
Encryptor = aes.CreateEncryptor();
|
Encryptor = aes.CreateEncryptor();
|
||||||
}
|
Logger.Verbose($"Decryptor initialized !!");
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ namespace AssetStudio
|
|||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
public static int Search(this byte[] src, string value, int offset = 0) => Search(src.AsSpan(), Encoding.UTF8.GetBytes(value), offset);
|
public static int Search(this byte[] src, string value, int offset = 0) => Search(src.AsSpan(), Encoding.UTF8.GetBytes(value), offset);
|
||||||
public static int Search(this Span<byte> src, byte[] pattern, int offset)
|
public static int Search(this Span<byte> src, byte[] pattern, int offset = 0)
|
||||||
{
|
{
|
||||||
int maxFirstCharSlot = src.Length - pattern.Length + 1;
|
int maxFirstCharSlot = src.Length - pattern.Length + 1;
|
||||||
for (int i = offset; i < maxFirstCharSlot; i++)
|
for (int i = offset; i < maxFirstCharSlot; i++)
|
||||||
|
|||||||
@@ -13,5 +13,15 @@ namespace AssetStudio
|
|||||||
|
|
||||||
//custom
|
//custom
|
||||||
public string fileName;
|
public string fileName;
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.Append($"Guid: {guid} | ");
|
||||||
|
sb.Append($"type: {type} | ");
|
||||||
|
sb.Append($"pathName: {pathName} | ");
|
||||||
|
sb.Append($"fileName: {fileName}");
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,12 +27,14 @@ namespace AssetStudio
|
|||||||
FullPath = Path.GetFullPath(path);
|
FullPath = Path.GetFullPath(path);
|
||||||
FileName = Path.GetFileName(path);
|
FileName = Path.GetFileName(path);
|
||||||
FileType = CheckFileType();
|
FileType = CheckFileType();
|
||||||
|
Logger.Verbose($"File {path} type is {FileType}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private FileType CheckFileType()
|
private FileType CheckFileType()
|
||||||
{
|
{
|
||||||
var signature = this.ReadStringToNull(20);
|
var signature = this.ReadStringToNull(20);
|
||||||
Position = 0;
|
Position = 0;
|
||||||
|
Logger.Verbose($"Parsed signature is {signature}");
|
||||||
switch (signature)
|
switch (signature)
|
||||||
{
|
{
|
||||||
case "ENCR":
|
case "ENCR":
|
||||||
@@ -47,46 +49,59 @@ namespace AssetStudio
|
|||||||
return FileType.BlkFile;
|
return FileType.BlkFile;
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
|
Logger.Verbose("signature does not match any of the supported string signatures, attempting to check bytes signatures");
|
||||||
byte[] magic = ReadBytes(2);
|
byte[] magic = ReadBytes(2);
|
||||||
Position = 0;
|
Position = 0;
|
||||||
|
Logger.Verbose($"Parsed signature is {Convert.ToHexString(magic)}");
|
||||||
if (gzipMagic.SequenceEqual(magic))
|
if (gzipMagic.SequenceEqual(magic))
|
||||||
{
|
{
|
||||||
return FileType.GZipFile;
|
return FileType.GZipFile;
|
||||||
}
|
}
|
||||||
|
Logger.Verbose($"Parsed signature does not match with expected signature {Convert.ToHexString(gzipMagic)}");
|
||||||
Position = 0x20;
|
Position = 0x20;
|
||||||
magic = ReadBytes(6);
|
magic = ReadBytes(6);
|
||||||
Position = 0;
|
Position = 0;
|
||||||
|
Logger.Verbose($"Parsed signature is {Convert.ToHexString(magic)}");
|
||||||
if (brotliMagic.SequenceEqual(magic))
|
if (brotliMagic.SequenceEqual(magic))
|
||||||
{
|
{
|
||||||
return FileType.BrotliFile;
|
return FileType.BrotliFile;
|
||||||
}
|
}
|
||||||
|
Logger.Verbose($"Parsed signature does not match with expected signature {Convert.ToHexString(brotliMagic)}");
|
||||||
if (IsSerializedFile())
|
if (IsSerializedFile())
|
||||||
{
|
{
|
||||||
return FileType.AssetsFile;
|
return FileType.AssetsFile;
|
||||||
}
|
}
|
||||||
magic = ReadBytes(4);
|
magic = ReadBytes(4);
|
||||||
Position = 0;
|
Position = 0;
|
||||||
|
Logger.Verbose($"Parsed signature is {Convert.ToHexString(magic)}");
|
||||||
if (zipMagic.SequenceEqual(magic) || zipSpannedMagic.SequenceEqual(magic))
|
if (zipMagic.SequenceEqual(magic) || zipSpannedMagic.SequenceEqual(magic))
|
||||||
{
|
{
|
||||||
return FileType.ZipFile;
|
return FileType.ZipFile;
|
||||||
}
|
}
|
||||||
|
Logger.Verbose($"Parsed signature does not match with expected signature {Convert.ToHexString(zipMagic)} or {Convert.ToHexString(zipSpannedMagic)}");
|
||||||
if (mhy0Magic.SequenceEqual(magic))
|
if (mhy0Magic.SequenceEqual(magic))
|
||||||
{
|
{
|
||||||
return FileType.Mhy0File;
|
return FileType.Mhy0File;
|
||||||
}
|
}
|
||||||
|
Logger.Verbose($"Parsed signature does not match with expected signature {Convert.ToHexString(mhy0Magic)}");
|
||||||
magic = ReadBytes(7);
|
magic = ReadBytes(7);
|
||||||
Position = 0;
|
Position = 0;
|
||||||
|
Logger.Verbose($"Parsed signature is {Convert.ToHexString(magic)}");
|
||||||
if (narakaMagic.SequenceEqual(magic))
|
if (narakaMagic.SequenceEqual(magic))
|
||||||
{
|
{
|
||||||
return FileType.BundleFile;
|
return FileType.BundleFile;
|
||||||
}
|
}
|
||||||
|
Logger.Verbose($"Parsed signature does not match with expected signature {Convert.ToHexString(narakaMagic)}");
|
||||||
magic = ReadBytes(9);
|
magic = ReadBytes(9);
|
||||||
Position = 0;
|
Position = 0;
|
||||||
|
Logger.Verbose($"Parsed signature is {Convert.ToHexString(magic)}");
|
||||||
if (gunfireMagic.SequenceEqual(magic))
|
if (gunfireMagic.SequenceEqual(magic))
|
||||||
{
|
{
|
||||||
Position = 0x32;
|
Position = 0x32;
|
||||||
return FileType.BundleFile;
|
return FileType.BundleFile;
|
||||||
}
|
}
|
||||||
|
Logger.Verbose($"Parsed signature does not match with expected signature {Convert.ToHexString(gunfireMagic)}");
|
||||||
|
Logger.Verbose($"Parsed signature does not match any of the supported signatures, assuming resource file");
|
||||||
return FileType.ResourceFile;
|
return FileType.ResourceFile;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -94,9 +109,12 @@ namespace AssetStudio
|
|||||||
|
|
||||||
private bool IsSerializedFile()
|
private bool IsSerializedFile()
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Attempting to check if the file is serialized file...");
|
||||||
|
|
||||||
var fileSize = BaseStream.Length;
|
var fileSize = BaseStream.Length;
|
||||||
if (fileSize < 20)
|
if (fileSize < 20)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"File size 0x{fileSize:X8} is too small, minimal acceptable size is 0x14, aborting...");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
var m_MetadataSize = ReadUInt32();
|
var m_MetadataSize = ReadUInt32();
|
||||||
@@ -109,6 +127,7 @@ namespace AssetStudio
|
|||||||
{
|
{
|
||||||
if (fileSize < 48)
|
if (fileSize < 48)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"File size 0x{fileSize:X8} for version {m_Version} is too small, minimal acceptable size is 0x30, aborting...");
|
||||||
Position = 0;
|
Position = 0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -119,12 +138,15 @@ namespace AssetStudio
|
|||||||
Position = 0;
|
Position = 0;
|
||||||
if (m_FileSize != fileSize)
|
if (m_FileSize != fileSize)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Parsed file size 0x{m_FileSize:X8} does not match stream size {fileSize}, file might be corrupted, aborting...");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (m_DataOffset > fileSize)
|
if (m_DataOffset > fileSize)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Parsed data offset 0x{m_DataOffset:X8} is outside the stream of the size {fileSize}, file might be corrupted, aborting...");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
Logger.Verbose($"Valid serialized file !!");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -133,8 +155,10 @@ namespace AssetStudio
|
|||||||
{
|
{
|
||||||
public static FileReader PreProcessing(this FileReader reader, Game game)
|
public static FileReader PreProcessing(this FileReader reader, Game game)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Applying preprocessing to file {reader.FileName}");
|
||||||
if (reader.FileType == FileType.ResourceFile || !game.Type.IsNormal())
|
if (reader.FileType == FileType.ResourceFile || !game.Type.IsNormal())
|
||||||
{
|
{
|
||||||
|
Logger.Verbose("File is encrypted !!");
|
||||||
switch (game.Type)
|
switch (game.Type)
|
||||||
{
|
{
|
||||||
case GameType.GI_Pack:
|
case GameType.GI_Pack:
|
||||||
@@ -147,16 +171,13 @@ namespace AssetStudio
|
|||||||
reader = DecryptEnsembleStar(reader);
|
reader = DecryptEnsembleStar(reader);
|
||||||
break;
|
break;
|
||||||
case GameType.OPFP:
|
case GameType.OPFP:
|
||||||
reader = ParseOPFP(reader);
|
|
||||||
break;
|
|
||||||
case GameType.FakeHeader:
|
case GameType.FakeHeader:
|
||||||
|
case GameType.ShiningNikki:
|
||||||
reader = ParseFakeHeader(reader);
|
reader = ParseFakeHeader(reader);
|
||||||
break;
|
break;
|
||||||
case GameType.FantasyOfWind:
|
case GameType.FantasyOfWind:
|
||||||
reader = DecryptFantasyOfWind(reader);
|
reader = DecryptFantasyOfWind(reader);
|
||||||
break;
|
break;
|
||||||
case GameType.ShiningNikki:
|
|
||||||
reader = ParseShiningNikki(reader);
|
|
||||||
break;
|
break;
|
||||||
case GameType.HelixWaltz2:
|
case GameType.HelixWaltz2:
|
||||||
reader = ParseHelixWaltz2(reader);
|
reader = ParseHelixWaltz2(reader);
|
||||||
@@ -174,6 +195,7 @@ namespace AssetStudio
|
|||||||
}
|
}
|
||||||
if (reader.FileType == FileType.BundleFile && game.Type.IsBlockFile())
|
if (reader.FileType == FileType.BundleFile && game.Type.IsBlockFile())
|
||||||
{
|
{
|
||||||
|
Logger.Verbose("File might have multiple bundles !!");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var signature = reader.ReadStringToNull();
|
var signature = reader.ReadStringToNull();
|
||||||
@@ -183,6 +205,8 @@ namespace AssetStudio
|
|||||||
var size = reader.ReadInt64();
|
var size = reader.ReadInt64();
|
||||||
if (!(signature == "UnityFS" && size == reader.BaseStream.Length))
|
if (!(signature == "UnityFS" && size == reader.BaseStream.Length))
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Found signature UnityFS, expected bundle size is 0x{size:X8}, found 0x{reader.BaseStream.Length} instead !!");
|
||||||
|
Logger.Verbose("Loading as block file !!");
|
||||||
reader.FileType = FileType.BlockFile;
|
reader.FileType = FileType.BlockFile;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -190,6 +214,7 @@ namespace AssetStudio
|
|||||||
reader.Position = 0;
|
reader.Position = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger.Verbose("No preprocessing is needed");
|
||||||
return reader;
|
return reader;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ namespace AssetStudio
|
|||||||
public class ImportedFrame
|
public class ImportedFrame
|
||||||
{
|
{
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public Vector3 LocalRotation { get; set; }
|
public Quaternion LocalRotation { get; set; }
|
||||||
public Vector3 LocalPosition { get; set; }
|
public Vector3 LocalPosition { get; set; }
|
||||||
public Vector3 LocalScale { get; set; }
|
public Vector3 LocalScale { get; set; }
|
||||||
public ImportedFrame Parent { get; set; }
|
public ImportedFrame Parent { get; set; }
|
||||||
@@ -248,7 +248,7 @@ namespace AssetStudio
|
|||||||
{
|
{
|
||||||
public string Path { get; set; }
|
public string Path { get; set; }
|
||||||
public List<ImportedKeyframe<Vector3>> Scalings = new List<ImportedKeyframe<Vector3>>();
|
public List<ImportedKeyframe<Vector3>> Scalings = new List<ImportedKeyframe<Vector3>>();
|
||||||
public List<ImportedKeyframe<Vector3>> Rotations = new List<ImportedKeyframe<Vector3>>();
|
public List<ImportedKeyframe<Quaternion>> Rotations = new List<ImportedKeyframe<Quaternion>>();
|
||||||
public List<ImportedKeyframe<Vector3>> Translations = new List<ImportedKeyframe<Vector3>>();
|
public List<ImportedKeyframe<Vector3>> Translations = new List<ImportedKeyframe<Vector3>>();
|
||||||
public ImportedBlendShape BlendShape;
|
public ImportedBlendShape BlendShape;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
@@ -34,4 +35,39 @@ namespace AssetStudio
|
|||||||
Console.WriteLine("[{0}] {1}", loggerEvent, message);
|
Console.WriteLine("[{0}] {1}", loggerEvent, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public sealed class FileLogger : ILogger
|
||||||
|
{
|
||||||
|
private const string LogFileName = "log.txt";
|
||||||
|
private const string PrevLogFileName = "log_prev.txt";
|
||||||
|
private readonly object LockWriter = new object();
|
||||||
|
|
||||||
|
public StreamWriter Writer;
|
||||||
|
|
||||||
|
public FileLogger()
|
||||||
|
{
|
||||||
|
var logPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, LogFileName);
|
||||||
|
var prevLogPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, PrevLogFileName);
|
||||||
|
|
||||||
|
if (File.Exists(logPath))
|
||||||
|
{
|
||||||
|
File.Move(logPath, prevLogPath, true);
|
||||||
|
}
|
||||||
|
Writer = new StreamWriter(logPath, true) { AutoFlush = true };
|
||||||
|
}
|
||||||
|
~FileLogger()
|
||||||
|
{
|
||||||
|
Writer?.Dispose();
|
||||||
|
}
|
||||||
|
public void Log(LoggerEvent loggerEvent, string message, bool silent = false)
|
||||||
|
{
|
||||||
|
if (silent)
|
||||||
|
return;
|
||||||
|
|
||||||
|
lock (LockWriter)
|
||||||
|
{
|
||||||
|
Writer.WriteLine($"[{DateTime.Now}][{loggerEvent}] {message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,9 @@ namespace AssetStudio
|
|||||||
{
|
{
|
||||||
public static void MergeSplitAssets(string path, bool allDirectories = false)
|
public static void MergeSplitAssets(string path, bool allDirectories = false)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Processing split assets (.splitX) prior to loading files...");
|
||||||
var splitFiles = Directory.GetFiles(path, "*.split0", allDirectories ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
|
var splitFiles = Directory.GetFiles(path, "*.split0", allDirectories ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
|
||||||
|
Logger.Verbose($"Found {splitFiles.Length} split files, attempting to merge...");
|
||||||
foreach (var splitFile in splitFiles)
|
foreach (var splitFile in splitFiles)
|
||||||
{
|
{
|
||||||
var destFile = Path.GetFileNameWithoutExtension(splitFile);
|
var destFile = Path.GetFileNameWithoutExtension(splitFile);
|
||||||
@@ -27,6 +29,7 @@ namespace AssetStudio
|
|||||||
if (!File.Exists(destFull))
|
if (!File.Exists(destFull))
|
||||||
{
|
{
|
||||||
var splitParts = Directory.GetFiles(destPath, destFile + ".split*");
|
var splitParts = Directory.GetFiles(destPath, destFile + ".split*");
|
||||||
|
Logger.Verbose($"Creating {destFull} where split files will be combined");
|
||||||
using (var destStream = File.Create(destFull))
|
using (var destStream = File.Create(destFull))
|
||||||
{
|
{
|
||||||
for (int i = 0; i < splitParts.Length; i++)
|
for (int i = 0; i < splitParts.Length; i++)
|
||||||
@@ -35,6 +38,7 @@ namespace AssetStudio
|
|||||||
using (var sourceStream = File.OpenRead(splitPart))
|
using (var sourceStream = File.OpenRead(splitPart))
|
||||||
{
|
{
|
||||||
sourceStream.CopyTo(destStream);
|
sourceStream.CopyTo(destStream);
|
||||||
|
Logger.Verbose($"{splitPart} has been combined into {destFull}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -44,6 +48,7 @@ namespace AssetStudio
|
|||||||
|
|
||||||
public static string[] ProcessingSplitFiles(List<string> selectFile)
|
public static string[] ProcessingSplitFiles(List<string> selectFile)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose("Filter out paths that has .split and has the same name");
|
||||||
var splitFiles = selectFile.Where(x => x.Contains(".split"))
|
var splitFiles = selectFile.Where(x => x.Contains(".split"))
|
||||||
.Select(x => Path.Combine(Path.GetDirectoryName(x), Path.GetFileNameWithoutExtension(x)))
|
.Select(x => Path.Combine(Path.GetDirectoryName(x), Path.GetFileNameWithoutExtension(x)))
|
||||||
.Distinct()
|
.Distinct()
|
||||||
@@ -61,6 +66,7 @@ namespace AssetStudio
|
|||||||
|
|
||||||
public static FileReader DecompressGZip(FileReader reader)
|
public static FileReader DecompressGZip(FileReader reader)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Decompressing GZip file {reader.FileName} into memory");
|
||||||
using (reader)
|
using (reader)
|
||||||
{
|
{
|
||||||
var stream = new MemoryStream();
|
var stream = new MemoryStream();
|
||||||
@@ -75,6 +81,7 @@ namespace AssetStudio
|
|||||||
|
|
||||||
public static FileReader DecompressBrotli(FileReader reader)
|
public static FileReader DecompressBrotli(FileReader reader)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Decompressing Brotli file {reader.FileName} into memory");
|
||||||
using (reader)
|
using (reader)
|
||||||
{
|
{
|
||||||
var stream = new MemoryStream();
|
var stream = new MemoryStream();
|
||||||
@@ -89,24 +96,31 @@ namespace AssetStudio
|
|||||||
|
|
||||||
public static FileReader DecryptPack(FileReader reader, Game game)
|
public static FileReader DecryptPack(FileReader reader, Game game)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Attempting to decrypt file {reader.FileName} with Pack encryption");
|
||||||
|
|
||||||
const int PackSize = 0x880;
|
const int PackSize = 0x880;
|
||||||
const string PackSignature = "pack";
|
const string PackSignature = "pack";
|
||||||
const string UnityFSSignature = "UnityFS";
|
const string UnityFSSignature = "UnityFS";
|
||||||
|
|
||||||
var data = reader.ReadBytes((int)reader.Length);
|
var data = reader.ReadBytes((int)reader.Length);
|
||||||
var idx = data.Search(PackSignature);
|
var packIdx = data.Search(PackSignature);
|
||||||
if (idx == -1)
|
if (packIdx == -1)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Signature {PackSignature} was not found, aborting...");
|
||||||
reader.Position = 0;
|
reader.Position = 0;
|
||||||
return reader;
|
return reader;
|
||||||
}
|
}
|
||||||
idx = data.Search("mr0k", idx);
|
Logger.Verbose($"Found signature {PackSignature} at offset 0x{packIdx:X8}");
|
||||||
if (idx == -1)
|
var mr0kIdx = data.Search("mr0k", packIdx);
|
||||||
|
if (mr0kIdx == -1)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose("Signature mr0k was not found, aborting...");
|
||||||
reader.Position = 0;
|
reader.Position = 0;
|
||||||
return reader;
|
return reader;
|
||||||
}
|
}
|
||||||
|
Logger.Verbose($"Found signature mr0k signature at offset 0x{mr0kIdx:X8}");
|
||||||
|
|
||||||
|
Logger.Verbose("Attempting to process pack chunks...");
|
||||||
var ms = new MemoryStream();
|
var ms = new MemoryStream();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -121,9 +135,12 @@ namespace AssetStudio
|
|||||||
var signature = reader.ReadStringToNull(4);
|
var signature = reader.ReadStringToNull(4);
|
||||||
if (signature == PackSignature)
|
if (signature == PackSignature)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Found {PackSignature} chunk at position {reader.Position - PackSignature.Length}");
|
||||||
var isMr0k = reader.ReadBoolean();
|
var isMr0k = reader.ReadBoolean();
|
||||||
|
Logger.Verbose("Chunk is mr0k encrypted");
|
||||||
var blockSize = BinaryPrimitives.ReadInt32LittleEndian(reader.ReadBytes(4));
|
var blockSize = BinaryPrimitives.ReadInt32LittleEndian(reader.ReadBytes(4));
|
||||||
|
|
||||||
|
Logger.Verbose($"Chunk size is 0x{blockSize:X8}");
|
||||||
Span<byte> buffer = new byte[blockSize];
|
Span<byte> buffer = new byte[blockSize];
|
||||||
reader.Read(buffer);
|
reader.Read(buffer);
|
||||||
if (isMr0k)
|
if (isMr0k)
|
||||||
@@ -134,6 +151,7 @@ namespace AssetStudio
|
|||||||
|
|
||||||
if (bundleSize == 0)
|
if (bundleSize == 0)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose("This is header chunk !! attempting to read the bundle size");
|
||||||
using var blockReader = new EndianBinaryReader(new MemoryStream(buffer.ToArray()));
|
using var blockReader = new EndianBinaryReader(new MemoryStream(buffer.ToArray()));
|
||||||
var header = new Header()
|
var header = new Header()
|
||||||
{
|
{
|
||||||
@@ -144,17 +162,21 @@ namespace AssetStudio
|
|||||||
size = blockReader.ReadInt64()
|
size = blockReader.ReadInt64()
|
||||||
};
|
};
|
||||||
bundleSize = header.size;
|
bundleSize = header.size;
|
||||||
|
Logger.Verbose($"Bundle size is 0x{bundleSize:X8}");
|
||||||
}
|
}
|
||||||
|
|
||||||
readSize += buffer.Length;
|
readSize += buffer.Length;
|
||||||
|
|
||||||
if (readSize % (PackSize - 0x80) == 0)
|
if (readSize % (PackSize - 0x80) == 0)
|
||||||
{
|
{
|
||||||
reader.Position += PackSize - 9 - blockSize;
|
var padding = PackSize - 9 - blockSize;
|
||||||
|
reader.Position += padding;
|
||||||
|
Logger.Verbose($"Skip 0x{padding:X8} padding");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (readSize == bundleSize)
|
if (readSize == bundleSize)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Bundle has been read entirely !!");
|
||||||
readSize = 0;
|
readSize = 0;
|
||||||
bundleSize = 0;
|
bundleSize = 0;
|
||||||
}
|
}
|
||||||
@@ -166,6 +188,7 @@ namespace AssetStudio
|
|||||||
signature = reader.ReadStringToNull();
|
signature = reader.ReadStringToNull();
|
||||||
if (signature == UnityFSSignature)
|
if (signature == UnityFSSignature)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Found {UnityFSSignature} chunk at position {reader.Position - (UnityFSSignature.Length + 1)}");
|
||||||
var header = new Header()
|
var header = new Header()
|
||||||
{
|
{
|
||||||
signature = reader.ReadStringToNull(),
|
signature = reader.ReadStringToNull(),
|
||||||
@@ -175,6 +198,7 @@ namespace AssetStudio
|
|||||||
size = reader.ReadInt64()
|
size = reader.ReadInt64()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Logger.Verbose($"Bundle size is 0x{header.size:X8}");
|
||||||
reader.Position = pos;
|
reader.Position = pos;
|
||||||
reader.BaseStream.CopyTo(ms, header.size);
|
reader.BaseStream.CopyTo(ms, header.size);
|
||||||
continue;
|
continue;
|
||||||
@@ -196,15 +220,19 @@ namespace AssetStudio
|
|||||||
reader.Dispose();
|
reader.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger.Verbose("Decrypted pack file successfully !!");
|
||||||
ms.Position = 0;
|
ms.Position = 0;
|
||||||
return new FileReader(reader.FullPath, ms);
|
return new FileReader(reader.FullPath, ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FileReader DecryptMark(FileReader reader)
|
public static FileReader DecryptMark(FileReader reader)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Attempting to decrypt file {reader.FileName} with Mark encryption");
|
||||||
|
|
||||||
var signature = reader.ReadStringToNull(4);
|
var signature = reader.ReadStringToNull(4);
|
||||||
if (signature != "mark")
|
if (signature != "mark")
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Expected signature mark, found {signature} instead, aborting...");
|
||||||
reader.Position = 0;
|
reader.Position = 0;
|
||||||
return reader;
|
return reader;
|
||||||
}
|
}
|
||||||
@@ -240,6 +268,7 @@ namespace AssetStudio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger.Verbose("Decrypted mark file successfully !!");
|
||||||
reader.Dispose();
|
reader.Dispose();
|
||||||
dataStream.Position = 0;
|
dataStream.Position = 0;
|
||||||
return new FileReader(reader.FullPath, dataStream);
|
return new FileReader(reader.FullPath, dataStream);
|
||||||
@@ -247,8 +276,10 @@ namespace AssetStudio
|
|||||||
|
|
||||||
public static FileReader DecryptEnsembleStar(FileReader reader)
|
public static FileReader DecryptEnsembleStar(FileReader reader)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Attempting to decrypt file {reader.FileName} with Ensemble Star encryption");
|
||||||
if (Path.GetExtension(reader.FileName) != ".z")
|
if (Path.GetExtension(reader.FileName) != ".z")
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Expected file extension .z, found {Path.GetExtension(reader.FileName)} instead, aborting...");
|
||||||
return reader;
|
return reader;
|
||||||
}
|
}
|
||||||
using (reader)
|
using (reader)
|
||||||
@@ -269,46 +300,42 @@ namespace AssetStudio
|
|||||||
data[i] = (byte)(EnsembleStarKey1[k1] ^ ((size ^ EnsembleStarKey3[k3] ^ data[i] ^ EnsembleStarKey2[k2]) + remaining));
|
data[i] = (byte)(EnsembleStarKey1[k1] ^ ((size ^ EnsembleStarKey3[k3] ^ data[i] ^ EnsembleStarKey2[k2]) + remaining));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger.Verbose("Decrypted Ensemble Star file successfully !!");
|
||||||
return new FileReader(reader.FullPath, new MemoryStream(data));
|
return new FileReader(reader.FullPath, new MemoryStream(data));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FileReader ParseOPFP(FileReader reader)
|
|
||||||
{
|
|
||||||
var stream = reader.BaseStream;
|
|
||||||
var data = reader.ReadBytes(0x1000);
|
|
||||||
var idx = data.Search("UnityFS");
|
|
||||||
if (idx != -1)
|
|
||||||
{
|
|
||||||
stream = new OffsetStream(stream, idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new FileReader(reader.FullPath, stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static FileReader ParseFakeHeader(FileReader reader)
|
public static FileReader ParseFakeHeader(FileReader reader)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Attempting to parse file {reader.FileName} with fake header");
|
||||||
|
|
||||||
var stream = reader.BaseStream;
|
var stream = reader.BaseStream;
|
||||||
var data = reader.ReadBytes(0x1000);
|
var data = reader.ReadBytes(0x1000);
|
||||||
var idx = data.Search("UnityFS");
|
var idx = data.Search("UnityFS");
|
||||||
if (idx != -1)
|
if (idx != -1)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Found fake header at offset 0x{idx:X8}");
|
||||||
var idx2 = data[(idx + 1)..].Search("UnityFS");
|
var idx2 = data[(idx + 1)..].Search("UnityFS");
|
||||||
if (idx2 != -1)
|
if (idx2 != -1)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Found real header at offset 0x{idx + idx2 + 1:X8}");
|
||||||
stream = new OffsetStream(stream, idx + idx2 + 1);
|
stream = new OffsetStream(stream, idx + idx2 + 1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Logger.Verbose("Real header was not found, assuming fake header is the real one");
|
||||||
stream = new OffsetStream(stream, idx);
|
stream = new OffsetStream(stream, idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger.Verbose("Parsed fake header file successfully !!");
|
||||||
return new FileReader(reader.FullPath, stream);
|
return new FileReader(reader.FullPath, stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FileReader DecryptFantasyOfWind(FileReader reader)
|
public static FileReader DecryptFantasyOfWind(FileReader reader)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Attempting to decrypt file {reader.FileName} with Fantasy of Wind encryption");
|
||||||
|
|
||||||
byte[] encryptKeyName = Encoding.UTF8.GetBytes("28856");
|
byte[] encryptKeyName = Encoding.UTF8.GetBytes("28856");
|
||||||
const int MinLength = 0xC8;
|
const int MinLength = 0xC8;
|
||||||
const int KeyLength = 8;
|
const int KeyLength = 8;
|
||||||
@@ -319,6 +346,7 @@ namespace AssetStudio
|
|||||||
var signature = reader.ReadStringToNull(HeadLength);
|
var signature = reader.ReadStringToNull(HeadLength);
|
||||||
if (string.Compare(signature, "K9999") > 0 || reader.Length <= MinLength)
|
if (string.Compare(signature, "K9999") > 0 || reader.Length <= MinLength)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Signature version {signature} is higher than K9999 or stream length {reader.Length} is less than minimum length {MinLength}, aborting...");
|
||||||
reader.Position = 0;
|
reader.Position = 0;
|
||||||
return reader;
|
return reader;
|
||||||
}
|
}
|
||||||
@@ -360,23 +388,13 @@ namespace AssetStudio
|
|||||||
reader.BaseStream.CopyTo(ms);
|
reader.BaseStream.CopyTo(ms);
|
||||||
ms.Position = 0;
|
ms.Position = 0;
|
||||||
|
|
||||||
|
Logger.Verbose("Decrypted Fantasy of Wind file successfully !!");
|
||||||
return new FileReader(reader.FullPath, ms);
|
return new FileReader(reader.FullPath, ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FileReader ParseShiningNikki(FileReader reader)
|
|
||||||
{
|
|
||||||
var data = reader.ReadBytes(0x1000);
|
|
||||||
var idx = data.Search("UnityFS");
|
|
||||||
if (idx == -1)
|
|
||||||
{
|
|
||||||
reader.Position = 0;
|
|
||||||
return reader;
|
|
||||||
}
|
|
||||||
var stream = new OffsetStream(reader.BaseStream, idx);
|
|
||||||
return new FileReader(reader.FullPath, stream);
|
|
||||||
}
|
|
||||||
public static FileReader ParseHelixWaltz2(FileReader reader)
|
public static FileReader ParseHelixWaltz2(FileReader reader)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Attempting to decrypt file {reader.FileName} with Helix Waltz 2 encryption");
|
||||||
|
|
||||||
var originalHeader = new byte[] { 0x55, 0x6E, 0x69, 0x74, 0x79, 0x46, 0x53, 0x00, 0x00, 0x00, 0x00, 0x07, 0x35, 0x2E, 0x78, 0x2E };
|
var originalHeader = new byte[] { 0x55, 0x6E, 0x69, 0x74, 0x79, 0x46, 0x53, 0x00, 0x00, 0x00, 0x00, 0x07, 0x35, 0x2E, 0x78, 0x2E };
|
||||||
|
|
||||||
var signature = reader.ReadStringToNull();
|
var signature = reader.ReadStringToNull();
|
||||||
@@ -384,6 +402,7 @@ namespace AssetStudio
|
|||||||
|
|
||||||
if (signature != "SzxFS")
|
if (signature != "SzxFS")
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Expected signature SzxFS, found {signature} instead, aborting...");
|
||||||
reader.Position = 0;
|
reader.Position = 0;
|
||||||
return reader;
|
return reader;
|
||||||
}
|
}
|
||||||
@@ -415,6 +434,7 @@ namespace AssetStudio
|
|||||||
data[i] = key[idx];
|
data[i] = key[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger.Verbose("Decrypted Helix Waltz 2 file successfully !!");
|
||||||
MemoryStream ms = new();
|
MemoryStream ms = new();
|
||||||
ms.Write(originalHeader);
|
ms.Write(originalHeader);
|
||||||
ms.Write(data);
|
ms.Write(data);
|
||||||
@@ -424,6 +444,8 @@ namespace AssetStudio
|
|||||||
}
|
}
|
||||||
public static FileReader DecryptAnchorPanic(FileReader reader)
|
public static FileReader DecryptAnchorPanic(FileReader reader)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Attempting to decrypt file {reader.FileName} with Anchor Panic encryption");
|
||||||
|
|
||||||
const int BlockSize = 0x800;
|
const int BlockSize = 0x800;
|
||||||
|
|
||||||
var data = reader.ReadBytes(0x1000);
|
var data = reader.ReadBytes(0x1000);
|
||||||
@@ -432,25 +454,31 @@ namespace AssetStudio
|
|||||||
var idx = data.Search("UnityFS");
|
var idx = data.Search("UnityFS");
|
||||||
if (idx != -1)
|
if (idx != -1)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose("Found UnityFS signature, file might not be encrypted");
|
||||||
return ParseFakeHeader(reader);
|
return ParseFakeHeader(reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
var key = GetKey(Path.GetFileNameWithoutExtension(reader.FileName));
|
var key = GetKey(Path.GetFileNameWithoutExtension(reader.FileName));
|
||||||
|
Logger.Verbose($"Calculated key is {key}");
|
||||||
|
|
||||||
var chunkIndex = 0;
|
var chunkIndex = 0;
|
||||||
MemoryStream ms = new();
|
MemoryStream ms = new();
|
||||||
while (reader.Remaining > 0)
|
while (reader.Remaining > 0)
|
||||||
{
|
{
|
||||||
var chunkSize = Math.Min((int)reader.Remaining, BlockSize);
|
var chunkSize = Math.Min((int)reader.Remaining, BlockSize);
|
||||||
|
Logger.Verbose($"Chunk {chunkIndex} size is {chunkSize}");
|
||||||
var chunk = reader.ReadBytes(chunkSize);
|
var chunk = reader.ReadBytes(chunkSize);
|
||||||
if (IsEncrypt((int)reader.Length, chunkIndex++))
|
if (IsEncrypt((int)reader.Length, chunkIndex++))
|
||||||
|
{
|
||||||
|
Logger.Verbose($"Chunk {chunkIndex} is encrypted, decrypting...");
|
||||||
RC4(chunk, key);
|
RC4(chunk, key);
|
||||||
|
}
|
||||||
|
|
||||||
ms.Write(chunk);
|
ms.Write(chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger.Verbose("Decrypted Anchor Panic file successfully !!");
|
||||||
ms.Position = 0;
|
ms.Position = 0;
|
||||||
|
|
||||||
return new FileReader(reader.FullPath, ms);
|
return new FileReader(reader.FullPath, ms);
|
||||||
|
|
||||||
bool IsEncrypt(int fileSize, int chunkIndex)
|
bool IsEncrypt(int fileSize, int chunkIndex)
|
||||||
@@ -533,11 +561,14 @@ namespace AssetStudio
|
|||||||
|
|
||||||
public static FileReader DecryptDreamscapeAlbireo(FileReader reader)
|
public static FileReader DecryptDreamscapeAlbireo(FileReader reader)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Attempting to decrypt file {reader.FileName} with Dreamscape Albireo encryption");
|
||||||
|
|
||||||
var key = new byte[] { 0x1E, 0x1E, 0x01, 0x01, 0xFC };
|
var key = new byte[] { 0x1E, 0x1E, 0x01, 0x01, 0xFC };
|
||||||
|
|
||||||
var signature = reader.ReadStringToNull(4);
|
var signature = reader.ReadStringToNull(4);
|
||||||
if (signature != "MJJ")
|
if (signature != "MJJ")
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Expected signature MJJ, found {signature} instead, aborting...");
|
||||||
reader.Position = 0;
|
reader.Position = 0;
|
||||||
return reader;
|
return reader;
|
||||||
}
|
}
|
||||||
@@ -559,6 +590,8 @@ namespace AssetStudio
|
|||||||
var sizeLow = (u5 >> 24 | (u2 << 8)) ^ u1;
|
var sizeLow = (u5 >> 24 | (u2 << 8)) ^ u1;
|
||||||
var size = (long)(sizeHigh << 32 | sizeLow);
|
var size = (long)(sizeHigh << 32 | sizeLow);
|
||||||
|
|
||||||
|
Logger.Verbose($"Decrypted File info: Flag 0x{flag:X8} | Compressed blockInfo size 0x{compressedBlocksInfoSize:X8} | Decompressed blockInfo size 0x{uncompressedBlocksInfoSize:X8} | Bundle size 0x{size:X8}");
|
||||||
|
|
||||||
var blocksInfo = reader.ReadBytes((int)compressedBlocksInfoSize);
|
var blocksInfo = reader.ReadBytes((int)compressedBlocksInfoSize);
|
||||||
for(int i = 0; i < blocksInfo.Length; i++)
|
for(int i = 0; i < blocksInfo.Length; i++)
|
||||||
{
|
{
|
||||||
@@ -587,6 +620,7 @@ namespace AssetStudio
|
|||||||
reader.BaseStream.CopyTo(ms);
|
reader.BaseStream.CopyTo(ms);
|
||||||
ms.Position = 0;
|
ms.Position = 0;
|
||||||
|
|
||||||
|
Logger.Verbose("Decrypted Dreamscape Albireo file successfully !!");
|
||||||
return new FileReader(reader.FullPath, ms);
|
return new FileReader(reader.FullPath, ms);
|
||||||
|
|
||||||
static uint Scrample(uint value) => (value >> 5) & 0xFFE000 | (value >> 29) | (value << 14) & 0xFF000000 | (8 * value) & 0x1FF8;
|
static uint Scrample(uint value) => (value >> 5) & 0xFFE000 | (value >> 29) | (value << 14) & 0xFF000000 | (8 * value) & 0x1FF8;
|
||||||
@@ -594,6 +628,8 @@ namespace AssetStudio
|
|||||||
|
|
||||||
public static FileReader DecryptImaginaryFest(FileReader reader)
|
public static FileReader DecryptImaginaryFest(FileReader reader)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Attempting to decrypt file {reader.FileName} with Imaginary Fest encryption");
|
||||||
|
|
||||||
const string dataRoot = "data";
|
const string dataRoot = "data";
|
||||||
var key = new byte[] { 0xBD, 0x65, 0xF2, 0x4F, 0xBE, 0xD1, 0x36, 0xD4, 0x95, 0xFE, 0x64, 0x94, 0xCB, 0xD3, 0x7E, 0x91, 0x57, 0xB7, 0x94, 0xB7, 0x9F, 0x70, 0xB2, 0xA9, 0xA0, 0xD5, 0x4E, 0x36, 0xC6, 0x40, 0xE0, 0x2F, 0x4E, 0x6E, 0x76, 0x6D, 0xCD, 0xAE, 0xEA, 0x05, 0x13, 0x6B, 0xA7, 0x84, 0xFF, 0xED, 0x90, 0x91, 0x15, 0x7E, 0xF1, 0xF8, 0xA5, 0x9C, 0xB6, 0xDE, 0xF9, 0x56, 0x57, 0x18, 0xBF, 0x94, 0x63, 0x6F, 0x1B, 0xE2, 0x92, 0xD2, 0x7E, 0x25, 0x95, 0x23, 0x24, 0xCB, 0x93, 0xD3, 0x36, 0xD9, 0x18, 0x11, 0xF5, 0x50, 0x18, 0xE4, 0x22, 0x28, 0xD8, 0xE2, 0x1A, 0x57, 0x1E, 0x04, 0x88, 0xA5, 0x84, 0xC0, 0x6C, 0x3B, 0x46, 0x62, 0xCE, 0x85, 0x10, 0x2E, 0xA0, 0xDC, 0xD3, 0x09, 0xB2, 0xB6, 0xA4, 0x8D, 0xAF, 0x74, 0x36, 0xF7, 0x9A, 0x3F, 0x98, 0xDA, 0x62, 0x57, 0x71, 0x75, 0x92, 0x05, 0xA3, 0xB2, 0x7C, 0xCA, 0xFB, 0x1E, 0xBE, 0xC9, 0x24, 0xC1, 0xD2, 0xB9, 0xDE, 0xE4, 0x7E, 0xF3, 0x0F, 0xB4, 0xFB, 0xA2, 0xC1, 0xC2, 0x14, 0x5C, 0x78, 0x13, 0x74, 0x41, 0x8D, 0x79, 0xF4, 0x3C, 0x49, 0x92, 0x98, 0xF2, 0xCD, 0x8C, 0x09, 0xA6, 0x40, 0x34, 0x51, 0x1C, 0x11, 0x2B, 0xE0, 0x6B, 0x42, 0x9C, 0x86, 0x41, 0x06, 0xF6, 0xD2, 0x87, 0xF1, 0x10, 0x26, 0x89, 0xC2, 0x7B, 0x2A, 0x5D, 0x1C, 0xDA, 0x92, 0xC8, 0x93, 0x59, 0xF9, 0x60, 0xD0, 0xB5, 0x1E, 0xD5, 0x75, 0x56, 0xA0, 0x05, 0x83, 0x90, 0xAC, 0x72, 0xC8, 0x10, 0x09, 0xED, 0x1A, 0x46, 0xD9, 0x39, 0x6B, 0x9E, 0x19, 0x5E, 0x51, 0x44, 0x09, 0x0D, 0x74, 0xAB, 0xA8, 0xF9, 0x32, 0x43, 0xBC, 0xD2, 0xED, 0x7B, 0x6C, 0x75, 0x32, 0x24, 0x14, 0x43, 0x5D, 0x98, 0xB2, 0xFC, 0xFB, 0xF5, 0x9A, 0x19, 0x03, 0xB0, 0xB7, 0xAC, 0xAE, 0x8B };
|
var key = new byte[] { 0xBD, 0x65, 0xF2, 0x4F, 0xBE, 0xD1, 0x36, 0xD4, 0x95, 0xFE, 0x64, 0x94, 0xCB, 0xD3, 0x7E, 0x91, 0x57, 0xB7, 0x94, 0xB7, 0x9F, 0x70, 0xB2, 0xA9, 0xA0, 0xD5, 0x4E, 0x36, 0xC6, 0x40, 0xE0, 0x2F, 0x4E, 0x6E, 0x76, 0x6D, 0xCD, 0xAE, 0xEA, 0x05, 0x13, 0x6B, 0xA7, 0x84, 0xFF, 0xED, 0x90, 0x91, 0x15, 0x7E, 0xF1, 0xF8, 0xA5, 0x9C, 0xB6, 0xDE, 0xF9, 0x56, 0x57, 0x18, 0xBF, 0x94, 0x63, 0x6F, 0x1B, 0xE2, 0x92, 0xD2, 0x7E, 0x25, 0x95, 0x23, 0x24, 0xCB, 0x93, 0xD3, 0x36, 0xD9, 0x18, 0x11, 0xF5, 0x50, 0x18, 0xE4, 0x22, 0x28, 0xD8, 0xE2, 0x1A, 0x57, 0x1E, 0x04, 0x88, 0xA5, 0x84, 0xC0, 0x6C, 0x3B, 0x46, 0x62, 0xCE, 0x85, 0x10, 0x2E, 0xA0, 0xDC, 0xD3, 0x09, 0xB2, 0xB6, 0xA4, 0x8D, 0xAF, 0x74, 0x36, 0xF7, 0x9A, 0x3F, 0x98, 0xDA, 0x62, 0x57, 0x71, 0x75, 0x92, 0x05, 0xA3, 0xB2, 0x7C, 0xCA, 0xFB, 0x1E, 0xBE, 0xC9, 0x24, 0xC1, 0xD2, 0xB9, 0xDE, 0xE4, 0x7E, 0xF3, 0x0F, 0xB4, 0xFB, 0xA2, 0xC1, 0xC2, 0x14, 0x5C, 0x78, 0x13, 0x74, 0x41, 0x8D, 0x79, 0xF4, 0x3C, 0x49, 0x92, 0x98, 0xF2, 0xCD, 0x8C, 0x09, 0xA6, 0x40, 0x34, 0x51, 0x1C, 0x11, 0x2B, 0xE0, 0x6B, 0x42, 0x9C, 0x86, 0x41, 0x06, 0xF6, 0xD2, 0x87, 0xF1, 0x10, 0x26, 0x89, 0xC2, 0x7B, 0x2A, 0x5D, 0x1C, 0xDA, 0x92, 0xC8, 0x93, 0x59, 0xF9, 0x60, 0xD0, 0xB5, 0x1E, 0xD5, 0x75, 0x56, 0xA0, 0x05, 0x83, 0x90, 0xAC, 0x72, 0xC8, 0x10, 0x09, 0xED, 0x1A, 0x46, 0xD9, 0x39, 0x6B, 0x9E, 0x19, 0x5E, 0x51, 0x44, 0x09, 0x0D, 0x74, 0xAB, 0xA8, 0xF9, 0x32, 0x43, 0xBC, 0xD2, 0xED, 0x7B, 0x6C, 0x75, 0x32, 0x24, 0x14, 0x43, 0x5D, 0x98, 0xB2, 0xFC, 0xFB, 0xF5, 0x9A, 0x19, 0x03, 0xB0, 0xB7, 0xAC, 0xAE, 0x8B };
|
||||||
|
|
||||||
@@ -601,12 +637,14 @@ namespace AssetStudio
|
|||||||
var signature = Encoding.UTF8.GetString(signatureBytes[..7]);
|
var signature = Encoding.UTF8.GetString(signatureBytes[..7]);
|
||||||
if (signature == "UnityFS")
|
if (signature == "UnityFS")
|
||||||
{
|
{
|
||||||
|
Logger.Verbose("Found UnityFS signature, file might not be encrypted");
|
||||||
reader.Position = 0;
|
reader.Position = 0;
|
||||||
return reader;
|
return reader;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (signatureBytes[7] != 0)
|
if (signatureBytes[7] != 0)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"File might be encrypted with a byte xorkey 0x{signatureBytes[7]:X8}, attemping to decrypting...");
|
||||||
var xorKey = signatureBytes[7];
|
var xorKey = signatureBytes[7];
|
||||||
for (int i = 0; i < signatureBytes.Length; i++)
|
for (int i = 0; i < signatureBytes.Length; i++)
|
||||||
{
|
{
|
||||||
@@ -615,12 +653,14 @@ namespace AssetStudio
|
|||||||
signature = Encoding.UTF8.GetString(signatureBytes[..7]);
|
signature = Encoding.UTF8.GetString(signatureBytes[..7]);
|
||||||
if (signature == "UnityFS")
|
if (signature == "UnityFS")
|
||||||
{
|
{
|
||||||
|
Logger.Verbose("Found UnityFS signature, key is valid, decrypting the rest of the stream");
|
||||||
var remaining = reader.ReadBytes((int)reader.Remaining);
|
var remaining = reader.ReadBytes((int)reader.Remaining);
|
||||||
for (int i = 0; i < remaining.Length; i++)
|
for (int i = 0; i < remaining.Length; i++)
|
||||||
{
|
{
|
||||||
remaining[i] ^= xorKey;
|
remaining[i] ^= xorKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger.Verbose("Decrypted Imaginary Fest file successfully !!");
|
||||||
var stream = new MemoryStream();
|
var stream = new MemoryStream();
|
||||||
stream.Write(signatureBytes);
|
stream.Write(signatureBytes);
|
||||||
stream.Write(remaining);
|
stream.Write(remaining);
|
||||||
@@ -635,25 +675,33 @@ namespace AssetStudio
|
|||||||
var startIdx = Array.FindIndex(paths, x => x == dataRoot);
|
var startIdx = Array.FindIndex(paths, x => x == dataRoot);
|
||||||
if (startIdx != -1 && startIdx != paths.Length - 1)
|
if (startIdx != -1 && startIdx != paths.Length - 1)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose("File is in the data folder !!");
|
||||||
var path = string.Join(Path.AltDirectorySeparatorChar, paths[(startIdx+1)..]);
|
var path = string.Join(Path.AltDirectorySeparatorChar, paths[(startIdx+1)..]);
|
||||||
var offset = GetLoadAssetBundleOffset(path);
|
var offset = GetLoadAssetBundleOffset(path);
|
||||||
if (offset > 0 && offset < reader.Length)
|
if (offset > 0 && offset < reader.Length)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Calculated offset is 0x{offset:X8}, attempting to read signature...");
|
||||||
reader.Position = offset;
|
reader.Position = offset;
|
||||||
signature = reader.ReadStringToNull(7);
|
signature = reader.ReadStringToNull(7);
|
||||||
if (signature == "UnityFS")
|
if (signature == "UnityFS")
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Found UnityFS signature, file starts at 0x{offset:X8} !!");
|
||||||
|
Logger.Verbose("Parsed Imaginary Fest file successfully !!");
|
||||||
reader.Position = offset;
|
reader.Position = offset;
|
||||||
return new FileReader(reader.FullPath, new MemoryStream(reader.ReadBytes((int)reader.Remaining)));
|
return new FileReader(reader.FullPath, new MemoryStream(reader.ReadBytes((int)reader.Remaining)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Logger.Verbose($"Invalid offset, attempting to generate key...");
|
||||||
reader.Position = 0;
|
reader.Position = 0;
|
||||||
var data = reader.ReadBytes((int)reader.Remaining);
|
var data = reader.ReadBytes((int)reader.Remaining);
|
||||||
var key_value = GetHashCode(path);
|
var key_value = GetHashCode(path);
|
||||||
|
Logger.Verbose($"Generated key is 0x{key_value:X8}, decrypting...");
|
||||||
Decrypt(data, key_value);
|
Decrypt(data, key_value);
|
||||||
|
Logger.Verbose("Decrypted Imaginary Fest file successfully !!");
|
||||||
return new FileReader(reader.FullPath, new MemoryStream(data));
|
return new FileReader(reader.FullPath, new MemoryStream(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger.Verbose("File doesn't match any of the encryption types");
|
||||||
reader.Position = 0;
|
reader.Position = 0;
|
||||||
return reader;
|
return reader;
|
||||||
|
|
||||||
|
|||||||
@@ -9,5 +9,13 @@ namespace AssetStudio
|
|||||||
{
|
{
|
||||||
public int localSerializedFileIndex;
|
public int localSerializedFileIndex;
|
||||||
public long localIdentifierInFile;
|
public long localIdentifierInFile;
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.Append($"localSerializedFileIndex: {localSerializedFileIndex} | ");
|
||||||
|
sb.Append($"localIdentifierInFile: {localIdentifierInFile}");
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
@@ -7,21 +8,79 @@ namespace AssetStudio
|
|||||||
{
|
{
|
||||||
public static class Logger
|
public static class Logger
|
||||||
{
|
{
|
||||||
public static ILogger Default = new DummyLogger();
|
private static bool _fileLogging = true;
|
||||||
public static bool Silent = false;
|
|
||||||
|
|
||||||
public static void Verbose(string message) => Default.Log(LoggerEvent.Verbose, message, Silent);
|
public static ILogger Default = new DummyLogger();
|
||||||
public static void Debug(string message) => Default.Log(LoggerEvent.Debug, message, Silent);
|
public static ILogger File;
|
||||||
public static void Info(string message) => Default.Log(LoggerEvent.Info, message, Silent);
|
public static bool Silent = false;
|
||||||
public static void Warning(string message) => Default.Log(LoggerEvent.Warning, message, Silent);
|
public static bool LogVerbose = false;
|
||||||
public static void Error(string message) => Default.Log(LoggerEvent.Error, message, Silent);
|
|
||||||
|
public static bool FileLogging
|
||||||
|
{
|
||||||
|
get => _fileLogging;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_fileLogging = value;
|
||||||
|
if (_fileLogging)
|
||||||
|
{
|
||||||
|
File = new FileLogger();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
((FileLogger)File)?.Writer?.Dispose();
|
||||||
|
File = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Verbose(string message)
|
||||||
|
{
|
||||||
|
if (LogVerbose)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var callerMethod = new StackTrace().GetFrame(1).GetMethod();
|
||||||
|
var callerMethodClass = callerMethod.ReflectedType.Name;
|
||||||
|
if (!string.IsNullOrEmpty(callerMethodClass))
|
||||||
|
{
|
||||||
|
message = $"[{callerMethodClass}] {message}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception) { }
|
||||||
|
if (FileLogging) File.Log(LoggerEvent.Verbose, message);
|
||||||
|
Default.Log(LoggerEvent.Verbose, message, Silent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static void Debug(string message)
|
||||||
|
{
|
||||||
|
if (FileLogging) File.Log(LoggerEvent.Debug, message);
|
||||||
|
Default.Log(LoggerEvent.Debug, message, Silent);
|
||||||
|
}
|
||||||
|
public static void Info(string message)
|
||||||
|
{
|
||||||
|
if (FileLogging) File.Log(LoggerEvent.Info, message);
|
||||||
|
Default.Log(LoggerEvent.Info, message, Silent);
|
||||||
|
}
|
||||||
|
public static void Warning(string message)
|
||||||
|
{
|
||||||
|
if (FileLogging) File.Log(LoggerEvent.Warning, message);
|
||||||
|
Default.Log(LoggerEvent.Warning, message, Silent);
|
||||||
|
}
|
||||||
|
public static void Error(string message)
|
||||||
|
{
|
||||||
|
if (FileLogging) File.Log(LoggerEvent.Error, message);
|
||||||
|
Default.Log(LoggerEvent.Error, message, Silent);
|
||||||
|
}
|
||||||
|
|
||||||
public static void Error(string message, Exception e)
|
public static void Error(string message, Exception e)
|
||||||
{
|
{
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
sb.AppendLine(message);
|
sb.AppendLine(message);
|
||||||
sb.AppendLine(e.ToString());
|
sb.AppendLine(e.ToString());
|
||||||
Default.Log(LoggerEvent.Error, sb.ToString(), Silent);
|
|
||||||
|
message = sb.ToString();
|
||||||
|
if (FileLogging) File.Log(LoggerEvent.Error, message);
|
||||||
|
Default.Log(LoggerEvent.Error, message, Silent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ namespace AssetStudio
|
|||||||
return X.Equals(other.X) && Y.Equals(other.Y) && Z.Equals(other.Z) && W.Equals(other.W);
|
return X.Equals(other.X) && Y.Equals(other.Y) && Z.Equals(other.Z) && W.Equals(other.W);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Quaternion Zero => new Quaternion(0, 0, 0, 1);
|
||||||
public static float Dot(Quaternion a, Quaternion b)
|
public static float Dot(Quaternion a, Quaternion b)
|
||||||
{
|
{
|
||||||
return a.X * b.X + a.Y * b.Y + a.Z * b.Z + a.W * b.W;
|
return a.X * b.X + a.Y * b.Y + a.Z * b.Z + a.W * b.W;
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ namespace AssetStudio
|
|||||||
public long Offset;
|
public long Offset;
|
||||||
public Mhy0 mhy0;
|
public Mhy0 mhy0;
|
||||||
|
|
||||||
|
public long TotalSize => 8 + m_Header.compressedBlocksInfoSize + m_BlocksInfo.Sum(x => x.compressedSize);
|
||||||
|
|
||||||
public Mhy0File(FileReader reader, string path, Mhy0 mhy0)
|
public Mhy0File(FileReader reader, string path, Mhy0 mhy0)
|
||||||
{
|
{
|
||||||
this.mhy0 = mhy0;
|
this.mhy0 = mhy0;
|
||||||
@@ -22,6 +24,10 @@ namespace AssetStudio
|
|||||||
reader.Endian = EndianType.LittleEndian;
|
reader.Endian = EndianType.LittleEndian;
|
||||||
|
|
||||||
var signature = reader.ReadStringToNull(4);
|
var signature = reader.ReadStringToNull(4);
|
||||||
|
Logger.Verbose($"Parsed signature {signature}");
|
||||||
|
if (signature != "mhy0")
|
||||||
|
throw new Exception("not a mhy0");
|
||||||
|
|
||||||
m_Header = new BundleFile.Header
|
m_Header = new BundleFile.Header
|
||||||
{
|
{
|
||||||
version = 6,
|
version = 6,
|
||||||
@@ -30,6 +36,7 @@ namespace AssetStudio
|
|||||||
compressedBlocksInfoSize = reader.ReadUInt32(),
|
compressedBlocksInfoSize = reader.ReadUInt32(),
|
||||||
flags = (ArchiveFlags)0x43
|
flags = (ArchiveFlags)0x43
|
||||||
};
|
};
|
||||||
|
Logger.Verbose($"Header: {m_Header}");
|
||||||
ReadBlocksInfoAndDirectory(reader);
|
ReadBlocksInfoAndDirectory(reader);
|
||||||
using var blocksStream = CreateBlocksStream(path);
|
using var blocksStream = CreateBlocksStream(path);
|
||||||
ReadBlocks(reader, blocksStream);
|
ReadBlocks(reader, blocksStream);
|
||||||
@@ -41,9 +48,11 @@ namespace AssetStudio
|
|||||||
var blocksInfo = reader.ReadBytes((int)m_Header.compressedBlocksInfoSize);
|
var blocksInfo = reader.ReadBytes((int)m_Header.compressedBlocksInfoSize);
|
||||||
DescrambleHeader(blocksInfo);
|
DescrambleHeader(blocksInfo);
|
||||||
|
|
||||||
|
Logger.Verbose($"Descrambled blocksInfo signature {Convert.ToHexString(blocksInfo, 0 , 4)}");
|
||||||
using var blocksInfoStream = new MemoryStream(blocksInfo, 0x20, (int)m_Header.compressedBlocksInfoSize - 0x20);
|
using var blocksInfoStream = new MemoryStream(blocksInfo, 0x20, (int)m_Header.compressedBlocksInfoSize - 0x20);
|
||||||
using var blocksInfoReader = new EndianBinaryReader(blocksInfoStream);
|
using var blocksInfoReader = new EndianBinaryReader(blocksInfoStream);
|
||||||
m_Header.uncompressedBlocksInfoSize = blocksInfoReader.ReadMhy0UInt();
|
m_Header.uncompressedBlocksInfoSize = blocksInfoReader.ReadMhy0UInt();
|
||||||
|
Logger.Verbose($"uncompressed blocksInfo size: 0x{m_Header.uncompressedBlocksInfoSize:X8}");
|
||||||
var compressedBlocksInfo = blocksInfoReader.ReadBytes((int)blocksInfoReader.Remaining);
|
var compressedBlocksInfo = blocksInfoReader.ReadBytes((int)blocksInfoReader.Remaining);
|
||||||
var uncompressedBlocksInfo = new byte[(int)m_Header.uncompressedBlocksInfoSize];
|
var uncompressedBlocksInfo = new byte[(int)m_Header.uncompressedBlocksInfoSize];
|
||||||
var numWrite = LZ4Codec.Decode(compressedBlocksInfo, uncompressedBlocksInfo);
|
var numWrite = LZ4Codec.Decode(compressedBlocksInfo, uncompressedBlocksInfo);
|
||||||
@@ -52,10 +61,12 @@ namespace AssetStudio
|
|||||||
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {m_Header.uncompressedBlocksInfoSize} bytes");
|
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {m_Header.uncompressedBlocksInfoSize} bytes");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger.Verbose($"Writing block and directory to blocks stream...");
|
||||||
using var blocksInfoUncompressedStream = new MemoryStream(uncompressedBlocksInfo);
|
using var blocksInfoUncompressedStream = new MemoryStream(uncompressedBlocksInfo);
|
||||||
using var blocksInfoUncompressedReader = new EndianBinaryReader(blocksInfoUncompressedStream);
|
using var blocksInfoUncompressedReader = new EndianBinaryReader(blocksInfoUncompressedStream);
|
||||||
var nodesCount = blocksInfoUncompressedReader.ReadMhy0Int();
|
var nodesCount = blocksInfoUncompressedReader.ReadMhy0Int();
|
||||||
m_DirectoryInfo = new BundleFile.Node[nodesCount];
|
m_DirectoryInfo = new BundleFile.Node[nodesCount];
|
||||||
|
Logger.Verbose($"Directory count: {nodesCount}");
|
||||||
for (int i = 0; i < nodesCount; i++)
|
for (int i = 0; i < nodesCount; i++)
|
||||||
{
|
{
|
||||||
m_DirectoryInfo[i] = new BundleFile.Node
|
m_DirectoryInfo[i] = new BundleFile.Node
|
||||||
@@ -65,10 +76,13 @@ namespace AssetStudio
|
|||||||
offset = blocksInfoUncompressedReader.ReadMhy0Int(),
|
offset = blocksInfoUncompressedReader.ReadMhy0Int(),
|
||||||
size = blocksInfoUncompressedReader.ReadMhy0UInt()
|
size = blocksInfoUncompressedReader.ReadMhy0UInt()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Logger.Verbose($"Directory {i} Info: {m_DirectoryInfo[i]}");
|
||||||
}
|
}
|
||||||
|
|
||||||
var blocksInfoCount = blocksInfoUncompressedReader.ReadMhy0Int();
|
var blocksInfoCount = blocksInfoUncompressedReader.ReadMhy0Int();
|
||||||
m_BlocksInfo = new BundleFile.StorageBlock[blocksInfoCount];
|
m_BlocksInfo = new BundleFile.StorageBlock[blocksInfoCount];
|
||||||
|
Logger.Verbose($"Blocks count: {blocksInfoCount}");
|
||||||
for (int i = 0; i < blocksInfoCount; i++)
|
for (int i = 0; i < blocksInfoCount; i++)
|
||||||
{
|
{
|
||||||
m_BlocksInfo[i] = new BundleFile.StorageBlock
|
m_BlocksInfo[i] = new BundleFile.StorageBlock
|
||||||
@@ -77,6 +91,8 @@ namespace AssetStudio
|
|||||||
uncompressedSize = blocksInfoUncompressedReader.ReadMhy0UInt(),
|
uncompressedSize = blocksInfoUncompressedReader.ReadMhy0UInt(),
|
||||||
flags = (StorageBlockFlags)0x43
|
flags = (StorageBlockFlags)0x43
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Logger.Verbose($"Block {i} Info: {m_BlocksInfo[i]}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,6 +100,7 @@ namespace AssetStudio
|
|||||||
{
|
{
|
||||||
Stream blocksStream;
|
Stream blocksStream;
|
||||||
var uncompressedSizeSum = (int)m_BlocksInfo.Sum(x => x.uncompressedSize);
|
var uncompressedSizeSum = (int)m_BlocksInfo.Sum(x => x.uncompressedSize);
|
||||||
|
Logger.Verbose($"Total size of decompressed blocks: 0x{uncompressedSizeSum:X8}");
|
||||||
if (uncompressedSizeSum >= int.MaxValue)
|
if (uncompressedSizeSum >= int.MaxValue)
|
||||||
blocksStream = new FileStream(path + ".temp", FileMode.Create, FileAccess.ReadWrite, FileShare.None, 4096, FileOptions.DeleteOnClose);
|
blocksStream = new FileStream(path + ".temp", FileMode.Create, FileAccess.ReadWrite, FileShare.None, 4096, FileOptions.DeleteOnClose);
|
||||||
else
|
else
|
||||||
@@ -110,6 +127,7 @@ namespace AssetStudio
|
|||||||
var uncompressedBytesSpan = uncompressedBytes.AsSpan(0, uncompressedSize);
|
var uncompressedBytesSpan = uncompressedBytes.AsSpan(0, uncompressedSize);
|
||||||
DescrambleEntry(compressedBytesSpan);
|
DescrambleEntry(compressedBytesSpan);
|
||||||
|
|
||||||
|
Logger.Verbose($"Descrambled block signature {Convert.ToHexString(compressedBytes, 0, 4)}");
|
||||||
var numWrite = LZ4Codec.Decode(compressedBytesSpan[0xC..compressedSize], uncompressedBytesSpan);
|
var numWrite = LZ4Codec.Decode(compressedBytesSpan[0xC..compressedSize], uncompressedBytesSpan);
|
||||||
if (numWrite != uncompressedSize)
|
if (numWrite != uncompressedSize)
|
||||||
{
|
{
|
||||||
@@ -124,6 +142,8 @@ namespace AssetStudio
|
|||||||
|
|
||||||
private void ReadFiles(Stream blocksStream, string path)
|
private void ReadFiles(Stream blocksStream, string path)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Writing files from blocks stream...");
|
||||||
|
|
||||||
fileList = new StreamFile[m_DirectoryInfo.Length];
|
fileList = new StreamFile[m_DirectoryInfo.Length];
|
||||||
for (int i = 0; i < m_DirectoryInfo.Length; i++)
|
for (int i = 0; i < m_DirectoryInfo.Length; i++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
namespace AssetStudio
|
using System.Text;
|
||||||
|
|
||||||
|
namespace AssetStudio
|
||||||
{
|
{
|
||||||
public class ObjectInfo
|
public class ObjectInfo
|
||||||
{
|
{
|
||||||
@@ -11,5 +13,18 @@
|
|||||||
|
|
||||||
public long m_PathID;
|
public long m_PathID;
|
||||||
public SerializedType serializedType;
|
public SerializedType serializedType;
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.Append($"byteStart: 0x{byteStart:X8} | ");
|
||||||
|
sb.Append($"byteSize: 0x{byteSize:X8} | ");
|
||||||
|
sb.Append($"typeID: {typeID} | ");
|
||||||
|
sb.Append($"classID: {classID} | ");
|
||||||
|
sb.Append($"isDestroyed: {isDestroyed} | ");
|
||||||
|
sb.Append($"stripped: {stripped} | ");
|
||||||
|
sb.Append($"PathID: {m_PathID}");
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,10 +39,13 @@ namespace AssetStudio
|
|||||||
serializedType = objectInfo.serializedType;
|
serializedType = objectInfo.serializedType;
|
||||||
platform = assetsFile.m_TargetPlatform;
|
platform = assetsFile.m_TargetPlatform;
|
||||||
m_Version = assetsFile.header.m_Version;
|
m_Version = assetsFile.header.m_Version;
|
||||||
|
|
||||||
|
Logger.Verbose($"Initialized reader for {type} object with {m_PathID} in file {assetsFile.fileName} !!");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset()
|
public void Reset()
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Resetting reader position to object offset 0x{byteStart:X8}...");
|
||||||
Position = byteStart;
|
Position = byteStart;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,14 +60,7 @@ namespace AssetStudio
|
|||||||
_baseStream.Seek(target, SeekOrigin.Begin);
|
_baseStream.Seek(target, SeekOrigin.Begin);
|
||||||
return Position;
|
return Position;
|
||||||
}
|
}
|
||||||
public override int Read(byte[] buffer, int offset, int count)
|
public override int Read(byte[] buffer, int offset, int count) => _baseStream.Read(buffer, offset, count);
|
||||||
{
|
|
||||||
if (offset > _baseStream.Length || Position + count > _baseStream.Length)
|
|
||||||
{
|
|
||||||
throw new IOException("Unable to read beyond stream bound");
|
|
||||||
}
|
|
||||||
return _baseStream.Read(buffer, offset, count);
|
|
||||||
}
|
|
||||||
public override void Write(byte[] buffer, int offset, int count) => throw new NotImplementedException();
|
public override void Write(byte[] buffer, int offset, int count) => throw new NotImplementedException();
|
||||||
public override void SetLength(long value) => throw new NotImplementedException();
|
public override void SetLength(long value) => throw new NotImplementedException();
|
||||||
public override void Flush() => throw new NotImplementedException();
|
public override void Flush() => throw new NotImplementedException();
|
||||||
|
|||||||
@@ -67,16 +67,21 @@ namespace AssetStudio
|
|||||||
header.m_FileSize = reader.ReadInt64();
|
header.m_FileSize = reader.ReadInt64();
|
||||||
header.m_DataOffset = reader.ReadInt64();
|
header.m_DataOffset = reader.ReadInt64();
|
||||||
reader.ReadInt64(); // unknown
|
reader.ReadInt64(); // unknown
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger.Verbose($"File {fileName} Info: {header}");
|
||||||
|
|
||||||
// ReadMetadata
|
// ReadMetadata
|
||||||
if (m_FileEndianess == 0)
|
if (m_FileEndianess == 0)
|
||||||
{
|
{
|
||||||
reader.Endian = EndianType.LittleEndian;
|
reader.Endian = EndianType.LittleEndian;
|
||||||
|
Logger.Verbose($"Endianness {reader.Endian}");
|
||||||
}
|
}
|
||||||
if (header.m_Version >= SerializedFileFormatVersion.Unknown_7)
|
if (header.m_Version >= SerializedFileFormatVersion.Unknown_7)
|
||||||
{
|
{
|
||||||
unityVersion = reader.ReadStringToNull();
|
unityVersion = reader.ReadStringToNull();
|
||||||
|
Logger.Verbose($"Unity version {unityVersion}");
|
||||||
SetVersion(unityVersion);
|
SetVersion(unityVersion);
|
||||||
}
|
}
|
||||||
if (header.m_Version >= SerializedFileFormatVersion.Unknown_8)
|
if (header.m_Version >= SerializedFileFormatVersion.Unknown_8)
|
||||||
@@ -84,12 +89,15 @@ namespace AssetStudio
|
|||||||
m_TargetPlatform = (BuildTarget)reader.ReadInt32();
|
m_TargetPlatform = (BuildTarget)reader.ReadInt32();
|
||||||
if (!Enum.IsDefined(typeof(BuildTarget), m_TargetPlatform))
|
if (!Enum.IsDefined(typeof(BuildTarget), m_TargetPlatform))
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Parsed target format {m_TargetPlatform} doesn't match any of supported formats, defaulting to {BuildTarget.UnknownPlatform}");
|
||||||
m_TargetPlatform = BuildTarget.UnknownPlatform;
|
m_TargetPlatform = BuildTarget.UnknownPlatform;
|
||||||
}
|
}
|
||||||
else if (game.Type.IsMhyGroup())
|
else if (game.Type.IsMhyGroup())
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Selected game {game.Name} is a mhy game, forcing target format {BuildTarget.StandaloneWindows64}");
|
||||||
m_TargetPlatform = BuildTarget.StandaloneWindows64;
|
m_TargetPlatform = BuildTarget.StandaloneWindows64;
|
||||||
}
|
}
|
||||||
|
Logger.Verbose($"Target format {m_TargetPlatform}");
|
||||||
}
|
}
|
||||||
if (header.m_Version >= SerializedFileFormatVersion.HasTypeTreeHashes)
|
if (header.m_Version >= SerializedFileFormatVersion.HasTypeTreeHashes)
|
||||||
{
|
{
|
||||||
@@ -99,6 +107,7 @@ namespace AssetStudio
|
|||||||
// Read Types
|
// Read Types
|
||||||
int typeCount = reader.ReadInt32();
|
int typeCount = reader.ReadInt32();
|
||||||
m_Types = new List<SerializedType>(typeCount);
|
m_Types = new List<SerializedType>(typeCount);
|
||||||
|
Logger.Verbose($"Found {typeCount} serialized types");
|
||||||
for (int i = 0; i < typeCount; i++)
|
for (int i = 0; i < typeCount; i++)
|
||||||
{
|
{
|
||||||
m_Types.Add(ReadSerializedType(false));
|
m_Types.Add(ReadSerializedType(false));
|
||||||
@@ -114,6 +123,7 @@ namespace AssetStudio
|
|||||||
m_Objects = new List<ObjectInfo>(objectCount);
|
m_Objects = new List<ObjectInfo>(objectCount);
|
||||||
Objects = new List<Object>(objectCount);
|
Objects = new List<Object>(objectCount);
|
||||||
ObjectsDic = new Dictionary<long, Object>(objectCount);
|
ObjectsDic = new Dictionary<long, Object>(objectCount);
|
||||||
|
Logger.Verbose($"Found {objectCount} objects");
|
||||||
for (int i = 0; i < objectCount; i++)
|
for (int i = 0; i < objectCount; i++)
|
||||||
{
|
{
|
||||||
var objectInfo = new ObjectInfo();
|
var objectInfo = new ObjectInfo();
|
||||||
@@ -164,12 +174,14 @@ namespace AssetStudio
|
|||||||
{
|
{
|
||||||
objectInfo.stripped = reader.ReadByte();
|
objectInfo.stripped = reader.ReadByte();
|
||||||
}
|
}
|
||||||
|
Logger.Verbose($"Object Info: {objectInfo}");
|
||||||
m_Objects.Add(objectInfo);
|
m_Objects.Add(objectInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (header.m_Version >= SerializedFileFormatVersion.HasScriptTypeIndex)
|
if (header.m_Version >= SerializedFileFormatVersion.HasScriptTypeIndex)
|
||||||
{
|
{
|
||||||
int scriptCount = reader.ReadInt32();
|
int scriptCount = reader.ReadInt32();
|
||||||
|
Logger.Verbose($"Found {scriptCount} scripts");
|
||||||
m_ScriptTypes = new List<LocalSerializedObjectIdentifier>(scriptCount);
|
m_ScriptTypes = new List<LocalSerializedObjectIdentifier>(scriptCount);
|
||||||
for (int i = 0; i < scriptCount; i++)
|
for (int i = 0; i < scriptCount; i++)
|
||||||
{
|
{
|
||||||
@@ -184,12 +196,14 @@ namespace AssetStudio
|
|||||||
reader.AlignStream();
|
reader.AlignStream();
|
||||||
m_ScriptType.localIdentifierInFile = reader.ReadInt64();
|
m_ScriptType.localIdentifierInFile = reader.ReadInt64();
|
||||||
}
|
}
|
||||||
|
Logger.Verbose($"Script Info: {m_ScriptType}");
|
||||||
m_ScriptTypes.Add(m_ScriptType);
|
m_ScriptTypes.Add(m_ScriptType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int externalsCount = reader.ReadInt32();
|
int externalsCount = reader.ReadInt32();
|
||||||
m_Externals = new List<FileIdentifier>(externalsCount);
|
m_Externals = new List<FileIdentifier>(externalsCount);
|
||||||
|
Logger.Verbose($"Found {externalsCount} externals");
|
||||||
for (int i = 0; i < externalsCount; i++)
|
for (int i = 0; i < externalsCount; i++)
|
||||||
{
|
{
|
||||||
var m_External = new FileIdentifier();
|
var m_External = new FileIdentifier();
|
||||||
@@ -204,6 +218,7 @@ namespace AssetStudio
|
|||||||
}
|
}
|
||||||
m_External.pathName = reader.ReadStringToNull();
|
m_External.pathName = reader.ReadStringToNull();
|
||||||
m_External.fileName = Path.GetFileName(m_External.pathName);
|
m_External.fileName = Path.GetFileName(m_External.pathName);
|
||||||
|
Logger.Verbose($"External Info: {m_External}");
|
||||||
m_Externals.Add(m_External);
|
m_Externals.Add(m_External);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,6 +226,7 @@ namespace AssetStudio
|
|||||||
{
|
{
|
||||||
int refTypesCount = reader.ReadInt32();
|
int refTypesCount = reader.ReadInt32();
|
||||||
m_RefTypes = new List<SerializedType>(refTypesCount);
|
m_RefTypes = new List<SerializedType>(refTypesCount);
|
||||||
|
Logger.Verbose($"Found {refTypesCount} reference types");
|
||||||
for (int i = 0; i < refTypesCount; i++)
|
for (int i = 0; i < refTypesCount; i++)
|
||||||
{
|
{
|
||||||
m_RefTypes.Add(ReadSerializedType(true));
|
m_RefTypes.Add(ReadSerializedType(true));
|
||||||
@@ -239,12 +255,14 @@ namespace AssetStudio
|
|||||||
|
|
||||||
private SerializedType ReadSerializedType(bool isRefType)
|
private SerializedType ReadSerializedType(bool isRefType)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Attempting to parse serialized" + (isRefType ? " reference" : " ") + "type");
|
||||||
var type = new SerializedType();
|
var type = new SerializedType();
|
||||||
|
|
||||||
type.classID = reader.ReadInt32();
|
type.classID = reader.ReadInt32();
|
||||||
|
|
||||||
if (game.Type.IsGIGroup() && BitConverter.ToBoolean(header.m_Reserved))
|
if (game.Type.IsGIGroup() && BitConverter.ToBoolean(header.m_Reserved))
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Encoded class ID {type.classID}, decoding...");
|
||||||
type.classID = DecodeClassID(type.classID);
|
type.classID = DecodeClassID(type.classID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,6 +291,7 @@ namespace AssetStudio
|
|||||||
|
|
||||||
if (m_EnableTypeTree)
|
if (m_EnableTypeTree)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"File has type tree enabled !!");
|
||||||
type.m_Type = new TypeTree();
|
type.m_Type = new TypeTree();
|
||||||
type.m_Type.m_Nodes = new List<TypeTreeNode>();
|
type.m_Type.m_Nodes = new List<TypeTreeNode>();
|
||||||
if (header.m_Version >= SerializedFileFormatVersion.Unknown_12 || header.m_Version == SerializedFileFormatVersion.Unknown_10)
|
if (header.m_Version >= SerializedFileFormatVersion.Unknown_12 || header.m_Version == SerializedFileFormatVersion.Unknown_10)
|
||||||
@@ -298,11 +317,13 @@ namespace AssetStudio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger.Verbose($"Serialized type info: {type}");
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ReadTypeTree(TypeTree m_Type, int level = 0)
|
private void ReadTypeTree(TypeTree m_Type, int level = 0)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Attempting to parse type tree...");
|
||||||
var typeTreeNode = new TypeTreeNode();
|
var typeTreeNode = new TypeTreeNode();
|
||||||
m_Type.m_Nodes.Add(typeTreeNode);
|
m_Type.m_Nodes.Add(typeTreeNode);
|
||||||
typeTreeNode.m_Level = level;
|
typeTreeNode.m_Level = level;
|
||||||
@@ -329,12 +350,16 @@ namespace AssetStudio
|
|||||||
{
|
{
|
||||||
ReadTypeTree(m_Type, level + 1);
|
ReadTypeTree(m_Type, level + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger.Verbose($"Type Tree Info: {m_Type}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TypeTreeBlobRead(TypeTree m_Type)
|
private void TypeTreeBlobRead(TypeTree m_Type)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Attempting to parse blob type tree...");
|
||||||
int numberOfNodes = reader.ReadInt32();
|
int numberOfNodes = reader.ReadInt32();
|
||||||
int stringBufferSize = reader.ReadInt32();
|
int stringBufferSize = reader.ReadInt32();
|
||||||
|
Logger.Verbose($"Found {numberOfNodes} nodes and {stringBufferSize} strings");
|
||||||
for (int i = 0; i < numberOfNodes; i++)
|
for (int i = 0; i < numberOfNodes; i++)
|
||||||
{
|
{
|
||||||
var typeTreeNode = new TypeTreeNode();
|
var typeTreeNode = new TypeTreeNode();
|
||||||
@@ -364,6 +389,8 @@ namespace AssetStudio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger.Verbose($"Type Tree Info: {m_Type}");
|
||||||
|
|
||||||
string ReadString(EndianBinaryReader stringBufferReader, uint value)
|
string ReadString(EndianBinaryReader stringBufferReader, uint value)
|
||||||
{
|
{
|
||||||
var isOffset = (value & 0x80000000) == 0;
|
var isOffset = (value & 0x80000000) == 0;
|
||||||
@@ -383,6 +410,7 @@ namespace AssetStudio
|
|||||||
|
|
||||||
public void AddObject(Object obj)
|
public void AddObject(Object obj)
|
||||||
{
|
{
|
||||||
|
Logger.Verbose($"Caching object with {obj.m_PathID} in file {fileName}...");
|
||||||
Objects.Add(obj);
|
Objects.Add(obj);
|
||||||
ObjectsDic.Add(obj.m_PathID, obj);
|
ObjectsDic.Add(obj.m_PathID, obj);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,5 +13,16 @@ namespace AssetStudio
|
|||||||
public long m_DataOffset;
|
public long m_DataOffset;
|
||||||
public byte m_Endianess;
|
public byte m_Endianess;
|
||||||
public byte[] m_Reserved;
|
public byte[] m_Reserved;
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.Append($"MetadataSize: 0x{m_MetadataSize:X8} | ");
|
||||||
|
sb.Append($"FileSize: 0x{m_FileSize:X8} | ");
|
||||||
|
sb.Append($"Version: {m_Version} | ");
|
||||||
|
sb.Append($"DataOffset: 0x{m_DataOffset:X8} | ");
|
||||||
|
sb.Append($"Endianness: {(EndianType)m_Endianess}");
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,5 +19,16 @@ namespace AssetStudio
|
|||||||
public string m_AsmName;
|
public string m_AsmName;
|
||||||
|
|
||||||
public bool Match(string hash) => Convert.ToHexString(m_OldTypeHash) == hash;
|
public bool Match(string hash) => Convert.ToHexString(m_OldTypeHash) == hash;
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.Append($"classID: {classID} | ");
|
||||||
|
sb.Append($"IsStrippedType: {m_IsStrippedType} | ");
|
||||||
|
sb.Append($"ScriptTypeIndex: {m_ScriptTypeIndex} | ");
|
||||||
|
sb.Append($"KlassName: {m_KlassName} | ");
|
||||||
|
sb.Append($"NameSpace: {m_NameSpace} | ");
|
||||||
|
sb.Append($"AsmName: {m_AsmName}");
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -186,6 +186,7 @@ namespace AssetStudio
|
|||||||
{
|
{
|
||||||
var m_Node = m_Nodes[i];
|
var m_Node = m_Nodes[i];
|
||||||
var varTypeStr = m_Node.m_Type;
|
var varTypeStr = m_Node.m_Type;
|
||||||
|
Logger.Verbose($"Reading {m_Node.m_Name} of type {varTypeStr}");
|
||||||
object value;
|
object value;
|
||||||
var align = (m_Node.m_MetaFlag & 0x4000) != 0;
|
var align = (m_Node.m_MetaFlag & 0x4000) != 0;
|
||||||
switch (varTypeStr)
|
switch (varTypeStr)
|
||||||
|
|||||||
@@ -28,5 +28,19 @@ namespace AssetStudio
|
|||||||
m_Level = level;
|
m_Level = level;
|
||||||
m_MetaFlag = align ? 0x4000 : 0;
|
m_MetaFlag = align ? 0x4000 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.Append($"Type: {m_Type} | ");
|
||||||
|
sb.Append($"Name: {m_Name} | ");
|
||||||
|
sb.Append($"ByteSize: 0x{m_ByteSize:X8} | ");
|
||||||
|
sb.Append($"Index: {m_Index} | ");
|
||||||
|
sb.Append($"TypeFlags: {m_TypeFlags} | ");
|
||||||
|
sb.Append($"Version: {m_Version} | ");
|
||||||
|
sb.Append($"TypeStrOffset: 0x{m_TypeStrOffset:X8} | ");
|
||||||
|
sb.Append($"NameStrOffset: 0x{m_NameStrOffset:X8}");
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,15 @@ namespace AssetStudio
|
|||||||
public int dataOffset;
|
public int dataOffset;
|
||||||
public int dataLength;
|
public int dataLength;
|
||||||
public string path;
|
public string path;
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.Append($"dataOffset: 0x{dataOffset:X8} | ");
|
||||||
|
sb.Append($"dataOffset: 0x{dataLength:X8} | ");
|
||||||
|
sb.Append($"path: {path}");
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public WebFile(EndianBinaryReader reader)
|
public WebFile(EndianBinaryReader reader)
|
||||||
@@ -21,15 +30,19 @@ namespace AssetStudio
|
|||||||
var signature = reader.ReadStringToNull();
|
var signature = reader.ReadStringToNull();
|
||||||
var headLength = reader.ReadInt32();
|
var headLength = reader.ReadInt32();
|
||||||
var dataList = new List<WebData>();
|
var dataList = new List<WebData>();
|
||||||
|
Logger.Verbose($"Header size: 0x{headLength:X8}");
|
||||||
while (reader.BaseStream.Position < headLength)
|
while (reader.BaseStream.Position < headLength)
|
||||||
{
|
{
|
||||||
var data = new WebData();
|
var data = new WebData();
|
||||||
data.dataOffset = reader.ReadInt32();
|
data.dataOffset = reader.ReadInt32();
|
||||||
data.dataLength = reader.ReadInt32();
|
data.dataLength = reader.ReadInt32();
|
||||||
var pathLength = reader.ReadInt32();
|
var pathLength = reader.ReadInt32();
|
||||||
|
Logger.Verbose($"Path length: {pathLength}");
|
||||||
data.path = Encoding.UTF8.GetString(reader.ReadBytes(pathLength));
|
data.path = Encoding.UTF8.GetString(reader.ReadBytes(pathLength));
|
||||||
|
Logger.Verbose($"Web data Info: {data}");
|
||||||
dataList.Add(data);
|
dataList.Add(data);
|
||||||
}
|
}
|
||||||
|
Logger.Verbose("Writing files to streams...");
|
||||||
fileList = new StreamFile[dataList.Count];
|
fileList = new StreamFile[dataList.Count];
|
||||||
for (int i = 0; i < dataList.Count; i++)
|
for (int i = 0; i < dataList.Count; i++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFrameworks>net6.0-windows;net7.0-windows</TargetFrameworks>
|
<TargetFrameworks>net6.0-windows;net7.0-windows</TargetFrameworks>
|
||||||
<ApplicationIcon>Resources\as.ico</ApplicationIcon>
|
<ApplicationIcon>Resources\as.ico</ApplicationIcon>
|
||||||
<Version>0.90.00</Version>
|
<Version>0.90.10</Version>
|
||||||
<AssemblyVersion>0.90.00</AssemblyVersion>
|
<AssemblyVersion>0.90.10</AssemblyVersion>
|
||||||
<FileVersion>0.90.00</FileVersion>
|
<FileVersion>0.90.10</FileVersion>
|
||||||
<Copyright>Copyright © Razmoth 2022; Copyright © Perfare 2018-2022</Copyright>
|
<Copyright>Copyright © Razmoth 2022; Copyright © Perfare 2018-2022</Copyright>
|
||||||
<BaseOutputPath>..\AssetStudioGUI\bin</BaseOutputPath>
|
<BaseOutputPath>..\AssetStudioGUI\bin</BaseOutputPath>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<Version>0.90.00</Version>
|
<Version>0.90.10</Version>
|
||||||
<AssemblyVersion>0.90.00</AssemblyVersion>
|
<AssemblyVersion>0.90.10</AssemblyVersion>
|
||||||
<FileVersion>0.90.00</FileVersion>
|
<FileVersion>0.90.10</FileVersion>
|
||||||
<Copyright>Copyright © Perfare 2018-2022; Copyright © hozuki 2020</Copyright>
|
<Copyright>Copyright © Perfare 2018-2022; Copyright © hozuki 2020</Copyright>
|
||||||
<DebugType>embedded</DebugType>
|
<DebugType>embedded</DebugType>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -27,9 +27,10 @@ namespace AssetStudio.FbxInterop
|
|||||||
[DllImport(FbxDll.DllName)]
|
[DllImport(FbxDll.DllName)]
|
||||||
private static extern IntPtr AsFbxGetSceneRootNode(IntPtr context);
|
private static extern IntPtr AsFbxGetSceneRootNode(IntPtr context);
|
||||||
|
|
||||||
private static IntPtr AsFbxExportSingleFrame(IntPtr context, IntPtr parentNode, string framePath, string frameName, in Vector3 localPosition, in Vector3 localRotation, in Vector3 localScale)
|
private static IntPtr AsFbxExportSingleFrame(IntPtr context, IntPtr parentNode, string framePath, string frameName, in Vector3 localPosition, in Quaternion localRotation, in Vector3 localScale)
|
||||||
{
|
{
|
||||||
return AsFbxExportSingleFrame(context, parentNode, framePath, frameName, localPosition.X, localPosition.Y, localPosition.Z, localRotation.X, localRotation.Y, localRotation.Z, localScale.X, localScale.Y, localScale.Z);
|
var localRotationEuler = Fbx.QuaternionToEuler(localRotation);
|
||||||
|
return AsFbxExportSingleFrame(context, parentNode, framePath, frameName, localPosition.X, localPosition.Y, localPosition.Z, localRotationEuler.X, localRotationEuler.Y, localRotationEuler.Z, localScale.X, localScale.Y, localScale.Z);
|
||||||
}
|
}
|
||||||
|
|
||||||
[DllImport(FbxDll.DllName)]
|
[DllImport(FbxDll.DllName)]
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ namespace AssetStudio.FbxInterop
|
|||||||
|
|
||||||
public FbxExporterContext()
|
public FbxExporterContext()
|
||||||
{
|
{
|
||||||
|
Fbx.QuaternionToEuler(Quaternion.Zero); // workaround to init dll
|
||||||
_pContext = AsFbxCreateContext();
|
_pContext = AsFbxCreateContext();
|
||||||
_frameToNode = new Dictionary<ImportedFrame, IntPtr>();
|
_frameToNode = new Dictionary<ImportedFrame, IntPtr>();
|
||||||
_createdMaterials = new List<KeyValuePair<string, IntPtr>>();
|
_createdMaterials = new List<KeyValuePair<string, IntPtr>>();
|
||||||
@@ -554,7 +555,7 @@ namespace AssetStudio.FbxInterop
|
|||||||
|
|
||||||
foreach (var rotation in track.Rotations)
|
foreach (var rotation in track.Rotations)
|
||||||
{
|
{
|
||||||
var value = rotation.value;
|
var value = Fbx.QuaternionToEuler(rotation.value);
|
||||||
AsFbxAnimAddRotationKey(pAnimContext, rotation.time, value.X, value.Y, value.Z);
|
AsFbxAnimAddRotationKey(pAnimContext, rotation.time, value.X, value.Y, value.Z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -115,6 +115,15 @@
|
|||||||
<setting name="selectedCABMapName" serializeAs="String">
|
<setting name="selectedCABMapName" serializeAs="String">
|
||||||
<value />
|
<value />
|
||||||
</setting>
|
</setting>
|
||||||
|
<setting name="disableAnimationClip" serializeAs="String">
|
||||||
|
<value>False</value>
|
||||||
|
</setting>
|
||||||
|
<setting name="enableFileLogging" serializeAs="String">
|
||||||
|
<value>True</value>
|
||||||
|
</setting>
|
||||||
|
<setting name="enableVerbose" serializeAs="String">
|
||||||
|
<value>False</value>
|
||||||
|
</setting>
|
||||||
</AssetStudioGUI.Properties.Settings>
|
</AssetStudioGUI.Properties.Settings>
|
||||||
</userSettings>
|
</userSettings>
|
||||||
</configuration>
|
</configuration>
|
||||||
@@ -5,9 +5,9 @@
|
|||||||
<TargetFrameworks>net6.0-windows;net7.0-windows</TargetFrameworks>
|
<TargetFrameworks>net6.0-windows;net7.0-windows</TargetFrameworks>
|
||||||
<UseWindowsForms>true</UseWindowsForms>
|
<UseWindowsForms>true</UseWindowsForms>
|
||||||
<ApplicationIcon>Resources\as.ico</ApplicationIcon>
|
<ApplicationIcon>Resources\as.ico</ApplicationIcon>
|
||||||
<Version>0.90.00</Version>
|
<Version>0.90.10</Version>
|
||||||
<AssemblyVersion>0.90.00</AssemblyVersion>
|
<AssemblyVersion>0.90.10</AssemblyVersion>
|
||||||
<FileVersion>0.90.00</FileVersion>
|
<FileVersion>0.90.10</FileVersion>
|
||||||
<Copyright>Copyright © Razmoth 2022; Copyright © Perfare 2018-2022</Copyright>
|
<Copyright>Copyright © Razmoth 2022; Copyright © Perfare 2018-2022</Copyright>
|
||||||
<DebugType>embedded</DebugType>
|
<DebugType>embedded</DebugType>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
@@ -69,7 +69,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="OpenTK" Version="5.0.0-pre.8" />
|
<PackageReference Include="OpenTK" Version="4.8.0" />
|
||||||
<Reference Include="OpenTK.WinForms">
|
<Reference Include="OpenTK.WinForms">
|
||||||
<HintPath>Libraries\OpenTK.WinForms.dll</HintPath>
|
<HintPath>Libraries\OpenTK.WinForms.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
|||||||
68
AssetStudioGUI/AssetStudioGUIForm.Designer.cs
generated
68
AssetStudioGUI/AssetStudioGUIForm.Designer.cs
generated
@@ -55,6 +55,8 @@ namespace AssetStudioGUI
|
|||||||
toolStripSeparator12 = new System.Windows.Forms.ToolStripSeparator();
|
toolStripSeparator12 = new System.Windows.Forms.ToolStripSeparator();
|
||||||
toolStripMenuItem14 = new System.Windows.Forms.ToolStripMenuItem();
|
toolStripMenuItem14 = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
specifyUnityVersion = new System.Windows.Forms.ToolStripTextBox();
|
specifyUnityVersion = new System.Windows.Forms.ToolStripTextBox();
|
||||||
|
specifyUnityCNKey = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
|
toolStripSeparator13 = new System.Windows.Forms.ToolStripSeparator();
|
||||||
toolStripMenuItem18 = new System.Windows.Forms.ToolStripMenuItem();
|
toolStripMenuItem18 = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
specifyGame = new System.Windows.Forms.ToolStripComboBox();
|
specifyGame = new System.Windows.Forms.ToolStripComboBox();
|
||||||
toolStripMenuItem19 = new System.Windows.Forms.ToolStripMenuItem();
|
toolStripMenuItem19 = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
@@ -101,6 +103,8 @@ namespace AssetStudioGUI
|
|||||||
exportClassStructuresMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
exportClassStructuresMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
enableConsole = new System.Windows.Forms.ToolStripMenuItem();
|
enableConsole = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
clearConsoleToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
clearConsoleToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
|
enableFileLogging = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
|
enableVerbose = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
miscToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
miscToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
MapNameComboBox = new System.Windows.Forms.ToolStripComboBox();
|
MapNameComboBox = new System.Windows.Forms.ToolStripComboBox();
|
||||||
buildMapToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
buildMapToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
@@ -167,8 +171,6 @@ namespace AssetStudioGUI
|
|||||||
exportAnimatorwithselectedAnimationClipMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
exportAnimatorwithselectedAnimationClipMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
goToSceneHierarchyToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
goToSceneHierarchyToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
showOriginalFileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
showOriginalFileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
specifyUnityCNKey = new System.Windows.Forms.ToolStripMenuItem();
|
|
||||||
toolStripSeparator13 = new System.Windows.Forms.ToolStripSeparator();
|
|
||||||
menuStrip1.SuspendLayout();
|
menuStrip1.SuspendLayout();
|
||||||
((System.ComponentModel.ISupportInitialize)splitContainer1).BeginInit();
|
((System.ComponentModel.ISupportInitialize)splitContainer1).BeginInit();
|
||||||
splitContainer1.Panel1.SuspendLayout();
|
splitContainer1.Panel1.SuspendLayout();
|
||||||
@@ -360,6 +362,18 @@ namespace AssetStudioGUI
|
|||||||
specifyUnityVersion.Name = "specifyUnityVersion";
|
specifyUnityVersion.Name = "specifyUnityVersion";
|
||||||
specifyUnityVersion.Size = new System.Drawing.Size(100, 23);
|
specifyUnityVersion.Size = new System.Drawing.Size(100, 23);
|
||||||
//
|
//
|
||||||
|
// specifyUnityCNKey
|
||||||
|
//
|
||||||
|
specifyUnityCNKey.Name = "specifyUnityCNKey";
|
||||||
|
specifyUnityCNKey.Size = new System.Drawing.Size(225, 22);
|
||||||
|
specifyUnityCNKey.Text = "Specify UnityCN Key";
|
||||||
|
specifyUnityCNKey.Click += specifyUnityCNKey_Click;
|
||||||
|
//
|
||||||
|
// toolStripSeparator13
|
||||||
|
//
|
||||||
|
toolStripSeparator13.Name = "toolStripSeparator13";
|
||||||
|
toolStripSeparator13.Size = new System.Drawing.Size(222, 6);
|
||||||
|
//
|
||||||
// toolStripMenuItem18
|
// toolStripMenuItem18
|
||||||
//
|
//
|
||||||
toolStripMenuItem18.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { specifyGame });
|
toolStripMenuItem18.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { specifyGame });
|
||||||
@@ -642,7 +656,7 @@ namespace AssetStudioGUI
|
|||||||
//
|
//
|
||||||
// debugMenuItem
|
// debugMenuItem
|
||||||
//
|
//
|
||||||
debugMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { toolStripMenuItem15, exportClassStructuresMenuItem, enableConsole, clearConsoleToolStripMenuItem });
|
debugMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { toolStripMenuItem15, exportClassStructuresMenuItem, enableConsole, clearConsoleToolStripMenuItem, enableFileLogging, enableVerbose });
|
||||||
debugMenuItem.Name = "debugMenuItem";
|
debugMenuItem.Name = "debugMenuItem";
|
||||||
debugMenuItem.Size = new System.Drawing.Size(54, 20);
|
debugMenuItem.Size = new System.Drawing.Size(54, 20);
|
||||||
debugMenuItem.Text = "Debug";
|
debugMenuItem.Text = "Debug";
|
||||||
@@ -681,6 +695,24 @@ namespace AssetStudioGUI
|
|||||||
clearConsoleToolStripMenuItem.Text = "Clear Console";
|
clearConsoleToolStripMenuItem.Text = "Clear Console";
|
||||||
clearConsoleToolStripMenuItem.Click += clearConsoleToolStripMenuItem_Click;
|
clearConsoleToolStripMenuItem.Click += clearConsoleToolStripMenuItem_Click;
|
||||||
//
|
//
|
||||||
|
// enableFileLogging
|
||||||
|
//
|
||||||
|
enableFileLogging.Checked = true;
|
||||||
|
enableFileLogging.CheckOnClick = true;
|
||||||
|
enableFileLogging.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||||
|
enableFileLogging.Name = "enableFileLogging";
|
||||||
|
enableFileLogging.Size = new System.Drawing.Size(191, 22);
|
||||||
|
enableFileLogging.Text = "Enable File Logging";
|
||||||
|
enableFileLogging.CheckedChanged += enableFileLogging_CheckedChanged;
|
||||||
|
//
|
||||||
|
// enableVerbose
|
||||||
|
//
|
||||||
|
enableVerbose.CheckOnClick = true;
|
||||||
|
enableVerbose.Name = "enableVerbose";
|
||||||
|
enableVerbose.Size = new System.Drawing.Size(191, 22);
|
||||||
|
enableVerbose.Text = "Enable Verbose";
|
||||||
|
enableVerbose.CheckedChanged += enableVerbose_Click;
|
||||||
|
//
|
||||||
// miscToolStripMenuItem
|
// miscToolStripMenuItem
|
||||||
//
|
//
|
||||||
miscToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { MapNameComboBox, buildMapToolStripMenuItem, buildBothToolStripMenuItem, clearMapToolStripMenuItem, toolStripSeparator7, assetMapNameTextBox, buildAssetMapToolStripMenuItem, assetMapTypeComboBox, toolStripSeparator8, loadAIToolStripMenuItem, assetBrowserToolStripMenuItem });
|
miscToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { MapNameComboBox, buildMapToolStripMenuItem, buildBothToolStripMenuItem, clearMapToolStripMenuItem, toolStripSeparator7, assetMapNameTextBox, buildAssetMapToolStripMenuItem, assetMapTypeComboBox, toolStripSeparator8, loadAIToolStripMenuItem, assetBrowserToolStripMenuItem });
|
||||||
@@ -843,16 +875,14 @@ namespace AssetStudioGUI
|
|||||||
// treeSearch
|
// treeSearch
|
||||||
//
|
//
|
||||||
treeSearch.Dock = System.Windows.Forms.DockStyle.Top;
|
treeSearch.Dock = System.Windows.Forms.DockStyle.Top;
|
||||||
treeSearch.ForeColor = System.Drawing.SystemColors.GrayText;
|
treeSearch.ForeColor = System.Drawing.SystemColors.WindowText;
|
||||||
treeSearch.Location = new System.Drawing.Point(0, 0);
|
treeSearch.Location = new System.Drawing.Point(0, 0);
|
||||||
treeSearch.Name = "treeSearch";
|
treeSearch.Name = "treeSearch";
|
||||||
treeSearch.Size = new System.Drawing.Size(472, 23);
|
treeSearch.Size = new System.Drawing.Size(472, 23);
|
||||||
treeSearch.TabIndex = 0;
|
treeSearch.TabIndex = 0;
|
||||||
treeSearch.Text = " Search ";
|
treeSearch.PlaceholderText = "Search (with Ctrl to check result, with Shift for all)";
|
||||||
treeSearch.TextChanged += treeSearch_TextChanged;
|
treeSearch.TextChanged += treeSearch_TextChanged;
|
||||||
treeSearch.Enter += treeSearch_Enter;
|
|
||||||
treeSearch.KeyDown += treeSearch_KeyDown;
|
treeSearch.KeyDown += treeSearch_KeyDown;
|
||||||
treeSearch.Leave += treeSearch_Leave;
|
|
||||||
//
|
//
|
||||||
// tabPage2
|
// tabPage2
|
||||||
//
|
//
|
||||||
@@ -910,15 +940,13 @@ namespace AssetStudioGUI
|
|||||||
// listSearch
|
// listSearch
|
||||||
//
|
//
|
||||||
listSearch.Dock = System.Windows.Forms.DockStyle.Top;
|
listSearch.Dock = System.Windows.Forms.DockStyle.Top;
|
||||||
listSearch.ForeColor = System.Drawing.SystemColors.GrayText;
|
listSearch.ForeColor = System.Drawing.SystemColors.WindowText;
|
||||||
listSearch.Location = new System.Drawing.Point(0, 0);
|
listSearch.Location = new System.Drawing.Point(0, 0);
|
||||||
listSearch.Name = "listSearch";
|
listSearch.Name = "listSearch";
|
||||||
listSearch.Size = new System.Drawing.Size(472, 23);
|
listSearch.Size = new System.Drawing.Size(472, 23);
|
||||||
listSearch.TabIndex = 0;
|
listSearch.TabIndex = 0;
|
||||||
listSearch.Text = " Filter ";
|
listSearch.PlaceholderText = "Search";
|
||||||
listSearch.TextChanged += ListSearchTextChanged;
|
listSearch.KeyPress += listSearch_KeyPress;
|
||||||
listSearch.Enter += listSearch_Enter;
|
|
||||||
listSearch.Leave += listSearch_Leave;
|
|
||||||
//
|
//
|
||||||
// tabPage3
|
// tabPage3
|
||||||
//
|
//
|
||||||
@@ -1166,7 +1194,7 @@ namespace AssetStudioGUI
|
|||||||
// glControl
|
// glControl
|
||||||
//
|
//
|
||||||
glControl.API = OpenTK.Windowing.Common.ContextAPI.OpenGL;
|
glControl.API = OpenTK.Windowing.Common.ContextAPI.OpenGL;
|
||||||
glControl.APIVersion = new Version(4, 6, 0, 0);
|
glControl.APIVersion = new Version(4, 5, 0, 0);
|
||||||
glControl.BackColor = System.Drawing.SystemColors.ControlDarkDark;
|
glControl.BackColor = System.Drawing.SystemColors.ControlDarkDark;
|
||||||
glControl.Dock = System.Windows.Forms.DockStyle.Fill;
|
glControl.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
glControl.Flags = OpenTK.Windowing.Common.ContextFlags.Default;
|
glControl.Flags = OpenTK.Windowing.Common.ContextFlags.Default;
|
||||||
@@ -1308,18 +1336,6 @@ namespace AssetStudioGUI
|
|||||||
showOriginalFileToolStripMenuItem.Visible = false;
|
showOriginalFileToolStripMenuItem.Visible = false;
|
||||||
showOriginalFileToolStripMenuItem.Click += showOriginalFileToolStripMenuItem_Click;
|
showOriginalFileToolStripMenuItem.Click += showOriginalFileToolStripMenuItem_Click;
|
||||||
//
|
//
|
||||||
// specifyUnityCNKey
|
|
||||||
//
|
|
||||||
specifyUnityCNKey.Name = "specifyUnityCNKey";
|
|
||||||
specifyUnityCNKey.Size = new System.Drawing.Size(225, 22);
|
|
||||||
specifyUnityCNKey.Text = "Specify UnityCN Key";
|
|
||||||
specifyUnityCNKey.Click += specifyUnityCNKey_Click;
|
|
||||||
//
|
|
||||||
// toolStripSeparator13
|
|
||||||
//
|
|
||||||
toolStripSeparator13.Name = "toolStripSeparator13";
|
|
||||||
toolStripSeparator13.Size = new System.Drawing.Size(222, 6);
|
|
||||||
//
|
|
||||||
// AssetStudioGUIForm
|
// AssetStudioGUIForm
|
||||||
//
|
//
|
||||||
AllowDrop = true;
|
AllowDrop = true;
|
||||||
@@ -1506,6 +1522,8 @@ namespace AssetStudioGUI
|
|||||||
private System.Windows.Forms.ToolStripSeparator toolStripSeparator12;
|
private System.Windows.Forms.ToolStripSeparator toolStripSeparator12;
|
||||||
private System.Windows.Forms.ToolStripMenuItem specifyUnityCNKey;
|
private System.Windows.Forms.ToolStripMenuItem specifyUnityCNKey;
|
||||||
private System.Windows.Forms.ToolStripSeparator toolStripSeparator13;
|
private System.Windows.Forms.ToolStripSeparator toolStripSeparator13;
|
||||||
|
private System.Windows.Forms.ToolStripMenuItem enableFileLogging;
|
||||||
|
private System.Windows.Forms.ToolStripMenuItem enableVerbose;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ using Matrix4 = OpenTK.Mathematics.Matrix4;
|
|||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using OpenTK.Mathematics;
|
using OpenTK.Mathematics;
|
||||||
using Newtonsoft.Json.Converters;
|
using Newtonsoft.Json.Converters;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace AssetStudioGUI
|
namespace AssetStudioGUI
|
||||||
{
|
{
|
||||||
@@ -50,14 +51,14 @@ namespace AssetStudioGUI
|
|||||||
private bool glControlLoaded;
|
private bool glControlLoaded;
|
||||||
private int mdx, mdy;
|
private int mdx, mdy;
|
||||||
private bool lmdown, rmdown;
|
private bool lmdown, rmdown;
|
||||||
private ProgramHandle pgmID, pgmColorID, pgmBlackID;
|
private int pgmID, pgmColorID, pgmBlackID;
|
||||||
private int attributeVertexPosition;
|
private int attributeVertexPosition;
|
||||||
private int attributeNormalDirection;
|
private int attributeNormalDirection;
|
||||||
private int attributeVertexColor;
|
private int attributeVertexColor;
|
||||||
private int uniformModelMatrix;
|
private int uniformModelMatrix;
|
||||||
private int uniformViewMatrix;
|
private int uniformViewMatrix;
|
||||||
private int uniformProjMatrix;
|
private int uniformProjMatrix;
|
||||||
private VertexArrayHandle vao;
|
private int vao;
|
||||||
private Vector3[] vertexData;
|
private Vector3[] vertexData;
|
||||||
private Vector3[] normalData;
|
private Vector3[] normalData;
|
||||||
private Vector3[] normal2Data;
|
private Vector3[] normal2Data;
|
||||||
@@ -75,10 +76,6 @@ namespace AssetStudioGUI
|
|||||||
private int sortColumn = -1;
|
private int sortColumn = -1;
|
||||||
private bool reverseSort;
|
private bool reverseSort;
|
||||||
|
|
||||||
//asset list filter
|
|
||||||
private System.Timers.Timer delayTimer;
|
|
||||||
private bool enableFiltering;
|
|
||||||
|
|
||||||
//tree search
|
//tree search
|
||||||
private int nextGObject;
|
private int nextGObject;
|
||||||
private List<TreeNode> treeSrcResults = new List<TreeNode>();
|
private List<TreeNode> treeSrcResults = new List<TreeNode>();
|
||||||
@@ -93,8 +90,6 @@ namespace AssetStudioGUI
|
|||||||
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
|
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
Text = $"Studio v{Application.ProductVersion}";
|
Text = $"Studio v{Application.ProductVersion}";
|
||||||
delayTimer = new System.Timers.Timer(800);
|
|
||||||
delayTimer.Elapsed += new ElapsedEventHandler(delayTimer_Elapsed);
|
|
||||||
InitializeExportOptions();
|
InitializeExportOptions();
|
||||||
InitializeProgressBar();
|
InitializeProgressBar();
|
||||||
InitializeLogger();
|
InitializeLogger();
|
||||||
@@ -105,6 +100,8 @@ namespace AssetStudioGUI
|
|||||||
private void InitializeExportOptions()
|
private void InitializeExportOptions()
|
||||||
{
|
{
|
||||||
enableConsole.Checked = Properties.Settings.Default.enableConsole;
|
enableConsole.Checked = Properties.Settings.Default.enableConsole;
|
||||||
|
enableFileLogging.Checked = Properties.Settings.Default.enableFileLogging;
|
||||||
|
enableVerbose.Checked = Properties.Settings.Default.enableVerbose;
|
||||||
displayAll.Checked = Properties.Settings.Default.displayAll;
|
displayAll.Checked = Properties.Settings.Default.displayAll;
|
||||||
displayInfo.Checked = Properties.Settings.Default.displayInfo;
|
displayInfo.Checked = Properties.Settings.Default.displayInfo;
|
||||||
enablePreview.Checked = Properties.Settings.Default.enablePreview;
|
enablePreview.Checked = Properties.Settings.Default.enablePreview;
|
||||||
@@ -119,10 +116,13 @@ namespace AssetStudioGUI
|
|||||||
AssetsHelper.Minimal = Properties.Settings.Default.minimalAssetMap;
|
AssetsHelper.Minimal = Properties.Settings.Default.minimalAssetMap;
|
||||||
Renderer.Parsable = !Properties.Settings.Default.disableRenderer;
|
Renderer.Parsable = !Properties.Settings.Default.disableRenderer;
|
||||||
Shader.Parsable = !Properties.Settings.Default.disableShader;
|
Shader.Parsable = !Properties.Settings.Default.disableShader;
|
||||||
|
AnimationClip.Parsable = !Properties.Settings.Default.disableAnimationClip;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeLogger()
|
private void InitializeLogger()
|
||||||
{
|
{
|
||||||
|
Logger.LogVerbose = enableVerbose.Checked;
|
||||||
|
Logger.FileLogging = enableFileLogging.Checked;
|
||||||
logger = new GUILogger(StatusStripUpdate);
|
logger = new GUILogger(StatusStripUpdate);
|
||||||
ConsoleHelper.AllocConsole();
|
ConsoleHelper.AllocConsole();
|
||||||
ConsoleHelper.SetConsoleTitle("Debug Console");
|
ConsoleHelper.SetConsoleTitle("Debug Console");
|
||||||
@@ -559,24 +559,6 @@ namespace AssetStudioGUI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void treeSearch_Enter(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
if (treeSearch.Text == " Search ")
|
|
||||||
{
|
|
||||||
treeSearch.Text = "";
|
|
||||||
treeSearch.ForeColor = SystemColors.WindowText;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void treeSearch_Leave(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
if (treeSearch.Text == "")
|
|
||||||
{
|
|
||||||
treeSearch.Text = " Search ";
|
|
||||||
treeSearch.ForeColor = SystemColors.GrayText;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void treeSearch_TextChanged(object sender, EventArgs e)
|
private void treeSearch_TextChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
treeSrcResults.Clear();
|
treeSrcResults.Clear();
|
||||||
@@ -585,38 +567,52 @@ namespace AssetStudioGUI
|
|||||||
|
|
||||||
private void treeSearch_KeyDown(object sender, KeyEventArgs e)
|
private void treeSearch_KeyDown(object sender, KeyEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.KeyCode == Keys.Enter)
|
if (e.KeyCode == Keys.Enter && !string.IsNullOrEmpty(treeSearch.Text))
|
||||||
{
|
{
|
||||||
if (treeSrcResults.Count == 0)
|
if (treeSrcResults.Count == 0)
|
||||||
{
|
{
|
||||||
|
var regex = new Regex(treeSearch.Text, RegexOptions.IgnoreCase);
|
||||||
foreach (TreeNode node in sceneTreeView.Nodes)
|
foreach (TreeNode node in sceneTreeView.Nodes)
|
||||||
{
|
{
|
||||||
TreeNodeSearch(node);
|
TreeNodeSearch(regex, node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (treeSrcResults.Count > 0)
|
if (treeSrcResults.Count > 0)
|
||||||
|
{
|
||||||
|
if (e.Shift)
|
||||||
|
{
|
||||||
|
foreach(var node in treeSrcResults)
|
||||||
|
{
|
||||||
|
node.EnsureVisible();
|
||||||
|
node.Checked = e.Control;
|
||||||
|
}
|
||||||
|
sceneTreeView.SelectedNode = treeSrcResults[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
if (nextGObject >= treeSrcResults.Count)
|
if (nextGObject >= treeSrcResults.Count)
|
||||||
{
|
{
|
||||||
nextGObject = 0;
|
nextGObject = 0;
|
||||||
}
|
}
|
||||||
treeSrcResults[nextGObject].EnsureVisible();
|
treeSrcResults[nextGObject].EnsureVisible();
|
||||||
|
treeSrcResults[nextGObject].Checked = e.Control;
|
||||||
sceneTreeView.SelectedNode = treeSrcResults[nextGObject];
|
sceneTreeView.SelectedNode = treeSrcResults[nextGObject];
|
||||||
nextGObject++;
|
nextGObject++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void TreeNodeSearch(TreeNode treeNode)
|
private void TreeNodeSearch(Regex regex, TreeNode treeNode)
|
||||||
{
|
{
|
||||||
if (treeNode.Text.IndexOf(treeSearch.Text, StringComparison.OrdinalIgnoreCase) >= 0)
|
if (regex.IsMatch(treeNode.Text))
|
||||||
{
|
{
|
||||||
treeSrcResults.Add(treeNode);
|
treeSrcResults.Add(treeNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (TreeNode node in treeNode.Nodes)
|
foreach (TreeNode node in treeNode.Nodes)
|
||||||
{
|
{
|
||||||
TreeNodeSearch(node);
|
TreeNodeSearch(regex, node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -628,47 +624,13 @@ namespace AssetStudioGUI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void listSearch_Enter(object sender, EventArgs e)
|
private void listSearch_KeyPress(object sender, KeyPressEventArgs e)
|
||||||
{
|
{
|
||||||
if (listSearch.Text == " Filter ")
|
if (e.KeyChar == (char)Keys.Enter)
|
||||||
{
|
{
|
||||||
listSearch.Text = "";
|
|
||||||
listSearch.ForeColor = SystemColors.WindowText;
|
|
||||||
enableFiltering = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void listSearch_Leave(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
if (listSearch.Text == "")
|
|
||||||
{
|
|
||||||
enableFiltering = false;
|
|
||||||
listSearch.Text = " Filter ";
|
|
||||||
listSearch.ForeColor = SystemColors.GrayText;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ListSearchTextChanged(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
if (enableFiltering)
|
|
||||||
{
|
|
||||||
if (delayTimer.Enabled)
|
|
||||||
{
|
|
||||||
delayTimer.Stop();
|
|
||||||
delayTimer.Start();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
delayTimer.Start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void delayTimer_Elapsed(object sender, ElapsedEventArgs e)
|
|
||||||
{
|
|
||||||
delayTimer.Stop();
|
|
||||||
Invoke(new Action(FilterAssetList));
|
Invoke(new Action(FilterAssetList));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void assetListView_ColumnClick(object sender, ColumnClickEventArgs e)
|
private void assetListView_ColumnClick(object sender, ColumnClickEventArgs e)
|
||||||
{
|
{
|
||||||
@@ -1429,8 +1391,7 @@ namespace AssetStudioGUI
|
|||||||
lastSelectedItem = null;
|
lastSelectedItem = null;
|
||||||
sortColumn = -1;
|
sortColumn = -1;
|
||||||
reverseSort = false;
|
reverseSort = false;
|
||||||
enableFiltering = false;
|
listSearch.Text = string.Empty;
|
||||||
listSearch.Text = " Filter ";
|
|
||||||
|
|
||||||
var count = filterTypeToolStripMenuItem.DropDownItems.Count;
|
var count = filterTypeToolStripMenuItem.DropDownItems.Count;
|
||||||
for (var i = 1; i < count; i++)
|
for (var i = 1; i < count; i++)
|
||||||
@@ -1788,12 +1749,13 @@ namespace AssetStudioGUI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (listSearch.Text != " Filter ")
|
if (!string.IsNullOrEmpty(listSearch.Text))
|
||||||
{
|
{
|
||||||
|
var regex = new Regex(listSearch.Text, RegexOptions.IgnoreCase);
|
||||||
visibleAssets = visibleAssets.FindAll(
|
visibleAssets = visibleAssets.FindAll(
|
||||||
x => x.Text.IndexOf(listSearch.Text, StringComparison.OrdinalIgnoreCase) >= 0 ||
|
x => regex.IsMatch(x.Text) ||
|
||||||
x.SubItems[1].Text.IndexOf(listSearch.Text, StringComparison.OrdinalIgnoreCase) >= 0 ||
|
regex.IsMatch(x.SubItems[1].Text) ||
|
||||||
x.SubItems[3].Text.IndexOf(listSearch.Text, StringComparison.OrdinalIgnoreCase) >= 0);
|
regex.IsMatch(x.SubItems[3].Text));
|
||||||
}
|
}
|
||||||
assetListView.VirtualListSize = visibleAssets.Count;
|
assetListView.VirtualListSize = visibleAssets.Count;
|
||||||
assetListView.EndUpdate();
|
assetListView.EndUpdate();
|
||||||
@@ -2238,6 +2200,22 @@ namespace AssetStudioGUI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void enableFileLogging_CheckedChanged(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
Properties.Settings.Default.enableFileLogging = enableFileLogging.Checked;
|
||||||
|
Properties.Settings.Default.Save();
|
||||||
|
|
||||||
|
Logger.FileLogging = enableFileLogging.Checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void enableVerbose_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
Properties.Settings.Default.enableVerbose = enableVerbose.Checked;
|
||||||
|
Properties.Settings.Default.Save();
|
||||||
|
|
||||||
|
Logger.LogVerbose = enableVerbose.Checked;
|
||||||
|
}
|
||||||
|
|
||||||
private void abortStripMenuItem_Click(object sender, EventArgs e)
|
private void abortStripMenuItem_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
Logger.Info("Aborting....");
|
Logger.Info("Aborting....");
|
||||||
@@ -2607,10 +2585,10 @@ namespace AssetStudioGUI
|
|||||||
private void InitOpenTK()
|
private void InitOpenTK()
|
||||||
{
|
{
|
||||||
ChangeGLSize(glControl.Size);
|
ChangeGLSize(glControl.Size);
|
||||||
GL.ClearColor(Color4.Cadetblue);
|
GL.ClearColor(System.Drawing.Color.CadetBlue);
|
||||||
pgmID = GL.CreateProgram();
|
pgmID = GL.CreateProgram();
|
||||||
LoadShader("vs", ShaderType.VertexShader, pgmID, out ShaderHandle vsID);
|
LoadShader("vs", ShaderType.VertexShader, pgmID, out int vsID);
|
||||||
LoadShader("fs", ShaderType.FragmentShader, pgmID, out ShaderHandle fsID);
|
LoadShader("fs", ShaderType.FragmentShader, pgmID, out int fsID);
|
||||||
GL.LinkProgram(pgmID);
|
GL.LinkProgram(pgmID);
|
||||||
|
|
||||||
pgmColorID = GL.CreateProgram();
|
pgmColorID = GL.CreateProgram();
|
||||||
@@ -2631,7 +2609,7 @@ namespace AssetStudioGUI
|
|||||||
uniformProjMatrix = GL.GetUniformLocation(pgmID, "projMatrix");
|
uniformProjMatrix = GL.GetUniformLocation(pgmID, "projMatrix");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void LoadShader(string filename, ShaderType type, ProgramHandle program, out ShaderHandle address)
|
private static void LoadShader(string filename, ShaderType type, int program, out int address)
|
||||||
{
|
{
|
||||||
address = GL.CreateShader(type);
|
address = GL.CreateShader(type);
|
||||||
var str = (string)Properties.Resources.ResourceManager.GetObject(filename);
|
var str = (string)Properties.Resources.ResourceManager.GetObject(filename);
|
||||||
@@ -2641,47 +2619,50 @@ namespace AssetStudioGUI
|
|||||||
GL.DeleteShader(address);
|
GL.DeleteShader(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void CreateVBO(out BufferHandle vboAddress, Vector3[] data, int address)
|
private static void CreateVBO(out int vboAddress, Vector3[] data, int address)
|
||||||
{
|
{
|
||||||
GL.CreateBuffer(out vboAddress);
|
GL.GenBuffers(1, out vboAddress);
|
||||||
GL.BindBuffer(BufferTargetARB.ArrayBuffer, vboAddress);
|
GL.BindBuffer(BufferTarget.ArrayBuffer, vboAddress);
|
||||||
GL.BufferData(BufferTargetARB.ArrayBuffer,
|
GL.BufferData(BufferTarget.ArrayBuffer,
|
||||||
|
(IntPtr)(data.Length * Vector3.SizeInBytes),
|
||||||
data,
|
data,
|
||||||
BufferUsageARB.StaticDraw);
|
BufferUsageHint.StaticDraw);
|
||||||
GL.VertexAttribPointer((uint)address, 3, VertexAttribPointerType.Float, false, 0, 0);
|
GL.VertexAttribPointer(address, 3, VertexAttribPointerType.Float, false, 0, 0);
|
||||||
GL.EnableVertexAttribArray((uint)address);
|
GL.EnableVertexAttribArray(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void CreateVBO(out BufferHandle vboAddress, Vector4[] data, int address)
|
private static void CreateVBO(out int vboAddress, Vector4[] data, int address)
|
||||||
{
|
{
|
||||||
GL.CreateBuffer(out vboAddress);
|
GL.GenBuffers(1, out vboAddress);
|
||||||
GL.BindBuffer(BufferTargetARB.ArrayBuffer, vboAddress);
|
GL.BindBuffer(BufferTarget.ArrayBuffer, vboAddress);
|
||||||
GL.BufferData(BufferTargetARB.ArrayBuffer,
|
GL.BufferData(BufferTarget.ArrayBuffer,
|
||||||
|
(IntPtr)(data.Length * Vector4.SizeInBytes),
|
||||||
data,
|
data,
|
||||||
BufferUsageARB.StaticDraw);
|
BufferUsageHint.StaticDraw);
|
||||||
GL.VertexAttribPointer((uint)address, 4, VertexAttribPointerType.Float, false, 0, 0);
|
GL.VertexAttribPointer(address, 4, VertexAttribPointerType.Float, false, 0, 0);
|
||||||
GL.EnableVertexAttribArray((uint)address);
|
GL.EnableVertexAttribArray(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void CreateVBO(out BufferHandle vboAddress, Matrix4 data, int address)
|
private static void CreateVBO(out int vboAddress, Matrix4 data, int address)
|
||||||
{
|
{
|
||||||
GL.CreateBuffer(out vboAddress);
|
GL.GenBuffers(1, out vboAddress);
|
||||||
GL.UniformMatrix4f(address, false, in data);
|
GL.UniformMatrix4(address, false, ref data);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void CreateEBO(out BufferHandle address, int[] data)
|
private static void CreateEBO(out int address, int[] data)
|
||||||
{
|
{
|
||||||
GL.CreateBuffer(out address);
|
GL.GenBuffers(1, out address);
|
||||||
GL.BindBuffer(BufferTargetARB.ElementArrayBuffer, address);
|
GL.BindBuffer(BufferTarget.ElementArrayBuffer, address);
|
||||||
GL.BufferData(BufferTargetARB.ElementArrayBuffer,
|
GL.BufferData(BufferTarget.ElementArrayBuffer,
|
||||||
|
(IntPtr)(data.Length * sizeof(int)),
|
||||||
data,
|
data,
|
||||||
BufferUsageARB.StaticDraw);
|
BufferUsageHint.StaticDraw);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateVAO()
|
private void CreateVAO()
|
||||||
{
|
{
|
||||||
GL.DeleteVertexArray(vao);
|
GL.DeleteVertexArray(vao);
|
||||||
GL.CreateVertexArray(out vao);
|
GL.GenVertexArrays(1, out vao);
|
||||||
GL.BindVertexArray(vao);
|
GL.BindVertexArray(vao);
|
||||||
CreateVBO(out var vboPositions, vertexData, attributeVertexPosition);
|
CreateVBO(out var vboPositions, vertexData, attributeVertexPosition);
|
||||||
if (normalMode == 0)
|
if (normalMode == 0)
|
||||||
@@ -2698,8 +2679,8 @@ namespace AssetStudioGUI
|
|||||||
CreateVBO(out var vboViewMatrix, viewMatrixData, uniformViewMatrix);
|
CreateVBO(out var vboViewMatrix, viewMatrixData, uniformViewMatrix);
|
||||||
CreateVBO(out var vboProjMatrix, projMatrixData, uniformProjMatrix);
|
CreateVBO(out var vboProjMatrix, projMatrixData, uniformProjMatrix);
|
||||||
CreateEBO(out var eboElements, indiceData);
|
CreateEBO(out var eboElements, indiceData);
|
||||||
GL.BindBuffer(BufferTargetARB.ArrayBuffer, BufferHandle.Zero);
|
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
|
||||||
GL.BindVertexArray(VertexArrayHandle.Zero);
|
GL.BindVertexArray(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ChangeGLSize(Size size)
|
private void ChangeGLSize(Size size)
|
||||||
@@ -2734,10 +2715,10 @@ namespace AssetStudioGUI
|
|||||||
if (wireFrameMode == 0 || wireFrameMode == 2)
|
if (wireFrameMode == 0 || wireFrameMode == 2)
|
||||||
{
|
{
|
||||||
GL.UseProgram(shadeMode == 0 ? pgmID : pgmColorID);
|
GL.UseProgram(shadeMode == 0 ? pgmID : pgmColorID);
|
||||||
GL.UniformMatrix4f(uniformModelMatrix, false, in modelMatrixData);
|
GL.UniformMatrix4(uniformModelMatrix, false, ref modelMatrixData);
|
||||||
GL.UniformMatrix4f(uniformViewMatrix, false, in viewMatrixData);
|
GL.UniformMatrix4(uniformViewMatrix, false, ref viewMatrixData);
|
||||||
GL.UniformMatrix4f(uniformProjMatrix, false, in projMatrixData);
|
GL.UniformMatrix4(uniformProjMatrix, false, ref projMatrixData);
|
||||||
GL.PolygonMode(TriangleFace.FrontAndBack, PolygonMode.Fill);
|
GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill);
|
||||||
GL.DrawElements(PrimitiveType.Triangles, indiceData.Length, DrawElementsType.UnsignedInt, 0);
|
GL.DrawElements(PrimitiveType.Triangles, indiceData.Length, DrawElementsType.UnsignedInt, 0);
|
||||||
}
|
}
|
||||||
//Wireframe
|
//Wireframe
|
||||||
@@ -2746,14 +2727,14 @@ namespace AssetStudioGUI
|
|||||||
GL.Enable(EnableCap.PolygonOffsetLine);
|
GL.Enable(EnableCap.PolygonOffsetLine);
|
||||||
GL.PolygonOffset(-1, -1);
|
GL.PolygonOffset(-1, -1);
|
||||||
GL.UseProgram(pgmBlackID);
|
GL.UseProgram(pgmBlackID);
|
||||||
GL.UniformMatrix4f(uniformModelMatrix, false, in modelMatrixData);
|
GL.UniformMatrix4(uniformModelMatrix, false, ref modelMatrixData);
|
||||||
GL.UniformMatrix4f(uniformViewMatrix, false, in viewMatrixData);
|
GL.UniformMatrix4(uniformViewMatrix, false, ref viewMatrixData);
|
||||||
GL.UniformMatrix4f(uniformProjMatrix, false, in projMatrixData);
|
GL.UniformMatrix4(uniformProjMatrix, false, ref projMatrixData);
|
||||||
GL.PolygonMode(TriangleFace.FrontAndBack, PolygonMode.Line);
|
GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line);
|
||||||
GL.DrawElements(PrimitiveType.Triangles, indiceData.Length, DrawElementsType.UnsignedInt, 0);
|
GL.DrawElements(PrimitiveType.Triangles, indiceData.Length, DrawElementsType.UnsignedInt, 0);
|
||||||
GL.Disable(EnableCap.PolygonOffsetLine);
|
GL.Disable(EnableCap.PolygonOffsetLine);
|
||||||
}
|
}
|
||||||
GL.BindVertexArray(VertexArrayHandle.Zero);
|
GL.BindVertexArray(0);
|
||||||
GL.Flush();
|
GL.Flush();
|
||||||
glControl.SwapBuffers();
|
glControl.SwapBuffers();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,6 +120,9 @@
|
|||||||
<metadata name="menuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
<metadata name="menuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
<value>312, 17</value>
|
<value>312, 17</value>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
<metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
|
<value>432, 17</value>
|
||||||
|
</metadata>
|
||||||
<data name="fontPreviewBox.Text" xml:space="preserve">
|
<data name="fontPreviewBox.Text" xml:space="preserve">
|
||||||
<value>abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWYZ
|
<value>abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWYZ
|
||||||
1234567890.:,;'\"(!?)+-*/=
|
1234567890.:,;'\"(!?)+-*/=
|
||||||
@@ -138,9 +141,6 @@ The quick brown fox jumps over the lazy dog. 1234567890
|
|||||||
|
|
||||||
The quick brown fox jumps over the lazy dog. 1234567890</value>
|
The quick brown fox jumps over the lazy dog. 1234567890</value>
|
||||||
</data>
|
</data>
|
||||||
<metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
|
||||||
<value>432, 17</value>
|
|
||||||
</metadata>
|
|
||||||
<metadata name="timer.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
<metadata name="timer.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
<value>553, 17</value>
|
<value>553, 17</value>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
|||||||
65
AssetStudioGUI/ExportOptions.Designer.cs
generated
65
AssetStudioGUI/ExportOptions.Designer.cs
generated
@@ -35,6 +35,8 @@ namespace AssetStudioGUI
|
|||||||
OKbutton = new System.Windows.Forms.Button();
|
OKbutton = new System.Windows.Forms.Button();
|
||||||
Cancel = new System.Windows.Forms.Button();
|
Cancel = new System.Windows.Forms.Button();
|
||||||
groupBox1 = new System.Windows.Forms.GroupBox();
|
groupBox1 = new System.Windows.Forms.GroupBox();
|
||||||
|
assetGroupOptions = new System.Windows.Forms.ComboBox();
|
||||||
|
label7 = new System.Windows.Forms.Label();
|
||||||
openAfterExport = new System.Windows.Forms.CheckBox();
|
openAfterExport = new System.Windows.Forms.CheckBox();
|
||||||
restoreExtensionName = new System.Windows.Forms.CheckBox();
|
restoreExtensionName = new System.Windows.Forms.CheckBox();
|
||||||
assetGroupOptions = new System.Windows.Forms.ComboBox();
|
assetGroupOptions = new System.Windows.Forms.ComboBox();
|
||||||
@@ -71,11 +73,10 @@ namespace AssetStudioGUI
|
|||||||
key = new System.Windows.Forms.NumericUpDown();
|
key = new System.Windows.Forms.NumericUpDown();
|
||||||
keyToolTip = new System.Windows.Forms.ToolTip(components);
|
keyToolTip = new System.Windows.Forms.ToolTip(components);
|
||||||
groupBox4 = new System.Windows.Forms.GroupBox();
|
groupBox4 = new System.Windows.Forms.GroupBox();
|
||||||
|
disableAnimationClip = new System.Windows.Forms.CheckBox();
|
||||||
minimalAssetMap = new System.Windows.Forms.CheckBox();
|
minimalAssetMap = new System.Windows.Forms.CheckBox();
|
||||||
disableShader = new System.Windows.Forms.CheckBox();
|
disableShader = new System.Windows.Forms.CheckBox();
|
||||||
disableRenderer = new System.Windows.Forms.CheckBox();
|
disableRenderer = new System.Windows.Forms.CheckBox();
|
||||||
resolveToolTip = new System.Windows.Forms.ToolTip(components);
|
|
||||||
skipToolTip = new System.Windows.Forms.ToolTip(components);
|
|
||||||
groupBox1.SuspendLayout();
|
groupBox1.SuspendLayout();
|
||||||
panel1.SuspendLayout();
|
panel1.SuspendLayout();
|
||||||
groupBox2.SuspendLayout();
|
groupBox2.SuspendLayout();
|
||||||
@@ -112,6 +113,8 @@ namespace AssetStudioGUI
|
|||||||
// groupBox1
|
// groupBox1
|
||||||
//
|
//
|
||||||
groupBox1.AutoSize = true;
|
groupBox1.AutoSize = true;
|
||||||
|
groupBox1.Controls.Add(assetGroupOptions);
|
||||||
|
groupBox1.Controls.Add(label7);
|
||||||
groupBox1.Controls.Add(openAfterExport);
|
groupBox1.Controls.Add(openAfterExport);
|
||||||
groupBox1.Controls.Add(restoreExtensionName);
|
groupBox1.Controls.Add(restoreExtensionName);
|
||||||
groupBox1.Controls.Add(assetGroupOptions);
|
groupBox1.Controls.Add(assetGroupOptions);
|
||||||
@@ -123,17 +126,38 @@ namespace AssetStudioGUI
|
|||||||
groupBox1.Margin = new System.Windows.Forms.Padding(4);
|
groupBox1.Margin = new System.Windows.Forms.Padding(4);
|
||||||
groupBox1.Name = "groupBox1";
|
groupBox1.Name = "groupBox1";
|
||||||
groupBox1.Padding = new System.Windows.Forms.Padding(4);
|
groupBox1.Padding = new System.Windows.Forms.Padding(4);
|
||||||
groupBox1.Size = new System.Drawing.Size(271, 243);
|
groupBox1.Size = new System.Drawing.Size(271, 273);
|
||||||
groupBox1.TabIndex = 9;
|
groupBox1.TabIndex = 9;
|
||||||
groupBox1.TabStop = false;
|
groupBox1.TabStop = false;
|
||||||
groupBox1.Text = "Export";
|
groupBox1.Text = "Export";
|
||||||
//
|
//
|
||||||
|
// assetGroupOptions
|
||||||
|
//
|
||||||
|
assetGroupOptions.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||||
|
assetGroupOptions.FormattingEnabled = true;
|
||||||
|
assetGroupOptions.Items.AddRange(new object[] { "type name", "container path", "source file name", "do not group" });
|
||||||
|
assetGroupOptions.Location = new System.Drawing.Point(7, 83);
|
||||||
|
assetGroupOptions.Margin = new System.Windows.Forms.Padding(4);
|
||||||
|
assetGroupOptions.Name = "assetGroupOptions";
|
||||||
|
assetGroupOptions.Size = new System.Drawing.Size(173, 23);
|
||||||
|
assetGroupOptions.TabIndex = 12;
|
||||||
|
//
|
||||||
|
// label7
|
||||||
|
//
|
||||||
|
label7.AutoSize = true;
|
||||||
|
label7.Location = new System.Drawing.Point(7, 64);
|
||||||
|
label7.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||||
|
label7.Name = "label7";
|
||||||
|
label7.Size = new System.Drawing.Size(140, 15);
|
||||||
|
label7.TabIndex = 11;
|
||||||
|
label7.Text = "Group exported assets by";
|
||||||
|
//
|
||||||
// openAfterExport
|
// openAfterExport
|
||||||
//
|
//
|
||||||
openAfterExport.AutoSize = true;
|
openAfterExport.AutoSize = true;
|
||||||
openAfterExport.Checked = true;
|
openAfterExport.Checked = true;
|
||||||
openAfterExport.CheckState = System.Windows.Forms.CheckState.Checked;
|
openAfterExport.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||||
openAfterExport.Location = new System.Drawing.Point(7, 200);
|
openAfterExport.Location = new System.Drawing.Point(8, 230);
|
||||||
openAfterExport.Margin = new System.Windows.Forms.Padding(4);
|
openAfterExport.Margin = new System.Windows.Forms.Padding(4);
|
||||||
openAfterExport.Name = "openAfterExport";
|
openAfterExport.Name = "openAfterExport";
|
||||||
openAfterExport.Size = new System.Drawing.Size(153, 19);
|
openAfterExport.Size = new System.Drawing.Size(153, 19);
|
||||||
@@ -146,7 +170,7 @@ namespace AssetStudioGUI
|
|||||||
restoreExtensionName.AutoSize = true;
|
restoreExtensionName.AutoSize = true;
|
||||||
restoreExtensionName.Checked = true;
|
restoreExtensionName.Checked = true;
|
||||||
restoreExtensionName.CheckState = System.Windows.Forms.CheckState.Checked;
|
restoreExtensionName.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||||
restoreExtensionName.Location = new System.Drawing.Point(7, 72);
|
restoreExtensionName.Location = new System.Drawing.Point(7, 109);
|
||||||
restoreExtensionName.Margin = new System.Windows.Forms.Padding(4);
|
restoreExtensionName.Margin = new System.Windows.Forms.Padding(4);
|
||||||
restoreExtensionName.Name = "restoreExtensionName";
|
restoreExtensionName.Name = "restoreExtensionName";
|
||||||
restoreExtensionName.Size = new System.Drawing.Size(204, 19);
|
restoreExtensionName.Size = new System.Drawing.Size(204, 19);
|
||||||
@@ -171,7 +195,7 @@ namespace AssetStudioGUI
|
|||||||
label6.Location = new System.Drawing.Point(7, 21);
|
label6.Location = new System.Drawing.Point(7, 21);
|
||||||
label6.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
label6.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||||
label6.Name = "label6";
|
label6.Name = "label6";
|
||||||
label6.Size = new System.Drawing.Size(140, 15);
|
label6.Size = new System.Drawing.Size(80, 15);
|
||||||
label6.TabIndex = 7;
|
label6.TabIndex = 7;
|
||||||
label6.Text = "Group exported assets by";
|
label6.Text = "Group exported assets by";
|
||||||
//
|
//
|
||||||
@@ -180,7 +204,7 @@ namespace AssetStudioGUI
|
|||||||
convertAudio.AutoSize = true;
|
convertAudio.AutoSize = true;
|
||||||
convertAudio.Checked = true;
|
convertAudio.Checked = true;
|
||||||
convertAudio.CheckState = System.Windows.Forms.CheckState.Checked;
|
convertAudio.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||||
convertAudio.Location = new System.Drawing.Point(7, 172);
|
convertAudio.Location = new System.Drawing.Point(7, 204);
|
||||||
convertAudio.Margin = new System.Windows.Forms.Padding(4);
|
convertAudio.Margin = new System.Windows.Forms.Padding(4);
|
||||||
convertAudio.Name = "convertAudio";
|
convertAudio.Name = "convertAudio";
|
||||||
convertAudio.Size = new System.Drawing.Size(200, 19);
|
convertAudio.Size = new System.Drawing.Size(200, 19);
|
||||||
@@ -194,7 +218,7 @@ namespace AssetStudioGUI
|
|||||||
panel1.Controls.Add(tojpg);
|
panel1.Controls.Add(tojpg);
|
||||||
panel1.Controls.Add(topng);
|
panel1.Controls.Add(topng);
|
||||||
panel1.Controls.Add(tobmp);
|
panel1.Controls.Add(tobmp);
|
||||||
panel1.Location = new System.Drawing.Point(23, 128);
|
panel1.Location = new System.Drawing.Point(23, 164);
|
||||||
panel1.Margin = new System.Windows.Forms.Padding(4);
|
panel1.Margin = new System.Windows.Forms.Padding(4);
|
||||||
panel1.Name = "panel1";
|
panel1.Name = "panel1";
|
||||||
panel1.Size = new System.Drawing.Size(236, 38);
|
panel1.Size = new System.Drawing.Size(236, 38);
|
||||||
@@ -251,7 +275,7 @@ namespace AssetStudioGUI
|
|||||||
converttexture.AutoSize = true;
|
converttexture.AutoSize = true;
|
||||||
converttexture.Checked = true;
|
converttexture.Checked = true;
|
||||||
converttexture.CheckState = System.Windows.Forms.CheckState.Checked;
|
converttexture.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||||
converttexture.Location = new System.Drawing.Point(7, 100);
|
converttexture.Location = new System.Drawing.Point(7, 136);
|
||||||
converttexture.Margin = new System.Windows.Forms.Padding(4);
|
converttexture.Margin = new System.Windows.Forms.Padding(4);
|
||||||
converttexture.Name = "converttexture";
|
converttexture.Name = "converttexture";
|
||||||
converttexture.Size = new System.Drawing.Size(123, 19);
|
converttexture.Size = new System.Drawing.Size(123, 19);
|
||||||
@@ -536,20 +560,32 @@ namespace AssetStudioGUI
|
|||||||
// groupBox4
|
// groupBox4
|
||||||
//
|
//
|
||||||
groupBox4.AutoSize = true;
|
groupBox4.AutoSize = true;
|
||||||
|
groupBox4.Controls.Add(disableAnimationClip);
|
||||||
groupBox4.Controls.Add(minimalAssetMap);
|
groupBox4.Controls.Add(minimalAssetMap);
|
||||||
groupBox4.Controls.Add(disableShader);
|
groupBox4.Controls.Add(disableShader);
|
||||||
groupBox4.Controls.Add(disableRenderer);
|
groupBox4.Controls.Add(disableRenderer);
|
||||||
groupBox4.Controls.Add(key);
|
groupBox4.Controls.Add(key);
|
||||||
groupBox4.Controls.Add(encrypted);
|
groupBox4.Controls.Add(encrypted);
|
||||||
groupBox4.Location = new System.Drawing.Point(13, 258);
|
groupBox4.Location = new System.Drawing.Point(13, 287);
|
||||||
groupBox4.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
groupBox4.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||||
groupBox4.Name = "groupBox4";
|
groupBox4.Name = "groupBox4";
|
||||||
groupBox4.Padding = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
groupBox4.Padding = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||||
groupBox4.Size = new System.Drawing.Size(272, 187);
|
groupBox4.Size = new System.Drawing.Size(272, 146);
|
||||||
groupBox4.TabIndex = 13;
|
groupBox4.TabIndex = 13;
|
||||||
groupBox4.TabStop = false;
|
groupBox4.TabStop = false;
|
||||||
groupBox4.Text = "Options";
|
groupBox4.Text = "Options";
|
||||||
//
|
//
|
||||||
|
// disableAnimationClip
|
||||||
|
//
|
||||||
|
disableAnimationClip.AutoSize = true;
|
||||||
|
disableAnimationClip.Location = new System.Drawing.Point(119, 72);
|
||||||
|
disableAnimationClip.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||||
|
disableAnimationClip.Name = "disableAnimationClip";
|
||||||
|
disableAnimationClip.Size = new System.Drawing.Size(144, 19);
|
||||||
|
disableAnimationClip.TabIndex = 18;
|
||||||
|
disableAnimationClip.Text = "Disable AnimationClip";
|
||||||
|
disableAnimationClip.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
// minimalAssetMap
|
// minimalAssetMap
|
||||||
//
|
//
|
||||||
minimalAssetMap.AutoSize = true;
|
minimalAssetMap.AutoSize = true;
|
||||||
@@ -569,7 +605,6 @@ namespace AssetStudioGUI
|
|||||||
disableShader.Size = new System.Drawing.Size(103, 19);
|
disableShader.Size = new System.Drawing.Size(103, 19);
|
||||||
disableShader.TabIndex = 16;
|
disableShader.TabIndex = 16;
|
||||||
disableShader.Text = "Disable Shader";
|
disableShader.Text = "Disable Shader";
|
||||||
skipToolTip.SetToolTip(disableShader, "Skips the container recovery step.\nImproves loading when dealing with a large number of files.");
|
|
||||||
disableShader.UseVisualStyleBackColor = true;
|
disableShader.UseVisualStyleBackColor = true;
|
||||||
//
|
//
|
||||||
// disableRenderer
|
// disableRenderer
|
||||||
@@ -581,7 +616,6 @@ namespace AssetStudioGUI
|
|||||||
disableRenderer.Size = new System.Drawing.Size(114, 19);
|
disableRenderer.Size = new System.Drawing.Size(114, 19);
|
||||||
disableRenderer.TabIndex = 15;
|
disableRenderer.TabIndex = 15;
|
||||||
disableRenderer.Text = "Disable Renderer";
|
disableRenderer.Text = "Disable Renderer";
|
||||||
skipToolTip.SetToolTip(disableRenderer, "Skips the container recovery step.\nImproves loading when dealing with a large number of files.");
|
|
||||||
disableRenderer.UseVisualStyleBackColor = true;
|
disableRenderer.UseVisualStyleBackColor = true;
|
||||||
//
|
//
|
||||||
// ExportOptions
|
// ExportOptions
|
||||||
@@ -661,10 +695,11 @@ namespace AssetStudioGUI
|
|||||||
private System.Windows.Forms.ToolTip keyToolTip;
|
private System.Windows.Forms.ToolTip keyToolTip;
|
||||||
private System.Windows.Forms.CheckBox exportUV0UV1;
|
private System.Windows.Forms.CheckBox exportUV0UV1;
|
||||||
private System.Windows.Forms.GroupBox groupBox4;
|
private System.Windows.Forms.GroupBox groupBox4;
|
||||||
private System.Windows.Forms.ToolTip resolveToolTip;
|
|
||||||
private System.Windows.Forms.ToolTip skipToolTip;
|
|
||||||
private System.Windows.Forms.CheckBox disableShader;
|
private System.Windows.Forms.CheckBox disableShader;
|
||||||
private System.Windows.Forms.CheckBox disableRenderer;
|
private System.Windows.Forms.CheckBox disableRenderer;
|
||||||
private System.Windows.Forms.CheckBox minimalAssetMap;
|
private System.Windows.Forms.CheckBox minimalAssetMap;
|
||||||
|
private System.Windows.Forms.ComboBox assetGroupOptions;
|
||||||
|
private System.Windows.Forms.Label label7;
|
||||||
|
private System.Windows.Forms.CheckBox disableAnimationClip;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -44,6 +44,7 @@ namespace AssetStudioGUI
|
|||||||
key.Value = Properties.Settings.Default.key;
|
key.Value = Properties.Settings.Default.key;
|
||||||
disableRenderer.Checked = Properties.Settings.Default.disableRenderer;
|
disableRenderer.Checked = Properties.Settings.Default.disableRenderer;
|
||||||
disableShader.Checked = Properties.Settings.Default.disableShader;
|
disableShader.Checked = Properties.Settings.Default.disableShader;
|
||||||
|
disableAnimationClip.Checked = Properties.Settings.Default.disableAnimationClip;
|
||||||
minimalAssetMap.Checked = Properties.Settings.Default.minimalAssetMap;
|
minimalAssetMap.Checked = Properties.Settings.Default.minimalAssetMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,6 +81,7 @@ namespace AssetStudioGUI
|
|||||||
Properties.Settings.Default.key = (byte)key.Value;
|
Properties.Settings.Default.key = (byte)key.Value;
|
||||||
Properties.Settings.Default.disableRenderer = disableRenderer.Checked;
|
Properties.Settings.Default.disableRenderer = disableRenderer.Checked;
|
||||||
Properties.Settings.Default.disableShader = disableShader.Checked;
|
Properties.Settings.Default.disableShader = disableShader.Checked;
|
||||||
|
Properties.Settings.Default.disableAnimationClip = disableAnimationClip.Checked;
|
||||||
Properties.Settings.Default.minimalAssetMap = minimalAssetMap.Checked;
|
Properties.Settings.Default.minimalAssetMap = minimalAssetMap.Checked;
|
||||||
Properties.Settings.Default.Save();
|
Properties.Settings.Default.Save();
|
||||||
MiHoYoBinData.Key = (byte)key.Value;
|
MiHoYoBinData.Key = (byte)key.Value;
|
||||||
@@ -87,6 +89,7 @@ namespace AssetStudioGUI
|
|||||||
AssetsHelper.Minimal = Properties.Settings.Default.minimalAssetMap;
|
AssetsHelper.Minimal = Properties.Settings.Default.minimalAssetMap;
|
||||||
Renderer.Parsable = !Properties.Settings.Default.disableRenderer;
|
Renderer.Parsable = !Properties.Settings.Default.disableRenderer;
|
||||||
Shader.Parsable = !Properties.Settings.Default.disableShader;
|
Shader.Parsable = !Properties.Settings.Default.disableShader;
|
||||||
|
AnimationClip.Parsable = !Properties.Settings.Default.disableAnimationClip;
|
||||||
DialogResult = DialogResult.OK;
|
DialogResult = DialogResult.OK;
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,24 +120,9 @@
|
|||||||
<metadata name="exportUvsTooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
<metadata name="exportUvsTooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
<value>17, 17</value>
|
<value>17, 17</value>
|
||||||
</metadata>
|
</metadata>
|
||||||
<metadata name="exportUvsTooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
|
||||||
<value>17, 17</value>
|
|
||||||
</metadata>
|
|
||||||
<metadata name="keyToolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
<metadata name="keyToolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
<value>162, 17</value>
|
<value>162, 17</value>
|
||||||
</metadata>
|
</metadata>
|
||||||
<metadata name="keyToolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
|
||||||
<value>162, 17</value>
|
|
||||||
</metadata>
|
|
||||||
<metadata name="skipToolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
|
||||||
<value>404, 17</value>
|
|
||||||
</metadata>
|
|
||||||
<metadata name="resolveToolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
|
||||||
<value>273, 17</value>
|
|
||||||
</metadata>
|
|
||||||
<metadata name="skipToolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
|
||||||
<value>404, 17</value>
|
|
||||||
</metadata>
|
|
||||||
<metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
<metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
<value>57</value>
|
<value>57</value>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
|||||||
36
AssetStudioGUI/Properties/Settings.Designer.cs
generated
36
AssetStudioGUI/Properties/Settings.Designer.cs
generated
@@ -465,5 +465,41 @@ namespace AssetStudioGUI.Properties {
|
|||||||
this["selectedCABMapName"] = value;
|
this["selectedCABMapName"] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
|
[global::System.Configuration.DefaultSettingValueAttribute("False")]
|
||||||
|
public bool disableAnimationClip {
|
||||||
|
get {
|
||||||
|
return ((bool)(this["disableAnimationClip"]));
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
this["disableAnimationClip"] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
|
[global::System.Configuration.DefaultSettingValueAttribute("True")]
|
||||||
|
public bool enableFileLogging {
|
||||||
|
get {
|
||||||
|
return ((bool)(this["enableFileLogging"]));
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
this["enableFileLogging"] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
|
[global::System.Configuration.DefaultSettingValueAttribute("False")]
|
||||||
|
public bool enableVerbose {
|
||||||
|
get {
|
||||||
|
return ((bool)(this["enableVerbose"]));
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
this["enableVerbose"] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,5 +113,14 @@
|
|||||||
<Setting Name="selectedCABMapName" Type="System.String" Scope="User">
|
<Setting Name="selectedCABMapName" Type="System.String" Scope="User">
|
||||||
<Value Profile="(Default)" />
|
<Value Profile="(Default)" />
|
||||||
</Setting>
|
</Setting>
|
||||||
|
<Setting Name="disableAnimationClip" Type="System.Boolean" Scope="User">
|
||||||
|
<Value Profile="(Default)">False</Value>
|
||||||
|
</Setting>
|
||||||
|
<Setting Name="enableFileLogging" Type="System.Boolean" Scope="User">
|
||||||
|
<Value Profile="(Default)">True</Value>
|
||||||
|
</Setting>
|
||||||
|
<Setting Name="enableVerbose" Type="System.Boolean" Scope="User">
|
||||||
|
<Value Profile="(Default)">False</Value>
|
||||||
|
</Setting>
|
||||||
</Settings>
|
</Settings>
|
||||||
</SettingsFile>
|
</SettingsFile>
|
||||||
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||||
<Version>0.90.00</Version>
|
<Version>0.90.10</Version>
|
||||||
<AssemblyVersion>0.90.00</AssemblyVersion>
|
<AssemblyVersion>0.90.10</AssemblyVersion>
|
||||||
<FileVersion>0.90.00</FileVersion>
|
<FileVersion>0.90.10</FileVersion>
|
||||||
<Copyright>Copyright © Perfare 2018-2022</Copyright>
|
<Copyright>Copyright © Perfare 2018-2022</Copyright>
|
||||||
<DebugType>embedded</DebugType>
|
<DebugType>embedded</DebugType>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Kyaru.Texture2DDecoder" Version="0.17.0" />
|
<PackageReference Include="Kyaru.Texture2DDecoder" Version="0.17.0" />
|
||||||
<PackageReference Include="Kyaru.Texture2DDecoder.Windows" Version="0.1.0" />
|
<PackageReference Include="Kyaru.Texture2DDecoder.Windows" Version="0.1.0" />
|
||||||
<PackageReference Include="Mono.Cecil" Version="0.11.4" />
|
<PackageReference Include="Mono.Cecil" Version="0.11.5" />
|
||||||
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta15" />
|
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta15" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -244,7 +244,7 @@ namespace AssetStudio
|
|||||||
private static void SetFrame(ImportedFrame frame, Vector3 t, Quaternion q, Vector3 s)
|
private static void SetFrame(ImportedFrame frame, Vector3 t, Quaternion q, Vector3 s)
|
||||||
{
|
{
|
||||||
frame.LocalPosition = new Vector3(-t.X, t.Y, t.Z);
|
frame.LocalPosition = new Vector3(-t.X, t.Y, t.Z);
|
||||||
frame.LocalRotation = Fbx.QuaternionToEuler(new Quaternion(q.X, -q.Y, -q.Z, q.W));
|
frame.LocalRotation = new Quaternion(q.X, -q.Y, -q.Z, q.W);
|
||||||
frame.LocalScale = s;
|
frame.LocalScale = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -818,8 +818,8 @@ namespace AssetStudio
|
|||||||
for (int i = 0; i < numKeys; i++)
|
for (int i = 0; i < numKeys; i++)
|
||||||
{
|
{
|
||||||
var quat = quats[i];
|
var quat = quats[i];
|
||||||
var value = Fbx.QuaternionToEuler(new Quaternion(quat.X, -quat.Y, -quat.Z, quat.W));
|
var value = new Quaternion(quat.X, -quat.Y, -quat.Z, quat.W);
|
||||||
track.Rotations.Add(new ImportedKeyframe<Vector3>(times[i], value));
|
track.Rotations.Add(new ImportedKeyframe<Quaternion>(times[i], value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach (var m_RotationCurve in animationClip.m_RotationCurves)
|
foreach (var m_RotationCurve in animationClip.m_RotationCurves)
|
||||||
@@ -827,8 +827,8 @@ namespace AssetStudio
|
|||||||
var track = iAnim.FindTrack(FixBonePath(animationClip, m_RotationCurve.path));
|
var track = iAnim.FindTrack(FixBonePath(animationClip, m_RotationCurve.path));
|
||||||
foreach (var m_Curve in m_RotationCurve.curve.m_Curve)
|
foreach (var m_Curve in m_RotationCurve.curve.m_Curve)
|
||||||
{
|
{
|
||||||
var value = Fbx.QuaternionToEuler(new Quaternion(m_Curve.value.X, -m_Curve.value.Y, -m_Curve.value.Z, m_Curve.value.W));
|
var value = new Quaternion(m_Curve.value.X, -m_Curve.value.Y, -m_Curve.value.Z, m_Curve.value.W);
|
||||||
track.Rotations.Add(new ImportedKeyframe<Vector3>(m_Curve.time, value));
|
track.Rotations.Add(new ImportedKeyframe<Quaternion>(m_Curve.time, value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach (var m_PositionCurve in animationClip.m_PositionCurves)
|
foreach (var m_PositionCurve in animationClip.m_PositionCurves)
|
||||||
@@ -854,7 +854,8 @@ namespace AssetStudio
|
|||||||
var track = iAnim.FindTrack(FixBonePath(animationClip, m_EulerCurve.path));
|
var track = iAnim.FindTrack(FixBonePath(animationClip, m_EulerCurve.path));
|
||||||
foreach (var m_Curve in m_EulerCurve.curve.m_Curve)
|
foreach (var m_Curve in m_EulerCurve.curve.m_Curve)
|
||||||
{
|
{
|
||||||
track.Rotations.Add(new ImportedKeyframe<Vector3>(m_Curve.time, new Vector3(m_Curve.value.X, -m_Curve.value.Y, -m_Curve.value.Z)));
|
var value = Fbx.EulerToQuaternion(new Vector3(m_Curve.value.X, -m_Curve.value.Y, -m_Curve.value.Z));
|
||||||
|
track.Rotations.Add(new ImportedKeyframe<Quaternion>(m_Curve.time, value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1009,14 +1010,13 @@ namespace AssetStudio
|
|||||||
)));
|
)));
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
var value = Fbx.QuaternionToEuler(new Quaternion
|
track.Rotations.Add(new ImportedKeyframe<Quaternion>(time, new Quaternion
|
||||||
(
|
(
|
||||||
data[curveIndex++ + offset],
|
data[curveIndex++ + offset],
|
||||||
-data[curveIndex++ + offset],
|
-data[curveIndex++ + offset],
|
||||||
-data[curveIndex++ + offset],
|
-data[curveIndex++ + offset],
|
||||||
data[curveIndex++ + offset]
|
data[curveIndex++ + offset]
|
||||||
));
|
)));
|
||||||
track.Rotations.Add(new ImportedKeyframe<Vector3>(time, value));
|
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
track.Scalings.Add(new ImportedKeyframe<Vector3>(time, new Vector3
|
track.Scalings.Add(new ImportedKeyframe<Vector3>(time, new Vector3
|
||||||
@@ -1027,12 +1027,13 @@ namespace AssetStudio
|
|||||||
)));
|
)));
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
track.Rotations.Add(new ImportedKeyframe<Vector3>(time, new Vector3
|
var value = Fbx.EulerToQuaternion(new Vector3
|
||||||
(
|
(
|
||||||
data[curveIndex++ + offset],
|
data[curveIndex++ + offset],
|
||||||
-data[curveIndex++ + offset],
|
-data[curveIndex++ + offset],
|
||||||
-data[curveIndex++ + offset]
|
-data[curveIndex++ + offset]
|
||||||
)));
|
));
|
||||||
|
track.Rotations.Add(new ImportedKeyframe<Quaternion>(time, value));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
curveIndex++;
|
curveIndex++;
|
||||||
|
|||||||
Reference in New Issue
Block a user