diff --git a/AssetStudio/AssetStudio.csproj b/AssetStudio/AssetStudio.csproj
index e7d3c21..d38d9ad 100644
--- a/AssetStudio/AssetStudio.csproj
+++ b/AssetStudio/AssetStudio.csproj
@@ -9,12 +9,14 @@
+
+
diff --git a/AssetStudio/AssetsManager.cs b/AssetStudio/AssetsManager.cs
index cbb4b28..1834ec3 100644
--- a/AssetStudio/AssetsManager.cs
+++ b/AssetStudio/AssetsManager.cs
@@ -11,6 +11,7 @@ namespace AssetStudio
public class AssetsManager
{
public string SpecifyUnityVersion;
+ public bool ZstdEnabled = true;
public List assetsFileList = new List();
private HashSet filteredAssetTypesList = new HashSet();
@@ -267,7 +268,7 @@ namespace AssetStudio
Logger.Info("Loading " + reader.FullPath);
try
{
- var bundleFile = new BundleFile(reader, SpecifyUnityVersion);
+ var bundleFile = new BundleFile(reader, ZstdEnabled, SpecifyUnityVersion);
foreach (var file in bundleFile.fileList)
{
var dummyPath = Path.Combine(Path.GetDirectoryName(reader.FullPath), file.fileName);
diff --git a/AssetStudio/BundleFile.cs b/AssetStudio/BundleFile.cs
index f82fb12..6b492fa 100644
--- a/AssetStudio/BundleFile.cs
+++ b/AssetStudio/BundleFile.cs
@@ -1,4 +1,5 @@
using K4os.Compression.LZ4;
+using ZstdSharp;
using System;
using System.IO;
using System.Linq;
@@ -36,7 +37,8 @@ namespace AssetStudio
Lzma,
Lz4,
Lz4HC,
- Lzham
+ Lzham,
+ Custom,
}
public class BundleFile
@@ -74,7 +76,7 @@ namespace AssetStudio
public StreamFile[] fileList;
- public BundleFile(FileReader reader, string specUnityVer = "")
+ public BundleFile(FileReader reader, bool useZstd, string specUnityVer = "")
{
m_Header = new Header();
m_Header.signature = reader.ReadStringToNull();
@@ -127,7 +129,7 @@ namespace AssetStudio
ReadBlocksInfoAndDirectory(reader, ver);
using (var blocksStream = CreateBlocksStream(reader.FullPath))
{
- ReadBlocks(reader, blocksStream);
+ ReadBlocks(reader, blocksStream, useZstd);
ReadFiles(blocksStream, reader.FullPath);
}
break;
@@ -325,7 +327,7 @@ namespace AssetStudio
break;
}
default:
- throw new IOException($"Unsupported compression type {compressionType}");
+ throw new IOException($"Unsupported block info compression type {compressionType}");
}
using (var blocksInfoReader = new EndianBinaryReader(blocksInfoUncompressedStream))
@@ -362,8 +364,10 @@ namespace AssetStudio
}
}
- private void ReadBlocks(FileReader reader, Stream blocksStream)
+ private void ReadBlocks(FileReader reader, Stream blocksStream, bool useZstd)
{
+ var zstdCodec = new Decompressor();
+ var i = 0;
foreach (var blockInfo in m_BlocksInfo)
{
var compressionType = (CompressionType)(blockInfo.flags & StorageBlockFlags.CompressionTypeMask);
@@ -381,6 +385,7 @@ namespace AssetStudio
}
case CompressionType.Lz4:
case CompressionType.Lz4HC:
+ case CompressionType.Custom:
{
var compressedSize = (int)blockInfo.compressedSize;
var compressedBytes = BigArrayPool.Shared.Rent(compressedSize);
@@ -389,10 +394,30 @@ namespace AssetStudio
var uncompressedBytes = BigArrayPool.Shared.Rent(uncompressedSize);
try
{
- var numWrite = LZ4Codec.Decode(compressedBytes, 0, compressedSize, uncompressedBytes, 0, uncompressedSize);
+ var compTypeStr = compressionType.ToString();
+ if (compressionType == CompressionType.Custom)
+ {
+ compTypeStr = useZstd ? "Zstd" : "Lz4";
+ if (i == 0)
+ {
+ Logger.Debug($"Custom block compression type was detected. Trying to decompress as {compTypeStr} archive..");
+ i++;
+ }
+ }
+
+ int numWrite;
+ if (compressionType == CompressionType.Custom && useZstd)
+ {
+ numWrite = zstdCodec.Unwrap(compressedBytes, 0, compressedSize, uncompressedBytes, 0, uncompressedSize);
+ }
+ else
+ {
+ numWrite = LZ4Codec.Decode(compressedBytes, 0, compressedSize, uncompressedBytes, 0, uncompressedSize);
+ }
+
if (numWrite != uncompressedSize)
{
- throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes");
+ throw new IOException($"{compTypeStr} block decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes");
}
blocksStream.Write(uncompressedBytes, 0, uncompressedSize);
}
@@ -404,7 +429,7 @@ namespace AssetStudio
break;
}
default:
- throw new IOException($"Unsupported compression type {compressionType}");
+ throw new IOException($"Unsupported block compression type {compressionType}");
}
}
blocksStream.Position = 0;
diff --git a/AssetStudioCLI/Options/CLIOptions.cs b/AssetStudioCLI/Options/CLIOptions.cs
index 7ab20c8..d17a4de 100644
--- a/AssetStudioCLI/Options/CLIOptions.cs
+++ b/AssetStudioCLI/Options/CLIOptions.cs
@@ -67,6 +67,12 @@ namespace AssetStudioCLI.Options
NameAndContainer,
}
+ internal enum CustomCompressionType
+ {
+ Zstd,
+ Lz4,
+ }
+
internal static class CLIOptions
{
public static bool isParsed;
@@ -105,6 +111,7 @@ namespace AssetStudioCLI.Options
public static Option> o_filterByPathID;
public static Option> o_filterByText;
//advanced
+ public static Option o_customCompressionType;
public static Option o_exportAssetList;
public static Option o_assemblyPath;
public static Option o_unityVersion;
@@ -377,6 +384,18 @@ namespace AssetStudioCLI.Options
#endregion
#region Init Advanced Options
+ o_customCompressionType = new GroupedOption
+ (
+ optionDefaultValue: CustomCompressionType.Zstd,
+ optionName: "--custom-compression ",
+ optionDescription: "Specify the compression type for assets that use custom compression\n" +
+ "\n" +
+ "Zstd - Try to decompress as zstd archive\n" +
+ "Lz4 - Try to decompress as lz4 archive\n",
+ optionExample: "Example: \"--custom-compression lz4\"\n",
+ optionHelpGroup: HelpGroups.Advanced
+ );
+
o_exportAssetList = new GroupedOption
(
optionDefaultValue: ExportListType.None,
@@ -838,6 +857,22 @@ namespace AssetStudioCLI.Options
return;
}
break;
+ case "--custom-compression":
+ switch (value.ToLower())
+ {
+ case "zstd":
+ o_customCompressionType.Value = CustomCompressionType.Zstd;
+ break;
+ case "lz4":
+ case "lz4hc":
+ o_customCompressionType.Value = CustomCompressionType.Lz4;
+ break;
+ default:
+ Console.WriteLine($"{"Error".Color(brightRed)} during parsing [{option}] option. Unsupported compression type: [{value.Color(brightRed)}].\n");
+ ShowOptionDescription(o_customCompressionType.Description);
+ return;
+ }
+ break;
case "--export-asset-list":
switch (value.ToLower())
{
@@ -1043,6 +1078,10 @@ namespace AssetStudioCLI.Options
var sb = new StringBuilder();
sb.AppendLine("[Current Options]");
sb.AppendLine($"# Working Mode: {o_workMode}");
+ if (o_customCompressionType.Value != o_customCompressionType.DefaultValue)
+ {
+ sb.AppendLine($"# Custom Compression Type: {o_customCompressionType}");
+ }
sb.AppendLine($"# Input Path: \"{inputPath}\"");
switch (o_workMode.Value)
{
diff --git a/AssetStudioCLI/Studio.cs b/AssetStudioCLI/Studio.cs
index ea5a797..1ff5b50 100644
--- a/AssetStudioCLI/Studio.cs
+++ b/AssetStudioCLI/Studio.cs
@@ -34,6 +34,7 @@ namespace AssetStudioCLI
{
var isLoaded = false;
assetsManager.SpecifyUnityVersion = CLIOptions.o_unityVersion.Value;
+ assetsManager.ZstdEnabled = CLIOptions.o_customCompressionType.Value == CustomCompressionType.Zstd;
if (!CLIOptions.f_loadAllAssets.Value)
{
assetsManager.SetAssetFilter(CLIOptions.o_exportAssetTypes.Value);
diff --git a/AssetStudioGUI/AssetStudioGUIForm.Designer.cs b/AssetStudioGUI/AssetStudioGUIForm.Designer.cs
index d00f83a..5a3fb77 100644
--- a/AssetStudioGUI/AssetStudioGUIForm.Designer.cs
+++ b/AssetStudioGUI/AssetStudioGUIForm.Designer.cs
@@ -42,6 +42,9 @@
this.enablePreview = new System.Windows.Forms.ToolStripMenuItem();
this.displayInfo = new System.Windows.Forms.ToolStripMenuItem();
this.buildTreeStructureToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.customCompressionTypeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.customCompressionZstdToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.customCompressionLZ4ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem14 = new System.Windows.Forms.ToolStripMenuItem();
this.specifyUnityVersion = new System.Windows.Forms.ToolStripTextBox();
this.showExpOpt = new System.Windows.Forms.ToolStripMenuItem();
@@ -82,15 +85,14 @@
this.filterTypeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.allToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.debugMenuItem = new System.Windows.Forms.ToolStripMenuItem();
- this.toolStripMenuItem15 = new System.Windows.Forms.ToolStripMenuItem();
this.showConsoleToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.toolStripMenuItem15 = new System.Windows.Forms.ToolStripMenuItem();
this.writeLogToFileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.exportClassStructuresMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.aboutToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.splitContainer1 = new System.Windows.Forms.SplitContainer();
this.tabControl1 = new System.Windows.Forms.TabControl();
this.tabPage1 = new System.Windows.Forms.TabPage();
- this.sceneTreeView = new AssetStudioGUI.GOHierarchy();
this.treeSearch = new System.Windows.Forms.TextBox();
this.tabPage2 = new System.Windows.Forms.TabPage();
this.assetListView = new System.Windows.Forms.ListView();
@@ -153,6 +155,7 @@
this.exportL2DWithClipsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.goToSceneHierarchyToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.showOriginalFileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.sceneTreeView = new AssetStudioGUI.GOHierarchy();
this.menuStrip1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit();
this.splitContainer1.Panel1.SuspendLayout();
@@ -244,6 +247,7 @@
this.enablePreview,
this.displayInfo,
this.buildTreeStructureToolStripMenuItem,
+ this.customCompressionTypeToolStripMenuItem,
this.toolStripMenuItem14,
this.showExpOpt});
this.optionsToolStripMenuItem.Name = "optionsToolStripMenuItem";
@@ -254,7 +258,7 @@
//
this.displayAll.CheckOnClick = true;
this.displayAll.Name = "displayAll";
- this.displayAll.Size = new System.Drawing.Size(207, 22);
+ this.displayAll.Size = new System.Drawing.Size(213, 22);
this.displayAll.Text = "Display all assets";
this.displayAll.ToolTipText = "Check this option will display all types assets. Not extractable assets can expor" +
"t the RAW file.";
@@ -266,7 +270,7 @@
this.enablePreview.CheckOnClick = true;
this.enablePreview.CheckState = System.Windows.Forms.CheckState.Checked;
this.enablePreview.Name = "enablePreview";
- this.enablePreview.Size = new System.Drawing.Size(207, 22);
+ this.enablePreview.Size = new System.Drawing.Size(213, 22);
this.enablePreview.Text = "Enable preview";
this.enablePreview.ToolTipText = "Toggle the loading and preview of readable assets, such as images, sounds, text, " +
"etc.\r\nDisable preview if you have performance or compatibility issues.";
@@ -278,7 +282,7 @@
this.displayInfo.CheckOnClick = true;
this.displayInfo.CheckState = System.Windows.Forms.CheckState.Checked;
this.displayInfo.Name = "displayInfo";
- this.displayInfo.Size = new System.Drawing.Size(207, 22);
+ this.displayInfo.Size = new System.Drawing.Size(213, 22);
this.displayInfo.Text = "Display asset information";
this.displayInfo.ToolTipText = "Toggle the overlay that shows information about each asset, eg. image size, forma" +
"t, audio bitrate, etc.";
@@ -290,17 +294,48 @@
this.buildTreeStructureToolStripMenuItem.CheckOnClick = true;
this.buildTreeStructureToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;
this.buildTreeStructureToolStripMenuItem.Name = "buildTreeStructureToolStripMenuItem";
- this.buildTreeStructureToolStripMenuItem.Size = new System.Drawing.Size(207, 22);
+ this.buildTreeStructureToolStripMenuItem.Size = new System.Drawing.Size(213, 22);
this.buildTreeStructureToolStripMenuItem.Text = "Build tree structure";
this.buildTreeStructureToolStripMenuItem.ToolTipText = "You can disable tree structure building if you don\'t use the Scene Hierarchy tab";
this.buildTreeStructureToolStripMenuItem.CheckedChanged += new System.EventHandler(this.buildTreeStructureToolStripMenuItem_CheckedChanged);
//
+ // customCompressionTypeToolStripMenuItem
+ //
+ this.customCompressionTypeToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this.customCompressionZstdToolStripMenuItem,
+ this.customCompressionLZ4ToolStripMenuItem});
+ this.customCompressionTypeToolStripMenuItem.Name = "customCompressionTypeToolStripMenuItem";
+ this.customCompressionTypeToolStripMenuItem.Size = new System.Drawing.Size(213, 22);
+ this.customCompressionTypeToolStripMenuItem.Text = "Custom compression type";
+ //
+ // customCompressionZstdToolStripMenuItem
+ //
+ this.customCompressionZstdToolStripMenuItem.Checked = true;
+ this.customCompressionZstdToolStripMenuItem.CheckOnClick = true;
+ this.customCompressionZstdToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;
+ this.customCompressionZstdToolStripMenuItem.Name = "customCompressionZstdToolStripMenuItem";
+ this.customCompressionZstdToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
+ this.customCompressionZstdToolStripMenuItem.Text = "Zstd";
+ this.customCompressionZstdToolStripMenuItem.ToolTipText = "If selected, Zstd-decompression will be used for assets with custom compression t" +
+ "ype";
+ this.customCompressionZstdToolStripMenuItem.CheckedChanged += new System.EventHandler(this.customCompressionZstd_CheckedChanged);
+ //
+ // customCompressionLZ4ToolStripMenuItem
+ //
+ this.customCompressionLZ4ToolStripMenuItem.CheckOnClick = true;
+ this.customCompressionLZ4ToolStripMenuItem.Name = "customCompressionLZ4ToolStripMenuItem";
+ this.customCompressionLZ4ToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
+ this.customCompressionLZ4ToolStripMenuItem.Text = "Lz4/Lz4HC";
+ this.customCompressionLZ4ToolStripMenuItem.ToolTipText = "If selected, Lz4-decompression will be used for assets with custom compression ty" +
+ "pe";
+ this.customCompressionLZ4ToolStripMenuItem.CheckedChanged += new System.EventHandler(this.customCompressionLZ4_CheckedChanged);
+ //
// toolStripMenuItem14
//
this.toolStripMenuItem14.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.specifyUnityVersion});
this.toolStripMenuItem14.Name = "toolStripMenuItem14";
- this.toolStripMenuItem14.Size = new System.Drawing.Size(207, 22);
+ this.toolStripMenuItem14.Size = new System.Drawing.Size(213, 22);
this.toolStripMenuItem14.Text = "Specify Unity version";
//
// specifyUnityVersion
@@ -314,7 +349,7 @@
// showExpOpt
//
this.showExpOpt.Name = "showExpOpt";
- this.showExpOpt.Size = new System.Drawing.Size(207, 22);
+ this.showExpOpt.Size = new System.Drawing.Size(213, 22);
this.showExpOpt.Text = "Export options";
this.showExpOpt.Click += new System.EventHandler(this.showExpOpt_Click);
//
@@ -607,14 +642,6 @@
this.debugMenuItem.Size = new System.Drawing.Size(54, 20);
this.debugMenuItem.Text = "Debug";
//
- // toolStripMenuItem15
- //
- this.toolStripMenuItem15.CheckOnClick = true;
- this.toolStripMenuItem15.Name = "toolStripMenuItem15";
- this.toolStripMenuItem15.Size = new System.Drawing.Size(288, 22);
- this.toolStripMenuItem15.Text = "Show debug messages in console logger";
- this.toolStripMenuItem15.Click += new System.EventHandler(this.toolStripMenuItem15_Click);
- //
// showConsoleToolStripMenuItem
//
this.showConsoleToolStripMenuItem.Checked = true;
@@ -625,6 +652,14 @@
this.showConsoleToolStripMenuItem.Text = "Show console logger";
this.showConsoleToolStripMenuItem.Click += new System.EventHandler(this.showConsoleToolStripMenuItem_Click);
//
+ // toolStripMenuItem15
+ //
+ this.toolStripMenuItem15.CheckOnClick = true;
+ this.toolStripMenuItem15.Name = "toolStripMenuItem15";
+ this.toolStripMenuItem15.Size = new System.Drawing.Size(288, 22);
+ this.toolStripMenuItem15.Text = "Show debug messages in console logger";
+ this.toolStripMenuItem15.Click += new System.EventHandler(this.toolStripMenuItem15_Click);
+ //
// writeLogToFileToolStripMenuItem
//
this.writeLogToFileToolStripMenuItem.CheckOnClick = true;
@@ -696,18 +731,6 @@
this.tabPage1.Text = "Scene Hierarchy";
this.tabPage1.UseVisualStyleBackColor = true;
//
- // sceneTreeView
- //
- this.sceneTreeView.CheckBoxes = true;
- this.sceneTreeView.Dock = System.Windows.Forms.DockStyle.Fill;
- this.sceneTreeView.HideSelection = false;
- this.sceneTreeView.Location = new System.Drawing.Point(0, 20);
- this.sceneTreeView.Name = "sceneTreeView";
- this.sceneTreeView.Size = new System.Drawing.Size(472, 587);
- this.sceneTreeView.TabIndex = 1;
- this.sceneTreeView.AfterCheck += new System.Windows.Forms.TreeViewEventHandler(this.sceneTreeView_AfterCheck);
- this.sceneTreeView.NodeMouseClick += new System.Windows.Forms.TreeNodeMouseClickEventHandler(this.sceneTreeView_NodeMouseClick);
- //
// treeSearch
//
this.treeSearch.Dock = System.Windows.Forms.DockStyle.Top;
@@ -1363,6 +1386,18 @@
this.showOriginalFileToolStripMenuItem.Visible = false;
this.showOriginalFileToolStripMenuItem.Click += new System.EventHandler(this.showOriginalFileToolStripMenuItem_Click);
//
+ // sceneTreeView
+ //
+ this.sceneTreeView.CheckBoxes = true;
+ this.sceneTreeView.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.sceneTreeView.HideSelection = false;
+ this.sceneTreeView.Location = new System.Drawing.Point(0, 20);
+ this.sceneTreeView.Name = "sceneTreeView";
+ this.sceneTreeView.Size = new System.Drawing.Size(472, 587);
+ this.sceneTreeView.TabIndex = 1;
+ this.sceneTreeView.AfterCheck += new System.Windows.Forms.TreeViewEventHandler(this.sceneTreeView_AfterCheck);
+ this.sceneTreeView.NodeMouseClick += new System.Windows.Forms.TreeNodeMouseClickEventHandler(this.sceneTreeView_NodeMouseClick);
+ //
// AssetStudioGUIForm
//
this.AllowDrop = true;
@@ -1538,6 +1573,9 @@
private System.Windows.Forms.ToolStripMenuItem exportL2DWithFadeToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem l2DModelWithFadeListToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem exportL2DWithFadeLstToolStripMenuItem;
+ private System.Windows.Forms.ToolStripMenuItem customCompressionTypeToolStripMenuItem;
+ private System.Windows.Forms.ToolStripMenuItem customCompressionZstdToolStripMenuItem;
+ private System.Windows.Forms.ToolStripMenuItem customCompressionLZ4ToolStripMenuItem;
}
}
diff --git a/AssetStudioGUI/AssetStudioGUIForm.cs b/AssetStudioGUI/AssetStudioGUIForm.cs
index 7428b3b..7951089 100644
--- a/AssetStudioGUI/AssetStudioGUIForm.cs
+++ b/AssetStudioGUI/AssetStudioGUIForm.cs
@@ -2267,6 +2267,18 @@ namespace AssetStudioGUI
}
}
+ private void customCompressionZstd_CheckedChanged(object sender, EventArgs e)
+ {
+ customCompressionLZ4ToolStripMenuItem.Checked = !customCompressionZstdToolStripMenuItem.Checked;
+ assetsManager.ZstdEnabled = customCompressionZstdToolStripMenuItem.Checked;
+ }
+
+ private void customCompressionLZ4_CheckedChanged(object sender, EventArgs e)
+ {
+ customCompressionZstdToolStripMenuItem.Checked = !customCompressionLZ4ToolStripMenuItem.Checked;
+ assetsManager.ZstdEnabled = customCompressionZstdToolStripMenuItem.Checked;
+ }
+
#region FMOD
private void FMODinit()
{
diff --git a/AssetStudioGUI/Studio.cs b/AssetStudioGUI/Studio.cs
index 78c6fa5..6db4f92 100644
--- a/AssetStudioGUI/Studio.cs
+++ b/AssetStudioGUI/Studio.cs
@@ -124,7 +124,7 @@ namespace AssetStudioGUI
private static int ExtractBundleFile(FileReader reader, string savePath)
{
Logger.Info($"Decompressing {reader.FileName} ...");
- var bundleFile = new BundleFile(reader, assetsManager.SpecifyUnityVersion);
+ var bundleFile = new BundleFile(reader, assetsManager.ZstdEnabled, assetsManager.SpecifyUnityVersion);
reader.Dispose();
if (bundleFile.fileList.Length > 0)
{