diff --git a/ArcFormats/Unity/ArcASSET.cs b/ArcFormats/Unity/ArcASSET.cs index 37d53e69..f6e2444b 100644 --- a/ArcFormats/Unity/ArcASSET.cs +++ b/ArcFormats/Unity/ArcASSET.cs @@ -42,12 +42,19 @@ namespace GameRes.Formats.Unity public override ArcFile TryOpen (ArcView file) { uint header_size = Binary.BigEndian (file.View.ReadUInt32 (0)); - uint file_size = Binary.BigEndian (file.View.ReadUInt32 (4)); - if (file_size != file.MaxOffset || header_size > file_size || 0 == header_size) - return null; + long file_size = Binary.BigEndian (file.View.ReadUInt32 (4)); int format = Binary.BigEndian (file.View.ReadInt32 (8)); - uint data_offset = Binary.BigEndian (file.View.ReadUInt32 (12)); - if (format <= 0 || format > 0x100 || data_offset >= file_size || data_offset < header_size) + if (format <= 0 || format > 0x100) + return null; + long data_offset = Binary.BigEndian (file.View.ReadUInt32 (12)); + if (format >= 22) + { + header_size = Binary.BigEndian (file.View.ReadUInt32 (0x14)); + file_size = Binary.BigEndian (file.View.ReadInt64 (0x18)); + data_offset = Binary.BigEndian (file.View.ReadInt64 (0x20)); + } + if (file_size != file.MaxOffset || header_size > file_size || 0 == header_size + || data_offset >= file_size || data_offset < header_size) return null; using (var stream = file.CreateStream()) using (var input = new AssetReader (stream)) @@ -84,7 +91,7 @@ namespace GameRes.Formats.Unity { reader.SetupReaders (obj.Asset); var tex = new Texture2D(); - tex.Load (reader, obj.Asset.Tree.Version); + tex.Load (reader, obj.Asset.Tree); if (0 == tex.m_DataLength) { reader.Dispose(); diff --git a/ArcFormats/Unity/Asset.cs b/ArcFormats/Unity/Asset.cs index 078a57ae..f49db1a4 100644 --- a/ArcFormats/Unity/Asset.cs +++ b/ArcFormats/Unity/Asset.cs @@ -41,7 +41,7 @@ namespace GameRes.Formats.Unity internal class Asset { int m_format; - uint m_data_offset; + long m_data_offset; bool m_is_little_endian; UnityTypeData m_tree = new UnityTypeData(); Dictionary m_adds; @@ -63,6 +63,13 @@ namespace GameRes.Formats.Unity m_data_offset = input.ReadUInt32(); if (m_format >= 9) m_is_little_endian = 0 == input.ReadInt32(); + if (m_format >= 22) + { + input.ReadInt32(); // header_size + input.ReadInt64(); // file_size + m_data_offset = input.ReadInt64(); + input.ReadInt64(); + } input.SetupReaders (this); m_tree.Load (input); @@ -176,7 +183,8 @@ namespace GameRes.Formats.Unity public void Load (AssetReader reader) { PathId = reader.ReadId(); - Offset = reader.ReadUInt32() + Asset.DataOffset; + Offset = reader.ReadOffset(); + Offset += Asset.DataOffset; Size = reader.ReadUInt32(); if (Asset.Format < 17) { diff --git a/ArcFormats/Unity/AssetReader.cs b/ArcFormats/Unity/AssetReader.cs index ffedf5c5..c77b993e 100644 --- a/ArcFormats/Unity/AssetReader.cs +++ b/ArcFormats/Unity/AssetReader.cs @@ -65,6 +65,7 @@ namespace GameRes.Formats.Unity public Func ReadInt32; public Func ReadInt64; public Func ReadId; + public Func ReadOffset; public void SetupReaders (Asset asset) { @@ -109,6 +110,10 @@ namespace GameRes.Formats.Unity ReadId = ReadInt64; else ReadId = () => ReadInt32(); + if (m_format >= 22) + ReadOffset = ReadInt64; + else + ReadOffset = () => ReadUInt32(); } /// @@ -122,6 +127,11 @@ namespace GameRes.Formats.Unity ReadId = () => ReadInt32(); } + public void Skip (int count) + { + m_input.Seek (count, SeekOrigin.Current); + } + /// /// Read bytes into specified buffer. /// diff --git a/ArcFormats/Unity/AudioClip.cs b/ArcFormats/Unity/AudioClip.cs index 74fbf692..ccd7c090 100644 --- a/ArcFormats/Unity/AudioClip.cs +++ b/ArcFormats/Unity/AudioClip.cs @@ -97,13 +97,13 @@ namespace GameRes.Formats.Unity internal class StreamingInfo { - public uint Offset; + public long Offset; public uint Size; public string Path; public void Load (AssetReader reader) { - Offset = reader.ReadUInt32(); + Offset = reader.ReadOffset(); Size = reader.ReadUInt32(); Path = reader.ReadString(); } diff --git a/ArcFormats/Unity/ResourcesAssets.cs b/ArcFormats/Unity/ResourcesAssets.cs index 612b49f5..83188d06 100644 --- a/ArcFormats/Unity/ResourcesAssets.cs +++ b/ArcFormats/Unity/ResourcesAssets.cs @@ -61,7 +61,7 @@ namespace GameRes.Formats.Unity case 28: // Texture2D { var tex = new Texture2D(); - tex.Load (input, asset.Tree.Version); + tex.Load (input, asset.Tree); if (0 == tex.m_DataLength) { var stream_data = new StreamingInfo(); diff --git a/ArcFormats/Unity/Texture2D.cs b/ArcFormats/Unity/Texture2D.cs index 2dd710f4..7382a1cf 100644 --- a/ArcFormats/Unity/Texture2D.cs +++ b/ArcFormats/Unity/Texture2D.cs @@ -97,12 +97,17 @@ namespace GameRes.Formats.Unity m_DataLength = reader.ReadInt32(); } - public void Load (AssetReader reader, string version) + public void Load (AssetReader reader, UnityTypeData type) { - if (version != "2017.3.1f1") + if ("2021.1.3f1" == type.Version) // type.Hashes[28] == [0D 08 41 4C FD 5B DB 0D 22 79 20 11 BD A9 AB 26] + { + Load2021 (reader); + return; + } + if (type.Version != "2017.3.1f1") { Load (reader); - if (0 == m_DataLength && version.StartsWith ("2017.")) // "2017.2.0f3" || "2017.1.1p1" + if (0 == m_DataLength && type.Version.StartsWith ("2017.")) // "2017.2.0f3" || "2017.1.1p1" reader.ReadInt64(); return; } @@ -130,6 +135,35 @@ namespace GameRes.Formats.Unity m_DataLength = reader.ReadInt32(); } + public void Load2021 (AssetReader reader) + { + m_Name = reader.ReadString(); + reader.Align(); + reader.ReadInt32(); // m_ForcedFallbackFormat + reader.ReadInt32(); // m_DownscaleFallback + m_Width = reader.ReadInt32(); + m_Height = reader.ReadInt32(); + m_CompleteImageSize = reader.ReadInt32(); + reader.ReadInt32(); // m_MipsStripped; + m_TextureFormat = (TextureFormat)reader.ReadInt32(); + m_MipCount = reader.ReadInt32(); + m_IsReadable = reader.ReadBool(); + reader.Align(); + reader.ReadInt32(); // m_StreamingMipmapsPriority + m_ImageCount = reader.ReadInt32(); + m_TextureDimension = reader.ReadInt32(); + m_FilterMode = reader.ReadInt32(); + m_Aniso = reader.ReadInt32(); + m_MipBias = reader.ReadFloat(); + m_WrapMode = reader.ReadInt32(); // m_WrapU + reader.ReadInt32(); // m_WrapV + reader.ReadInt32(); // m_WrapW + reader.ReadInt32(); // m_LightmapFormat + m_ColorSpace = reader.ReadInt32(); + reader.ReadInt32(); + m_DataLength = reader.ReadInt32(); + } + public void LoadData (AssetReader reader) { m_Data = reader.ReadBytes (m_DataLength); @@ -243,6 +277,12 @@ namespace GameRes.Formats.Unity pixels = ConvertArgb16 (m_texture.m_Data); break; + case TextureFormat.BC7: + { + var decoder = new Bc7Decoder (m_texture.m_Data, Info); + pixels = decoder.Unpack(); + break; + } default: throw new NotImplementedException (string.Format ("Not supported Unity Texture2D format '{0}'.", m_texture.m_TextureFormat)); }