diff --git a/Source/AssetRipper.IO.Files/AssetRipper.IO.Files.csproj b/Source/AssetRipper.IO.Files/AssetRipper.IO.Files.csproj
index f81b0e398..674d0b212 100644
--- a/Source/AssetRipper.IO.Files/AssetRipper.IO.Files.csproj
+++ b/Source/AssetRipper.IO.Files/AssetRipper.IO.Files.csproj
@@ -10,6 +10,7 @@
+
diff --git a/Source/AssetRipper.IO.Files/BundleFiles/FileStream/BundleFileBlockReader.cs b/Source/AssetRipper.IO.Files/BundleFiles/FileStream/BundleFileBlockReader.cs
index e6ccd5ed3..9b1f68b16 100644
--- a/Source/AssetRipper.IO.Files/BundleFiles/FileStream/BundleFileBlockReader.cs
+++ b/Source/AssetRipper.IO.Files/BundleFiles/FileStream/BundleFileBlockReader.cs
@@ -107,7 +107,14 @@ namespace AssetRipper.IO.Files.BundleFiles.FileStream
break;
default:
- UnsupportedBundleDecompression.Throw(entry.PathFixed, compressType);
+ if (ZstdCompression.IsZstd(m_stream))
+ {
+ ZstdCompression.DecompressStream(m_stream, block.CompressedSize, m_cachedBlockStream, block.UncompressedSize);
+ }
+ else
+ {
+ UnsupportedBundleDecompression.Throw(entry.PathFixed, compressType);
+ }
break;
}
blockStream = m_cachedBlockStream;
diff --git a/Source/AssetRipper.IO.Files/BundleFiles/ZstdCompression.cs b/Source/AssetRipper.IO.Files/BundleFiles/ZstdCompression.cs
new file mode 100644
index 000000000..b9ecd0fc4
--- /dev/null
+++ b/Source/AssetRipper.IO.Files/BundleFiles/ZstdCompression.cs
@@ -0,0 +1,28 @@
+using AssetRipper.IO.Files.Streams;
+using ZstdSharp;
+
+namespace AssetRipper.IO.Files.BundleFiles
+{
+ public static class ZstdCompression
+ {
+ private static readonly byte[] Signature = [0x28, 0xB5, 0x2F, 0xFD];
+ public static bool IsZstd(Stream Stream)
+ {
+ Span buffer = stackalloc byte[4];
+
+ long pos = Stream.Position;
+ Stream.ReadExactly(buffer);
+ Stream.Position = pos;
+
+ return buffer.SequenceEqual(Signature);
+ }
+
+ public static void DecompressStream(Stream compressedStream, long compressedSize, Stream decompressedStream, long decompressedSize)
+ {
+ using PartialStream compressedPartialStream = new PartialStream(compressedStream, compressedStream.Position, compressedSize, true);
+ using PartialStream decompressedPartialStream = new PartialStream(decompressedStream, decompressedStream.Position, decompressedSize, true);
+ using DecompressionStream zstdStream = new DecompressionStream(compressedPartialStream);
+ zstdStream.CopyTo(decompressedPartialStream);
+ }
+ }
+}