Improve support for some older Unity versions (<3.0)

- Fix export of AudioClip assets from unity v2.5 and earlier
- Fix parsing of PlayerSettings assets from unity v2.6 and earlier
- Fix parsing of AnimationClip assets from unity v2.5 and earlier
This commit is contained in:
VaDiM 2024-10-04 01:29:38 +03:00
parent c93d27d9a4
commit 58ee2b8f1e
7 changed files with 180 additions and 90 deletions

View File

@ -984,14 +984,18 @@ namespace AssetStudio
public AnimationEvent(ObjectReader reader) public AnimationEvent(ObjectReader reader)
{ {
var version = reader.version;
time = reader.ReadSingle(); time = reader.ReadSingle();
functionName = reader.ReadAlignedString(); functionName = reader.ReadAlignedString();
data = reader.ReadAlignedString(); data = reader.ReadAlignedString();
objectReferenceParameter = new PPtr<Object>(reader); if (version >= (2, 6)) //2.6 and up
floatParameter = reader.ReadSingle();
if (reader.version >= 3) //3 and up
{ {
intParameter = reader.ReadInt32(); objectReferenceParameter = new PPtr<Object>(reader);
floatParameter = reader.ReadSingle();
if (version >= 3) //3 and up
{
intParameter = reader.ReadInt32();
}
} }
messageOptions = reader.ReadInt32(); messageOptions = reader.ReadInt32();
} }
@ -1067,7 +1071,10 @@ namespace AssetStudio
{ {
m_Legacy = true; m_Legacy = true;
} }
m_Compressed = reader.ReadBoolean(); if (version >= (2, 6)) //2.6 and up
{
m_Compressed = reader.ReadBoolean();
}
if (version >= (4, 3))//4.3 and up if (version >= (4, 3))//4.3 and up
{ {
m_UseHighQualityCurve = reader.ReadBoolean(); m_UseHighQualityCurve = reader.ReadBoolean();
@ -1080,11 +1087,14 @@ namespace AssetStudio
m_RotationCurves[i] = new QuaternionCurve(reader); m_RotationCurves[i] = new QuaternionCurve(reader);
} }
int numCRCurves = reader.ReadInt32(); if (version >= (2, 6)) //2.6 and up
m_CompressedRotationCurves = new CompressedAnimationCurve[numCRCurves];
for (int i = 0; i < numCRCurves; i++)
{ {
m_CompressedRotationCurves[i] = new CompressedAnimationCurve(reader); int numCRCurves = reader.ReadInt32();
m_CompressedRotationCurves = new CompressedAnimationCurve[numCRCurves];
for (int i = 0; i < numCRCurves; i++)
{
m_CompressedRotationCurves[i] = new CompressedAnimationCurve(reader);
}
} }
if (version >= (5, 3))//5.3 and up if (version >= (5, 3))//5.3 and up
@ -1129,7 +1139,10 @@ namespace AssetStudio
} }
m_SampleRate = reader.ReadSingle(); m_SampleRate = reader.ReadSingle();
m_WrapMode = reader.ReadInt32(); if (version >= (2, 6)) //2.6 and up
{
m_WrapMode = reader.ReadInt32();
}
if (version >= (3, 4)) //3.4 and up if (version >= (3, 4)) //3.4 and up
{ {
m_Bounds = new AABB(reader); m_Bounds = new AABB(reader);

View File

@ -1,10 +1,4 @@
using System; namespace AssetStudio
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace AssetStudio
{ {
public sealed class AudioClip : NamedObject public sealed class AudioClip : NamedObject
{ {
@ -36,11 +30,19 @@ namespace AssetStudio
if (version < 5) if (version < 5)
{ {
m_Format = reader.ReadInt32(); m_Format = reader.ReadInt32();
m_Type = (FMODSoundType)reader.ReadInt32(); if (version >= (2, 6)) //2.6 to 5
m_3D = reader.ReadBoolean(); {
m_UseHardware = reader.ReadBoolean(); m_Type = (FMODSoundType)reader.ReadInt32();
reader.AlignStream(); m_3D = reader.ReadBoolean();
m_UseHardware = reader.ReadBoolean();
reader.AlignStream();
}
else
{
m_Length = reader.ReadSingle();
m_Frequency = reader.ReadInt32();
m_Channels = m_Format != 0x05 ? m_Format >> 1 : 0;
}
if (version >= (3, 2)) //3.2.0 to 5 if (version >= (3, 2)) //3.2.0 to 5
{ {
int m_Stream = reader.ReadInt32(); int m_Stream = reader.ReadInt32();

View File

@ -1,9 +1,4 @@
using System; namespace AssetStudio
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace AssetStudio
{ {
public sealed class PlayerSettings : Object public sealed class PlayerSettings : Object
{ {
@ -12,37 +7,40 @@ namespace AssetStudio
public PlayerSettings(ObjectReader reader) : base(reader) public PlayerSettings(ObjectReader reader) : base(reader)
{ {
if (version >= (5, 4)) //5.4.0 and up if (version >= (3, 0))
{ {
var productGUID = reader.ReadBytes(16); if (version >= (5, 4)) //5.4.0 and up
}
var AndroidProfiler = reader.ReadBoolean();
//bool AndroidFilterTouchesWhenObscured 2017.2 and up
//bool AndroidEnableSustainedPerformanceMode 2018 and up
reader.AlignStream();
int defaultScreenOrientation = reader.ReadInt32();
int targetDevice = reader.ReadInt32();
if (version < (5, 3)) //5.3 down
{
if (version < 5) //5.0 down
{ {
int targetPlatform = reader.ReadInt32(); //4.0 and up targetGlesGraphics var productGUID = reader.ReadBytes(16);
if (version >= (4, 6)) //4.6 and up
{
var targetIOSGraphics = reader.ReadInt32();
}
} }
int targetResolution = reader.ReadInt32();
} var AndroidProfiler = reader.ReadBoolean();
else //bool AndroidFilterTouchesWhenObscured 2017.2 and up
{ //bool AndroidEnableSustainedPerformanceMode 2018 and up
var useOnDemandResources = reader.ReadBoolean();
reader.AlignStream(); reader.AlignStream();
} int defaultScreenOrientation = reader.ReadInt32();
if (version >= (3, 5)) //3.5 and up int targetDevice = reader.ReadInt32();
{ if (version < (5, 3)) //5.3 down
var accelerometerFrequency = reader.ReadInt32(); {
if (version < 5) //5.0 down
{
int targetPlatform = reader.ReadInt32(); //4.0 and up targetGlesGraphics
if (version >= (4, 6)) //4.6 and up
{
var targetIOSGraphics = reader.ReadInt32();
}
}
int targetResolution = reader.ReadInt32();
}
else
{
var useOnDemandResources = reader.ReadBoolean();
reader.AlignStream();
}
if (version >= (3, 5)) //3.5 and up
{
var accelerometerFrequency = reader.ReadInt32();
}
} }
companyName = reader.ReadAlignedString(); companyName = reader.ReadAlignedString();
productName = reader.ReadAlignedString(); productName = reader.ReadAlignedString();

View File

@ -84,13 +84,13 @@ namespace AssetStudio
} }
} }
public void GetData(byte[] buff) public void GetData(byte[] buff, int startIndex = 0)
{ {
var binaryReader = GetReader(); var binaryReader = GetReader();
lock (binaryReader) lock (binaryReader)
{ {
binaryReader.BaseStream.Position = Offset; binaryReader.BaseStream.Position = Offset;
binaryReader.Read(buff, 0, (int) size); binaryReader.Read(buff, startIndex, (int) size);
} }
} }

View File

@ -109,7 +109,7 @@ namespace AssetStudioCLI
return false; return false;
} }
var converter = new AudioClipConverter(m_AudioClip); var converter = new AudioClipConverter(m_AudioClip);
if (CLIOptions.o_audioFormat.Value != AudioFormat.None && converter.IsSupport) if (CLIOptions.o_audioFormat.Value != AudioFormat.None && (converter.IsSupport || converter.IsLegacy))
{ {
if (!TryExportFile(exportPath, item, ".wav", out exportFullPath)) if (!TryExportFile(exportPath, item, ".wav", out exportFullPath))
return false; return false;
@ -118,14 +118,28 @@ namespace AssetStudioCLI
{ {
var sb = new StringBuilder(); var sb = new StringBuilder();
sb.AppendLine($"Converting {item.TypeString} \"{m_AudioClip.m_Name}\" to wav.."); sb.AppendLine($"Converting {item.TypeString} \"{m_AudioClip.m_Name}\" to wav..");
sb.AppendLine(m_AudioClip.version < 5 ? $"AudioClip type: {m_AudioClip.m_Type}" : $"AudioClip compression format: {m_AudioClip.m_CompressionFormat}"); if (m_AudioClip.version >= (2, 6))
sb.AppendLine($"AudioClip channel count: {m_AudioClip.m_Channels}"); {
sb.AppendLine($"AudioClip sample rate: {m_AudioClip.m_Frequency}"); sb.AppendLine(m_AudioClip.version < 5
sb.AppendLine($"AudioClip bit depth: {m_AudioClip.m_BitsPerSample}"); ? $"AudioClip type: {m_AudioClip.m_Type}"
: $"AudioClip compression format: {m_AudioClip.m_CompressionFormat}");
sb.AppendLine($"AudioClip channel count: {m_AudioClip.m_Channels}");
sb.AppendLine($"AudioClip sample rate: {m_AudioClip.m_Frequency}");
sb.AppendLine($"AudioClip bit depth: {m_AudioClip.m_BitsPerSample}");
}
else
{
sb.AppendLine($"Is raw AudioClip: {m_AudioClip.m_Format != 0x05}");
sb.AppendLine($"AudioClip channel count: {m_AudioClip.m_Channels}");
sb.AppendLine($"AudioClip sample rate: {m_AudioClip.m_Frequency}");
}
debugLog += sb.ToString(); debugLog += sb.ToString();
} }
var buffer = converter.ConvertToWav(m_AudioData, out var debugLogConverter); var debugLogConverter = "";
var buffer = converter.IsLegacy
? converter.RawAudioClipToWav(out debugLogConverter)
: converter.ConvertToWav(m_AudioData, out debugLogConverter);
debugLog += debugLogConverter; debugLog += debugLogConverter;
if (buffer == null) if (buffer == null)
{ {
@ -143,13 +157,26 @@ namespace AssetStudioCLI
{ {
var sb = new StringBuilder(); var sb = new StringBuilder();
sb.AppendLine($"Exporting non-fmod {item.TypeString} \"{m_AudioClip.m_Name}\".."); sb.AppendLine($"Exporting non-fmod {item.TypeString} \"{m_AudioClip.m_Name}\"..");
sb.AppendLine(m_AudioClip.version < 5 ? $"AudioClip type: {m_AudioClip.m_Type}" : $"AudioClip compression format: {m_AudioClip.m_CompressionFormat}"); if (m_AudioClip.version >= (2, 6))
sb.AppendLine($"AudioClip channel count: {m_AudioClip.m_Channels}"); {
sb.AppendLine($"AudioClip sample rate: {m_AudioClip.m_Frequency}"); sb.AppendLine(m_AudioClip.version < 5
sb.AppendLine($"AudioClip bit depth: {m_AudioClip.m_BitsPerSample}"); ? $"AudioClip type: {m_AudioClip.m_Type}"
: $"AudioClip compression format: {m_AudioClip.m_CompressionFormat}");
sb.AppendLine($"AudioClip channel count: {m_AudioClip.m_Channels}");
sb.AppendLine($"AudioClip sample rate: {m_AudioClip.m_Frequency}");
sb.AppendLine($"AudioClip bit depth: {m_AudioClip.m_BitsPerSample}");
}
else
{
sb.AppendLine($"Is raw AudioClip: {m_AudioClip.m_Format != 0x05}");
sb.AppendLine($"AudioClip sample rate: {m_AudioClip.m_Frequency}");
}
debugLog += sb.ToString(); debugLog += sb.ToString();
} }
File.WriteAllBytes(exportFullPath, m_AudioData); using (var file = File.OpenWrite(exportFullPath))
{
file.Write(m_AudioData, 0, m_AudioClip.m_AudioData.Size);
}
} }
debugLog += $"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\""; debugLog += $"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\"";
return true; return true;

View File

@ -108,7 +108,7 @@ namespace AssetStudioGUI
return false; return false;
} }
var converter = new AudioClipConverter(m_AudioClip); var converter = new AudioClipConverter(m_AudioClip);
if (Properties.Settings.Default.convertAudio && converter.IsSupport) if (Properties.Settings.Default.convertAudio && (converter.IsSupport || converter.IsLegacy))
{ {
if (!TryExportFile(exportPath, item, ".wav", out exportFullPath)) if (!TryExportFile(exportPath, item, ".wav", out exportFullPath))
return false; return false;
@ -117,16 +117,29 @@ namespace AssetStudioGUI
{ {
var sb = new StringBuilder(); var sb = new StringBuilder();
sb.AppendLine($"Converting {item.TypeString} \"{m_AudioClip.m_Name}\" to wav.."); sb.AppendLine($"Converting {item.TypeString} \"{m_AudioClip.m_Name}\" to wav..");
sb.AppendLine(m_AudioClip.version < 5 if (m_AudioClip.version >= (2, 6))
? $"AudioClip type: {m_AudioClip.m_Type}" {
: $"AudioClip compression format: {m_AudioClip.m_CompressionFormat}"); sb.AppendLine(m_AudioClip.version < 5
sb.AppendLine($"AudioClip channel count: {m_AudioClip.m_Channels}"); ? $"AudioClip type: {m_AudioClip.m_Type}"
sb.AppendLine($"AudioClip sample rate: {m_AudioClip.m_Frequency}"); : $"AudioClip compression format: {m_AudioClip.m_CompressionFormat}");
sb.AppendLine($"AudioClip bit depth: {m_AudioClip.m_BitsPerSample}"); sb.AppendLine($"AudioClip channel count: {m_AudioClip.m_Channels}");
sb.AppendLine($"AudioClip sample rate: {m_AudioClip.m_Frequency}");
sb.AppendLine($"AudioClip bit depth: {m_AudioClip.m_BitsPerSample}");
}
else
{
sb.AppendLine($"Is raw AudioClip: {m_AudioClip.m_Format != 0x05}");
sb.AppendLine($"AudioClip channel count: {m_AudioClip.m_Channels}");
sb.AppendLine($"AudioClip sample rate: {m_AudioClip.m_Frequency}");
}
debugLog += sb.ToString(); debugLog += sb.ToString();
} }
var buffer = converter.ConvertToWav(m_AudioData, out var debugLogConverter); var debugLogConverter = "";
var buffer = converter.IsLegacy
? converter.RawAudioClipToWav(out debugLogConverter)
: converter.ConvertToWav(m_AudioData, out debugLogConverter);
debugLog += debugLogConverter; debugLog += debugLogConverter;
if (buffer == null) if (buffer == null)
{ {
@ -144,15 +157,27 @@ namespace AssetStudioGUI
{ {
var sb = new StringBuilder(); var sb = new StringBuilder();
sb.AppendLine($"Exporting non-fmod {item.TypeString} \"{m_AudioClip.m_Name}\".."); sb.AppendLine($"Exporting non-fmod {item.TypeString} \"{m_AudioClip.m_Name}\"..");
sb.AppendLine(m_AudioClip.version < 5 if (m_AudioClip.version >= (2, 6))
? $"AudioClip type: {m_AudioClip.m_Type}" {
: $"AudioClip compression format: {m_AudioClip.m_CompressionFormat}"); sb.AppendLine(m_AudioClip.version < 5
sb.AppendLine($"AudioClip channel count: {m_AudioClip.m_Channels}"); ? $"AudioClip type: {m_AudioClip.m_Type}"
sb.AppendLine($"AudioClip sample rate: {m_AudioClip.m_Frequency}"); : $"AudioClip compression format: {m_AudioClip.m_CompressionFormat}");
sb.AppendLine($"AudioClip bit depth: {m_AudioClip.m_BitsPerSample}"); sb.AppendLine($"AudioClip channel count: {m_AudioClip.m_Channels}");
sb.AppendLine($"AudioClip sample rate: {m_AudioClip.m_Frequency}");
sb.AppendLine($"AudioClip bit depth: {m_AudioClip.m_BitsPerSample}");
}
else
{
sb.AppendLine($"Is raw AudioClip: {m_AudioClip.m_Format != 0x05}");
sb.AppendLine($"AudioClip sample rate: {m_AudioClip.m_Frequency}");
}
debugLog += sb.ToString(); debugLog += sb.ToString();
} }
File.WriteAllBytes(exportFullPath, m_AudioData); using (var file = File.OpenWrite(exportFullPath))
{
file.Write(m_AudioData, 0, m_AudioClip.m_AudioData.Size);
}
} }
debugLog += $"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\""; debugLog += $"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\"";
return true; return true;

View File

@ -8,6 +8,7 @@ namespace AssetStudio
public class AudioClipConverter public class AudioClipConverter
{ {
public bool IsSupport => m_AudioClip.IsConvertSupport(); public bool IsSupport => m_AudioClip.IsConvertSupport();
public bool IsLegacy => m_AudioClip.IsLegacyConvertSupport();
private AudioClip m_AudioClip; private AudioClip m_AudioClip;
private static FMOD.System system; private static FMOD.System system;
@ -84,8 +85,32 @@ namespace AssetStudio
return null; return null;
var buffer = new byte[len1 + 44]; var buffer = new byte[len1 + 44];
//添加wav头 //添加wav头
WriteWavHeader(buffer, len1, sampleRate, channels, bits);
Marshal.Copy(ptr1, buffer, 44, (int)len1);
result = sound.unlock(ptr1, ptr2, len1, len2);
if (result != RESULT.OK)
return null;
return buffer;
}
public byte[] RawAudioClipToWav(out string debugLog)
{
var audioSize = m_AudioClip.m_Size;
var channels = m_AudioClip.m_Channels;
var sampleRate = m_AudioClip.m_Frequency;
var bits = 16;
debugLog = "[Legacy wav converter] Generating wav header..\n";
var buffer = new byte[audioSize + 44];
m_AudioClip.m_AudioData.GetData(buffer, 44);
WriteWavHeader(buffer, audioSize, sampleRate, channels, bits);
return buffer;
}
private static void WriteWavHeader(byte[] buffer, long size, int sampleRate, int channels, int bits)
{
Encoding.ASCII.GetBytes("RIFF").CopyTo(buffer, 0); Encoding.ASCII.GetBytes("RIFF").CopyTo(buffer, 0);
BitConverter.GetBytes(len1 + 36).CopyTo(buffer, 4); BitConverter.GetBytes(size + 36).CopyTo(buffer, 4);
Encoding.ASCII.GetBytes("WAVEfmt ").CopyTo(buffer, 8); Encoding.ASCII.GetBytes("WAVEfmt ").CopyTo(buffer, 8);
BitConverter.GetBytes(16).CopyTo(buffer, 16); BitConverter.GetBytes(16).CopyTo(buffer, 16);
BitConverter.GetBytes((short)1).CopyTo(buffer, 20); BitConverter.GetBytes((short)1).CopyTo(buffer, 20);
@ -95,12 +120,7 @@ namespace AssetStudio
BitConverter.GetBytes((short)(channels * bits / 8)).CopyTo(buffer, 32); BitConverter.GetBytes((short)(channels * bits / 8)).CopyTo(buffer, 32);
BitConverter.GetBytes((short)bits).CopyTo(buffer, 34); BitConverter.GetBytes((short)bits).CopyTo(buffer, 34);
Encoding.ASCII.GetBytes("data").CopyTo(buffer, 36); Encoding.ASCII.GetBytes("data").CopyTo(buffer, 36);
BitConverter.GetBytes(len1).CopyTo(buffer, 40); BitConverter.GetBytes(size).CopyTo(buffer, 40);
Marshal.Copy(ptr1, buffer, 44, (int)len1);
result = sound.unlock(ptr1, ptr2, len1, len2);
if (result != RESULT.OK)
return null;
return buffer;
} }
public string GetExtensionName() public string GetExtensionName()
@ -201,5 +221,10 @@ namespace AssetStudio
} }
} }
} }
public static bool IsLegacyConvertSupport(this AudioClip m_AudioClip)
{
return m_AudioClip.version < (2, 6) && m_AudioClip.m_Format != 0x05;
}
} }
} }