Hmm, maybe you've seen it in my MaxScript, which also had the ability to parse any and all Unity versions
Here's the complete structure of assetfiles (mainData, level#, .assets, .sharedAssets, CustomAssetBundle, BuildPlayer)
Note that unity 5 still needs further testing
As of yesterday, Unity Studio is also on GitHub:
https://github.com/RaduMC/UnityStudio
Code: Select all
public AssetsFile(string fileName)
{
EndianStream fileStream = new EndianStream(File.OpenRead(fileName), EndianType.BigEndian);
int tableSize = fileStream.ReadInt32();
int dataEnd = fileStream.ReadInt32();
int fileGen = fileStream.ReadInt32();
int dataOffset = fileStream.ReadInt32();
bool baseDefinitions = false;
switch (fileGen)
{
case 6:
{
fileStream.Position = (dataEnd - tableSize);
fileStream.Position += 1;
break;
}
case 7://Unity 3 beta
{
fileStream.Position = (dataEnd - tableSize);
fileStream.Position += 1;
m_Version = fileStream.ReadStringToNull();
break;
}
case 8:
{
fileStream.Position = (dataEnd - tableSize);
fileStream.Position += 1;
m_Version = fileStream.ReadStringToNull();
platform = fileStream.ReadInt32();
break;
}
case 9:
{
fileStream.Position += 4;//unknown zero
m_Version = fileStream.ReadStringToNull();
platform = fileStream.ReadInt32();
break;
}
case 14:
case 15://not fully tested!
{
fileStream.Position += 4;//unknown zero
m_Version = fileStream.ReadStringToNull();
platform = fileStream.ReadInt32();
baseDefinitions = fileStream.ReadBoolean();
break;
}
default:
{
//MessageBox.Show("Unsupported Unity version!", "Unity Studio Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
}
if (platform > 255 || platform < 0)
{
byte[] b32 = BitConverter.GetBytes(platform);
Array.Reverse(b32);
platform = BitConverter.ToInt32(b32, 0);
fileStream.endian = EndianType.LittleEndian;
}
/*Platform list:
-2: unitypackage
4: OSX
5: PC
6: Web
7: Web_streamed
9: iOS
10: PS3(big)
11: Xbox360(big)
13: Android
16: Google_NaCl
21: WP8
25: Linux
*/
int baseCount = fileStream.ReadInt32();
for (int i = 0; i < baseCount; i++)
{
if (fileGen < 14)
{
int baseType = fileStream.ReadInt32();
readBase();
}
else { readBase5(baseDefinitions); }
}
if (fileGen >= 7 && fileGen < 14) { fileStream.Position += 4; }//unknown zero
int assetCount = fileStream.ReadInt32();
for (int i = 0; i < assetCount; i++)
{
if (fileGen >= 14) { fileStream.AlignStream(4); }
AssetPreloadData asset = new AssetPreloadData();
if (fileGen < 14) { asset.m_PathID = fileStream.ReadInt32(); }
else { asset.m_PathID = fileStream.ReadInt64(); }
asset.Offset = fileStream.ReadInt32();
asset.Offset += dataOffset;
asset.Size = fileStream.ReadInt32();
asset.Type1 = fileStream.ReadInt32();
asset.Type2 = fileStream.ReadUInt16();
fileStream.Position += 2;
if (fileGen >= 15) { byte unknownByte = a_Stream.ReadByte(); }
preloadTable.Add(asset.m_PathID, asset);
}
if (fileGen >= 14)
{
//this looks like a list of assets that need to be preloaded in memory before anytihng else
int someCount = a_Stream.ReadInt32();
for (int i = 0; i < someCount; i++)
{
int num1 = a_Stream.ReadInt32();
a_Stream.AlignStream(4);
long m_PathID = a_Stream.ReadInt64();
}
}
int sharedFileCount = fileStream.ReadInt32();
for (int i = 0; i < sharedFileCount; i++)
{
string aName = fileStream.ReadStringToNull();
fileStream.Position += 20;
string sharedFileName = fileStream.ReadStringToNull(); //relative path
}
}
private void readBase() //recursive
{
string baseFormat = fileStream.ReadStringToNull();
string baseName = fileStream.ReadStringToNull();
fileStream.Position += 20;
int childrenCount = fileStream.ReadInt32();
//Debug.WriteLine(baseFormat + " " + baseName + " " + childrenCount);
for (int i = 0; i < childrenCount; i++) { readBase(); }
}
private void readBase5(bool baseDefinitions)
{
int baseType = fileStream.ReadInt32();
if (baseType < 0) { fileStream.Position += 16; }
fileStream.Position += 16;
if (baseDefinitions)
{
int varCount = fileStream.ReadInt32();
int stringSize = fileStream.ReadInt32();
fileStream.Position += varCount * 24;
string varStrings = Encoding.UTF8.GetString(fileStream.ReadBytes(stringSize));
//can skip this
fileStream.Position -= varCount * 24 + stringSize;
for (int i = 0; i < varCount; i++)
{
ushort num0 = fileStream.ReadUInt16();
byte level = fileStream.ReadByte();
bool isArray = fileStream.ReadBoolean();
ushort varTypeIndex = fileStream.ReadUInt16();
ushort test = fileStream.ReadUInt16();
string varTypeStr;
if (test == 0) //varType is an offset in the string block
{ varTypeStr = varStrings.Substring(varTypeIndex, varStrings.IndexOf('\0', varTypeIndex) - varTypeIndex); }//substringToNull
else //varType is an index in an internal strig array
{ varTypeStr = baseStrings[varTypeIndex] != null ? baseStrings[varTypeIndex] : varTypeIndex.ToString(); }
ushort varNameIndex = fileStream.ReadUInt16();
test = fileStream.ReadUInt16();
string varNameStr;
if (test == 0) { varNameStr = varStrings.Substring(varNameIndex, varStrings.IndexOf('\0', varNameIndex) - varNameIndex); }
else { varNameStr = baseStrings[varNameIndex] != null ? baseStrings[varNameIndex] : varNameIndex.ToString(); }
int size = fileStream.ReadInt32();
int index = fileStream.ReadInt32();
int num1 = fileStream.ReadInt32();
for (int t = 0; t < level; t++) { Debug.Write("\t"); }
//Debug.WriteLine(varTypeStr + " " + varNameStr + " " + size);
}
fileStream.Position += stringSize;
}
}
Please post any requests or issues with my tools in the appropriate topics.
I'm sorry if I don't reply or if I ignore PMs. My time is very limited.