public GameObject(AssetPreloadData preloadData) { if (preloadData == null) { AssetsFile sourceFile = preloadData.sourceFile; EndianStream stream = preloadData.sourceFile.a_Stream; stream.Position = preloadData.Offset; this.uniqueID = preloadData.uniqueID; if (sourceFile.platform == -2) { uint num3 = stream.ReadUInt32(); PPtr ptr = sourceFile.ReadPPtr(); PPtr ptr2 = sourceFile.ReadPPtr(); } int num = stream.ReadInt32(); for (int i = 0; i < num; i++) { switch (stream.ReadInt32()) { case 4: this.m_Transform = sourceFile.ReadPPtr(); break; case 0x17: this.m_Renderer = sourceFile.ReadPPtr(); break; case 0x21: this.m_MeshFilter = sourceFile.ReadPPtr(); break; case 0x89: this.m_SkinnedMeshRenderer = sourceFile.ReadPPtr(); break; default: { PPtr ptr3 = sourceFile.ReadPPtr(); break; } } } this.m_Layer = stream.ReadInt32(); int length = stream.ReadInt32(); this.m_Name = stream.ReadAlignedString(length); if (this.m_Name == "") { this.m_Name = "GameObject #" + this.uniqueID; } this.m_Tag = stream.ReadUInt16(); this.m_IsActive = stream.ReadBoolean(); this.Text = this.m_Name; this.Name = this.uniqueID; } }
public TextAsset(AssetPreloadData preloadData, bool readSwitch) { AssetsFile sourceFile = preloadData.sourceFile; EndianStream stream = preloadData.sourceFile.a_Stream; stream.Position = preloadData.Offset; preloadData.extension = ".txt"; if (sourceFile.platform == -2) { uint num2 = stream.ReadUInt32(); PPtr ptr = sourceFile.ReadPPtr(); PPtr ptr2 = sourceFile.ReadPPtr(); } this.m_Name = stream.ReadAlignedString(stream.ReadInt32()); if (this.m_Name != "") { preloadData.Name = this.m_Name; } else { preloadData.Name = preloadData.TypeString + " #" + preloadData.uniqueID; } int count = stream.ReadInt32(); if (readSwitch) { this.m_Script = new byte[count]; stream.Read(this.m_Script, 0, count); if (this.m_Script[0] == 0x5d) { this.m_Script = SevenZipHelper.Decompress(this.m_Script); } if ((this.m_Script[0] == 60) || ((((this.m_Script[0] == 0xef) && (this.m_Script[1] == 0xbb)) && (this.m_Script[2] == 0xbf)) && (this.m_Script[3] == 60))) { preloadData.extension = ".xml"; } } else { if (stream.ReadByte() == 0x5d) { stream.Position += 4L; preloadData.exportSize = stream.ReadInt32(); stream.Position -= 8L; } else { preloadData.exportSize = count; } stream.Position += count - 1; } stream.AlignStream(4); this.m_PathName = stream.ReadAlignedString(stream.ReadInt32()); }
public BundleFile(string fileName) { if (Path.GetExtension(fileName) == ".lz4") { byte[] filebuffer; using (BinaryReader lz4Stream = new BinaryReader(File.OpenRead(fileName))) { int version = lz4Stream.ReadInt32(); int uncompressedSize = lz4Stream.ReadInt32(); int compressedSize = lz4Stream.ReadInt32(); int something = lz4Stream.ReadInt32(); //1 byte[] lz4buffer = new byte[compressedSize]; lz4Stream.Read(lz4buffer, 0, compressedSize); using (var inputStream = new MemoryStream(lz4buffer)) { var decoder = new Lz4DecoderStream(inputStream); filebuffer = new byte[uncompressedSize]; //is this ok? for (;;) { int nRead = decoder.Read(filebuffer, 0, uncompressedSize); if (nRead == 0) { break; } } } } using (var b_Stream = new EndianStream(new MemoryStream(filebuffer), EndianType.BigEndian)) { readBundle(b_Stream); } } else { using (var b_Stream = new EndianStream(File.OpenRead(fileName), EndianType.BigEndian)) { readBundle(b_Stream); } } }
public static PPtr ReadPPtr(this AssetsFile sourceFile) { PPtr ptr = new PPtr(); EndianStream stream = sourceFile.a_Stream; int num = stream.ReadInt32(); if ((num >= 0) && (num < sourceFile.sharedAssetsList.Count)) { ptr.m_FileID = sourceFile.sharedAssetsList[num].Index; } if (sourceFile.fileGen < 14) { ptr.m_PathID = stream.ReadInt32(); return(ptr); } ptr.m_PathID = stream.ReadInt64(); return(ptr); }
public BundleFile(string fileName) { if (Path.GetExtension(fileName) == ".lz4") { byte[] filebuffer; using (BinaryReader lz4Stream = new BinaryReader(File.OpenRead(fileName))) { int version = lz4Stream.ReadInt32(); int uncompressedSize = lz4Stream.ReadInt32(); int compressedSize = lz4Stream.ReadInt32(); int something = lz4Stream.ReadInt32(); //1 byte[] lz4buffer = new byte[compressedSize]; lz4Stream.Read(lz4buffer, 0, compressedSize); using (var inputStream = new MemoryStream(lz4buffer)) { var decoder = new Lz4DecoderStream(inputStream); filebuffer = new byte[uncompressedSize]; //is this ok? for (;;) { int nRead = decoder.Read(filebuffer, 0, uncompressedSize); if (nRead == 0) break; } } } using (var b_Stream = new EndianStream(new MemoryStream(filebuffer), EndianType.BigEndian)) { readBundle(b_Stream); } } else { using (var b_Stream = new EndianStream(File.OpenRead(fileName), EndianType.BigEndian)) { readBundle(b_Stream); } } }
private void getFiles(EndianStream f_Stream, int offset) { int fileCount = f_Stream.ReadInt32(); for (int i = 0; i < fileCount; i++) { MemoryAssetsFile memFile = new MemoryAssetsFile(); memFile.fileName = f_Stream.ReadStringToNull(); int fileOffset = f_Stream.ReadInt32(); fileOffset += offset; int fileSize = f_Stream.ReadInt32(); long nextFile = f_Stream.Position; f_Stream.Position = fileOffset; byte[] buffer = new byte[fileSize]; f_Stream.Read(buffer, 0, fileSize); memFile.memStream = new MemoryStream(buffer); MemoryAssetsFileList.Add(memFile); f_Stream.Position = nextFile; } }
public AssetsFile(string fileName, EndianStream fileStream) { //if (memFile != null) { Stream = new EndianStream(memFile, endianType); } //else { Stream = new EndianStream(File.OpenRead(fileName), endianType); } a_Stream = fileStream; filePath = fileName; int tableSize = a_Stream.ReadInt32(); int dataEnd = a_Stream.ReadInt32(); fileGen = a_Stream.ReadInt32(); int dataOffset = a_Stream.ReadInt32(); sharedAssetsList[0].fileName = Path.GetFileName(fileName); //reference itself because sharedFileIDs start from 1 switch (fileGen) { case 6: //2.5.0 - 2.6.1 { a_Stream.Position = (dataEnd - tableSize); a_Stream.Position += 1; break; } case 7: //3.0.0 beta { a_Stream.Position = (dataEnd - tableSize); a_Stream.Position += 1; m_Version = a_Stream.ReadStringToNull(); break; } case 8: //3.0.0 - 3.4.2 { a_Stream.Position = (dataEnd - tableSize); a_Stream.Position += 1; m_Version = a_Stream.ReadStringToNull(); platform = a_Stream.ReadInt32(); break; } case 9: //3.5.0 - 4.6.x { a_Stream.Position += 4; //azero m_Version = a_Stream.ReadStringToNull(); platform = a_Stream.ReadInt32(); break; } case 14: //5.0.0 beta and final case 15: //5.0.1 and up case 16: //5.5.0 and up case 17: //5.5.0 and up { a_Stream.Position += 4; //azero m_Version = a_Stream.ReadStringToNull(); platform = a_Stream.ReadInt32(); baseDefinitions = a_Stream.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); //endianType = EndianType.LittleEndian; a_Stream.endian = EndianType.LittleEndian; } switch (platform) { case -2: platformStr = "Unity Package"; break; case 4: platformStr = "OSX"; break; case 5: platformStr = "PC"; break; case 6: platformStr = "Web"; break; case 7: platformStr = "Web streamed"; break; case 9: platformStr = "iOS"; break; case 10: platformStr = "PS3"; break; case 11: platformStr = "Xbox 360"; break; case 13: platformStr = "Android"; break; case 16: platformStr = "Google NaCl"; break; case 21: platformStr = "WP8"; break; case 25: platformStr = "Linux"; break; } int baseCount = a_Stream.ReadInt32(); for (int i = 0; i < baseCount; i++) { if (fileGen < 14) { int classID = a_Stream.ReadInt32(); string baseType = a_Stream.ReadStringToNull(); string baseName = a_Stream.ReadStringToNull(); a_Stream.Position += 20; int memberCount = a_Stream.ReadInt32(); StringBuilder cb = new StringBuilder(); for (int m = 0; m < memberCount; m++) { readBase(cb, 1); } var aClass = new ClassStrStruct() { ID = classID, Text = (baseType + " " + baseName), members = cb.ToString() }; aClass.subItems.Add(classID.ToString()); ClassStructures.Add(classID, aClass); } else { readBase5(i); } } if (fileGen >= 7 && fileGen < 14) { a_Stream.Position += 4; } //azero int assetCount = a_Stream.ReadInt32(); #region asset preload table string assetIDfmt = "D" + assetCount.ToString().Length.ToString(); //format for unique ID for (int i = 0; i < assetCount; i++) { //each table entry is aligned individually, not the whole table if (fileGen >= 14) { a_Stream.AlignStream(4); } AssetPreloadData asset = new AssetPreloadData(); if (fileGen < 14) { asset.m_PathID = a_Stream.ReadInt32(); } else { asset.m_PathID = a_Stream.ReadInt64(); } if (fileGen > 15) { asset.Offset = a_Stream.ReadInt32(); int tmp = asset.Offset; asset.Offset += dataOffset; asset.Size = a_Stream.ReadInt32(); int classIndex = a_Stream.ReadUInt16(); if (classIDLookup.ContainsKey(classIndex)) { asset.Type2 = classIDLookup[classIndex]; } } else { asset.Offset = a_Stream.ReadInt32(); asset.Offset += dataOffset; asset.Size = a_Stream.ReadInt32(); asset.Type1 = a_Stream.ReadInt32(); asset.Type2 = a_Stream.ReadUInt16(); a_Stream.Position += 2; if (fileGen >= 15) { a_Stream.ReadByte(); //this is a single byte, not an int32 //the next entry is aligned after this //but not the last! } } if (UnityClassID.Names[asset.Type2] != null) { asset.TypeString = UnityClassID.Names[asset.Type2]; } asset.uniqueID = i.ToString(assetIDfmt); asset.exportSize = asset.Size; asset.sourceFile = this; preloadTable.Add(asset.m_PathID, asset); #region read BuildSettings to get version for unity 2.x files if (asset.Type2 == 141 && fileGen == 6) { long nextAsset = a_Stream.Position; BuildSettings BSettings = new BuildSettings(asset); m_Version = BSettings.m_Version; a_Stream.Position = nextAsset; } #endregion } #endregion buildType = m_Version.Split(new string[] { ".", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" }, StringSplitOptions.RemoveEmptyEntries); string[] strver = (m_Version.Split(new string[] { ".", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "\n" }, StringSplitOptions.RemoveEmptyEntries)); version = Array.ConvertAll <string, int>(strver, int.Parse); if (fileGen > 15) { a_Stream.Position += 2; } 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++) { a_Stream.ReadInt32(); a_Stream.AlignStream(4); a_Stream.ReadInt64(); } } int sharedFileCount = a_Stream.ReadInt32(); for (int i = 0; i < sharedFileCount; i++) { UnityShared shared = new UnityShared(); shared.aName = a_Stream.ReadStringToNull(); a_Stream.Position += 20; string sharedFileName = a_Stream.ReadStringToNull(); //relative path shared.fileName = sharedFileName.Replace("/", "\\"); sharedAssetsList.Add(shared); } }
public BundleFile(string fileName) { if (Path.GetExtension(fileName) == ".lz4") { byte[] filebuffer; using (BinaryReader lz4Stream = new BinaryReader(File.OpenRead(fileName))) { int version = lz4Stream.ReadInt32(); int uncompressedSize = lz4Stream.ReadInt32(); int compressedSize = lz4Stream.ReadInt32(); int something = lz4Stream.ReadInt32(); //1 byte[] lz4buffer = new byte[compressedSize]; lz4Stream.Read(lz4buffer, 0, compressedSize); using (var inputStream = new MemoryStream(lz4buffer)) { var decoder = new Lz4DecoderStream(inputStream); filebuffer = new byte[uncompressedSize]; //is this ok? for (;;) { int nRead = decoder.Read(filebuffer, 0, uncompressedSize); if (nRead == 0) break; } } } Stream = new EndianStream(new MemoryStream(filebuffer), EndianType.BigEndian); } else { Stream = new EndianStream(File.OpenRead(fileName), EndianType.BigEndian); } long magicHeader = Stream.ReadInt64(); if (magicHeader == -361700864190383366 || magicHeader == 6155973689634940258 || magicHeader == 6155973689634611575) { int dummy = Stream.ReadInt32(); ver1 = Stream.ReadByte(); ver2 = Stream.ReadStringToNull(); ver3 = Stream.ReadStringToNull(); int lzmaSize = 0; int fileSize = Stream.ReadInt32(); short dummy2 = Stream.ReadInt16(); int offset = Stream.ReadInt16(); int dummy3 = Stream.ReadInt32(); int lzmaChunks = Stream.ReadInt32(); for (int i = 0; i < lzmaChunks; i++) { lzmaSize = Stream.ReadInt32(); fileSize = Stream.ReadInt32(); } Stream.Position = offset; switch (magicHeader) { case -361700864190383366: //.bytes case 6155973689634940258: //UnityWeb { byte[] lzmaBuffer = new byte[lzmaSize]; Stream.Read(lzmaBuffer, 0, lzmaSize); Stream.Close(); Stream.Dispose(); Stream = new EndianStream(SevenZip.Compression.LZMA.SevenZipHelper.StreamDecompress(new MemoryStream(lzmaBuffer)), EndianType.BigEndian); offset = 0; break; } case 6155973689634611575: //UnityRaw { break; } } int fileCount = Stream.ReadInt32(); for (int i = 0; i < fileCount; i++) { MemoryAssetsFile memFile = new MemoryAssetsFile(); memFile.fileName = Stream.ReadStringToNull(); int fileOffset = Stream.ReadInt32(); fileOffset += offset; fileSize = Stream.ReadInt32(); long nextFile = Stream.Position; Stream.Position = fileOffset; byte[] buffer = new byte[fileSize]; Stream.Read(buffer, 0, fileSize); memFile.memStream = new MemoryStream(buffer); MemoryAssetsFileList.Add(memFile); Stream.Position = nextFile; } } Stream.Close(); }
public AssetsFile(string fileName, EndianStream fileStream) { //if (memFile != null) { Stream = new EndianStream(memFile, endianType); } //else { Stream = new EndianStream(File.OpenRead(fileName), endianType); } a_Stream = fileStream; filePath = fileName; int tableSize = a_Stream.ReadInt32(); int dataEnd = a_Stream.ReadInt32(); fileGen = a_Stream.ReadInt32(); int dataOffset = a_Stream.ReadInt32(); sharedAssetsList[0].fileName = Path.GetFileName(fileName); //reference itself because sharedFileIDs start from 1 switch (fileGen) { case 6: { a_Stream.Position = (dataEnd - tableSize); a_Stream.Position += 1; break; } case 7://beta { a_Stream.Position = (dataEnd - tableSize); a_Stream.Position += 1; m_Version = a_Stream.ReadStringToNull(); break; } case 8: { a_Stream.Position = (dataEnd - tableSize); a_Stream.Position += 1; m_Version = a_Stream.ReadStringToNull(); platform = a_Stream.ReadInt32(); break; } case 9: { a_Stream.Position += 4;//azero m_Version = a_Stream.ReadStringToNull(); platform = a_Stream.ReadInt32(); break; } case 14: case 15://not fully tested!s { a_Stream.Position += 4;//azero m_Version = a_Stream.ReadStringToNull(); platform = a_Stream.ReadInt32(); baseDefinitions = a_Stream.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); //endianType = EndianType.LittleEndian; a_Stream.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 = a_Stream.ReadInt32(); for (int i = 0; i < baseCount; i++) { if (fileGen < 14) { int baseType = a_Stream.ReadInt32(); readBase(); } else { readBase5(); } } if (fileGen >= 7 && fileGen < 14) {a_Stream.Position += 4;}//azero int assetCount = a_Stream.ReadInt32(); if (fileGen >= 14) { a_Stream.AlignStream(4); } string assetIDfmt = "D" + assetCount.ToString().Length.ToString(); //format for unique ID for (int i = 0; i < assetCount; i++) { AssetPreloadData asset = new AssetPreloadData(); if (fileGen < 14) { asset.m_PathID = a_Stream.ReadInt32(); } else { asset.m_PathID = a_Stream.ReadInt64(); } asset.Offset = a_Stream.ReadInt32(); asset.Offset += dataOffset; asset.Size = a_Stream.ReadInt32(); asset.Type1 = a_Stream.ReadInt32(); asset.Type2 = a_Stream.ReadUInt16(); a_Stream.Position += 2; if (fileGen >= 15) { int azero = a_Stream.ReadInt32(); } asset.TypeString = asset.Type2.ToString(); if (UnityClassID.Names[asset.Type2] != null) { asset.TypeString = UnityClassID.Names[asset.Type2]; } asset.uniqueID = i.ToString(assetIDfmt); asset.exportSize = asset.Size; asset.sourceFile = this; preloadTable.Add(asset.m_PathID, asset); //this should be among the first nodes in mainData and it contains the version - useful for unity 2.x files if (asset.Type2 == 141 && fileGen == 6) { long nextAsset = a_Stream.Position; BuildSettings BSettings = new BuildSettings(asset); m_Version = BSettings.m_Version; a_Stream.Position = nextAsset; } } buildType = m_Version.Split(new string[] { ".", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" }, StringSplitOptions.RemoveEmptyEntries); string[] strver = (m_Version.Split(new string[] { ".", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "\n" }, StringSplitOptions.RemoveEmptyEntries)); version = Array.ConvertAll(strver, int.Parse); if (fileGen >= 14) { int someCount = a_Stream.ReadInt32(); a_Stream.Position += someCount * 12; } int sharedFileCount = a_Stream.ReadInt32(); for (int i = 0; i < sharedFileCount; i++) { UnityShared shared = new UnityShared(); shared.aName = a_Stream.ReadStringToNull(); a_Stream.Position += 20; string sharedFileName = a_Stream.ReadStringToNull(); //relative path shared.fileName = sharedFileName.Replace("/", "\\"); sharedAssetsList.Add(shared); } }
private void readBundle(EndianStream b_Stream) { var signature = b_Stream.ReadStringToNull(); if (signature == "UnityWeb" || signature == "UnityRaw" || signature == "\xFA\xFA\xFA\xFA\xFA\xFA\xFA\xFA") { format = b_Stream.ReadInt32(); versionPlayer = b_Stream.ReadStringToNull(); versionEngine = b_Stream.ReadStringToNull(); if (format < 6) { int bundleSize = b_Stream.ReadInt32(); } else if (format == 6) { ReadFormat6(b_Stream, true); return; } short dummy2 = b_Stream.ReadInt16(); int offset = b_Stream.ReadInt16(); int dummy3 = b_Stream.ReadInt32(); int lzmaChunks = b_Stream.ReadInt32(); int lzmaSize = 0; long streamSize = 0; for (int i = 0; i < lzmaChunks; i++) { lzmaSize = b_Stream.ReadInt32(); streamSize = b_Stream.ReadInt32(); } b_Stream.Position = offset; switch (signature) { case "\xFA\xFA\xFA\xFA\xFA\xFA\xFA\xFA": //.bytes case "UnityWeb": { byte[] lzmaBuffer = new byte[lzmaSize]; b_Stream.Read(lzmaBuffer, 0, lzmaSize); using (var lzmaStream = new EndianStream(SevenZipHelper.StreamDecompress(new MemoryStream(lzmaBuffer)), EndianType.BigEndian)) { getFiles(lzmaStream, 0); } break; } case "UnityRaw": { getFiles(b_Stream, offset); break; } } } else if (signature == "UnityFS") { format = b_Stream.ReadInt32(); versionPlayer = b_Stream.ReadStringToNull(); versionEngine = b_Stream.ReadStringToNull(); if (format == 6) { ReadFormat6(b_Stream); } } }
public AssetsFile(string fileName, EndianStream fileStream = null) { List <UnityShared> list1 = new List <UnityShared> { new UnityShared() }; this.sharedAssetsList = list1; this.UnityClassID = new ClassIDReference(); this.baseDefinitions = false; if (fileStream == null) { fileStream = new EndianStream(File.OpenRead(fileName), EndianType.BigEndian); } this.a_Stream = fileStream; this.filePath = fileName; int num = this.a_Stream.ReadInt32(); int num2 = this.a_Stream.ReadInt32(); this.fileGen = this.a_Stream.ReadInt32(); int num3 = this.a_Stream.ReadInt32(); this.sharedAssetsList[0].fileName = Path.GetFileName(fileName); switch (this.fileGen) { case 6: this.a_Stream.Position = num2 - num; this.a_Stream.Position += 1L; break; case 7: this.a_Stream.Position = num2 - num; this.a_Stream.Position += 1L; this.m_Version = this.a_Stream.ReadStringToNull(); break; case 8: this.a_Stream.Position = num2 - num; this.a_Stream.Position += 1L; this.m_Version = this.a_Stream.ReadStringToNull(); this.platform = this.a_Stream.ReadInt32(); break; case 9: this.a_Stream.Position += 4L; this.m_Version = this.a_Stream.ReadStringToNull(); this.platform = this.a_Stream.ReadInt32(); break; case 10: case 11: case 12: case 13: return; case 14: case 15: this.a_Stream.Position += 4L; this.m_Version = this.a_Stream.ReadStringToNull(); this.platform = this.a_Stream.ReadInt32(); this.baseDefinitions = this.a_Stream.ReadBoolean(); break; default: return; } if ((this.platform > 0xff) || (this.platform < 0)) { byte[] bytes = BitConverter.GetBytes(this.platform); Array.Reverse(bytes); this.platform = BitConverter.ToInt32(bytes, 0); this.a_Stream.endian = EndianType.LittleEndian; } switch (this.platform) { case -2: this.platformStr = "Unity Package"; break; case 4: this.platformStr = "OSX"; break; case 5: this.platformStr = "PC"; break; case 6: this.platformStr = "Web"; break; case 7: this.platformStr = "Web streamed"; break; case 9: this.platformStr = "iOS"; break; case 10: this.platformStr = "PS3"; break; case 11: this.platformStr = "Xbox 360"; break; case 13: this.platformStr = "Android"; break; case 0x10: this.platformStr = "Google NaCl"; break; case 0x15: this.platformStr = "WP8"; break; case 0x19: this.platformStr = "Linux"; break; } int num4 = this.a_Stream.ReadInt32(); for (int i = 0; i < num4; i++) { if (this.fileGen < 14) { int num10 = this.a_Stream.ReadInt32(); string str2 = this.a_Stream.ReadStringToNull(); string str3 = this.a_Stream.ReadStringToNull(); this.a_Stream.Position += 20L; int num11 = this.a_Stream.ReadInt32(); StringBuilder cb = new StringBuilder(); for (int m = 0; m < num11; m++) { this.readBase(cb, 1); } } else { this.readBase5(); } } if ((this.fileGen >= 7) && (this.fileGen < 14)) { this.a_Stream.Position += 4L; } int num5 = this.a_Stream.ReadInt32(); string format = "D" + num5.ToString().Length.ToString(); for (int j = 0; j < num5; j++) { if (this.fileGen >= 14) { this.a_Stream.AlignStream(4); } AssetPreloadData data = new AssetPreloadData(); if (this.fileGen < 14) { data.m_PathID = this.a_Stream.ReadInt32(); } else { data.m_PathID = this.a_Stream.ReadInt64(); } data.Offset = this.a_Stream.ReadInt32(); data.Offset += num3; data.Size = this.a_Stream.ReadInt32(); data.Type1 = this.a_Stream.ReadInt32(); data.Type2 = this.a_Stream.ReadUInt16(); this.a_Stream.Position += 2L; if ((this.fileGen >= 15) && (this.a_Stream.ReadByte() > 0)) { } if (this.UnityClassID.Names[data.Type2] == null) { data.TypeString = this.UnityClassID.Names[data.Type2]; } data.uniqueID = j.ToString(format); data.exportSize = data.Size; data.sourceFile = this; this.preloadTable.Add(data.m_PathID, data); if ((data.Type2 == 0x8d) && (this.fileGen == 6)) { long position = this.a_Stream.Position; BuildSettings settings = new BuildSettings(data); this.m_Version = settings.m_Version; this.a_Stream.Position = position; } } string[] separator = new string[] { ".", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" }; this.buildType = this.m_Version.Split(separator, StringSplitOptions.RemoveEmptyEntries); string[] textArray2 = new string[] { ".", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "\n" }; string[] array = this.m_Version.Split(textArray2, StringSplitOptions.RemoveEmptyEntries); this.version = Array.ConvertAll <string, int>(array, new Converter <string, int>(int.Parse)); if (this.fileGen >= 14) { int num17 = this.a_Stream.ReadInt32(); for (int n = 0; n < num17; n++) { int num19 = this.a_Stream.ReadInt32(); this.a_Stream.AlignStream(4); long num20 = this.a_Stream.ReadInt64(); } } int num6 = this.a_Stream.ReadInt32(); for (int k = 0; k < num6; k++) { UnityShared item = new UnityShared { aName = this.a_Stream.ReadStringToNull() }; this.a_Stream.Position += 20L; item.fileName = this.a_Stream.ReadStringToNull().Replace("/", @"\"); this.sharedAssetsList.Add(item); } }
private void readBundle(EndianStream b_Stream) { var header = b_Stream.ReadStringToNull(); if (header == "UnityWeb" || header == "UnityRaw" || header == "\xFA\xFA\xFA\xFA\xFA\xFA\xFA\xFA") { ver1 = b_Stream.ReadInt32(); ver2 = b_Stream.ReadStringToNull(); ver3 = b_Stream.ReadStringToNull(); if (ver1 < 6) { int bundleSize = b_Stream.ReadInt32(); } else { long bundleSize = b_Stream.ReadInt64(); return; } short dummy2 = b_Stream.ReadInt16(); int offset = b_Stream.ReadInt16(); int dummy3 = b_Stream.ReadInt32(); int lzmaChunks = b_Stream.ReadInt32(); int lzmaSize = 0; long streamSize = 0; for (int i = 0; i < lzmaChunks; i++) { lzmaSize = b_Stream.ReadInt32(); streamSize = b_Stream.ReadInt32(); } b_Stream.Position = offset; switch (header) { case "\xFA\xFA\xFA\xFA\xFA\xFA\xFA\xFA": //.bytes case "UnityWeb": { byte[] lzmaBuffer = new byte[lzmaSize]; b_Stream.Read(lzmaBuffer, 0, lzmaSize); using (var lzmaStream = new EndianStream(SevenZip.Compression.LZMA.SevenZipHelper.StreamDecompress(new MemoryStream(lzmaBuffer)), EndianType.BigEndian)) { getFiles(lzmaStream, 0); } break; } case "UnityRaw": { getFiles(b_Stream, offset); break; } } } else if (header == "UnityFS") { ver1 = b_Stream.ReadInt32(); ver2 = b_Stream.ReadStringToNull(); ver3 = b_Stream.ReadStringToNull(); long bundleSize = b_Stream.ReadInt64(); } }
public AssetsFile(string fullName, EndianStream fileStream) { //if (memFile != null) { Stream = new EndianStream(memFile, endianType); } //else { Stream = new EndianStream(File.OpenRead(fileName), endianType); } a_Stream = fileStream; filePath = fullName; fileName = Path.GetFileName(fullName); int tableSize = a_Stream.ReadInt32(); int dataEnd = a_Stream.ReadInt32(); fileGen = a_Stream.ReadInt32(); uint dataOffset = a_Stream.ReadUInt32(); sharedAssetsList[0].fileName = Path.GetFileName(fullName); //reference itself because sharedFileIDs start from 1 switch (fileGen) { case 6: //2.5.0 - 2.6.1 { a_Stream.Position = (dataEnd - tableSize); a_Stream.Position += 1; break; } case 7: //3.0.0 beta { a_Stream.Position = (dataEnd - tableSize); a_Stream.Position += 1; m_Version = a_Stream.ReadStringToNull(); break; } case 8: //3.0.0 - 3.4.2 { a_Stream.Position = (dataEnd - tableSize); a_Stream.Position += 1; m_Version = a_Stream.ReadStringToNull(); platform = a_Stream.ReadInt32(); break; } case 9: //3.5.0 - 4.6.x { a_Stream.Position += 4; //azero m_Version = a_Stream.ReadStringToNull(); platform = a_Stream.ReadInt32(); break; } case 14: //5.0.0 beta and final case 15: //5.0.1 - 5.4 case 16: //??.. no sure case 17: //5.5.0 and up { a_Stream.Position += 4; //azero m_Version = a_Stream.ReadStringToNull(); platform = a_Stream.ReadInt32(); baseDefinitions = a_Stream.ReadBoolean(); break; } default: { //MessageBox.Show("Unsupported Unity version!" + fileGen, "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); //endianType = EndianType.LittleEndian; a_Stream.endian = EndianType.LittleEndian; } switch (platform) { case -2: platformStr = "Unity Package"; break; case 4: platformStr = "OSX"; break; case 5: platformStr = "PC"; break; case 6: platformStr = "Web"; break; case 7: platformStr = "Web streamed"; break; case 9: platformStr = "iOS"; break; case 10: platformStr = "PS3"; break; case 11: platformStr = "Xbox 360"; break; case 13: platformStr = "Android"; break; case 16: platformStr = "Google NaCl"; break; case 21: platformStr = "WP8"; break; case 25: platformStr = "Linux"; break; case 29: platformStr = "Wii U"; break; default: platformStr = "Unknown Platform"; break; } int baseCount = a_Stream.ReadInt32(); for (int i = 0; i < baseCount; i++) { if (fileGen < 14) { int classID = a_Stream.ReadInt32(); string baseType = a_Stream.ReadStringToNull(); string baseName = a_Stream.ReadStringToNull(); a_Stream.Position += 20; int memberCount = a_Stream.ReadInt32(); var cb = new List <ClassMember>(); for (int m = 0; m < memberCount; m++) { readBase(cb, 1); } var aClass = new ClassStruct() { ID = classID, Text = (baseType + " " + baseName), members = cb }; aClass.SubItems.Add(classID.ToString()); ClassStructures.Add(classID, aClass); } else { readBase5(); } } if (fileGen >= 7 && fileGen < 14) { a_Stream.Position += 4; } //azero int assetCount = a_Stream.ReadInt32(); #region asset preload table string assetIDfmt = "D" + assetCount.ToString().Length; //format for unique ID for (int i = 0; i < assetCount; i++) { //each table entry is aligned individually, not the whole table if (fileGen >= 14) { a_Stream.AlignStream(4); } AssetPreloadData asset = new AssetPreloadData(); if (fileGen < 14) { asset.m_PathID = a_Stream.ReadInt32(); } else { asset.m_PathID = a_Stream.ReadInt64(); } asset.Offset = a_Stream.ReadUInt32(); asset.Offset += dataOffset; asset.Size = a_Stream.ReadInt32(); if (fileGen > 15) { int index = a_Stream.ReadInt32(); asset.Type1 = classIDs[index][0]; asset.Type2 = (ushort)classIDs[index][1]; } else { asset.Type1 = a_Stream.ReadInt32(); asset.Type2 = a_Stream.ReadUInt16(); a_Stream.Position += 2; } if (fileGen == 15) { byte unknownByte = a_Stream.ReadByte(); //this is a single byte, not an int32 //the next entry is aligned after this //but not the last! if (unknownByte != 0) { //bool investigate = true; } } string typeString; if (ClassIDReference.Names.TryGetValue(asset.Type2, out typeString)) { asset.TypeString = typeString; } else { asset.TypeString = "Unknown Type " + asset.Type2; } asset.uniqueID = i.ToString(assetIDfmt); asset.sourceFile = this; preloadTable.Add(asset.m_PathID, asset); #region read BuildSettings to get version for unity 2.x files if (asset.Type2 == 141 && fileGen == 6) { long nextAsset = a_Stream.Position; BuildSettings BSettings = new BuildSettings(asset); m_Version = BSettings.m_Version; a_Stream.Position = nextAsset; } #endregion } #endregion buildType = m_Version.Split(buildTypeSplit, StringSplitOptions.RemoveEmptyEntries); var strver = m_Version.Split(strverSplit, StringSplitOptions.RemoveEmptyEntries); version = Array.ConvertAll(strver, int.Parse); 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 = a_Stream.ReadInt32(); for (int i = 0; i < sharedFileCount; i++) { UnityShared shared = new UnityShared(); shared.aName = a_Stream.ReadStringToNull(); a_Stream.Position += 20; string sharedFileName = a_Stream.ReadStringToNull(); //relative path shared.fileName = sharedFileName.Replace("/", "\\"); sharedAssetsList.Add(shared); } }
public Mesh(AssetPreloadData MeshPD) { //Stream = new EndianStream(File.OpenRead(sourceFile.filePath), sourceFile.endianType); //Stream.endian = sourceFile.endianType; var version = MeshPD.sourceFile.version; a_Stream = MeshPD.sourceFile.a_Stream; a_Stream.Position = MeshPD.Offset; bool m_Use16BitIndices = true; //3.5.0 and newer always uses 16bit indices uint m_MeshCompression = 0; if (MeshPD.sourceFile.platform == -2) { uint m_ObjectHideFlags = a_Stream.ReadUInt32(); PPtr m_PrefabParentObject = MeshPD.sourceFile.ReadPPtr(); PPtr m_PrefabInternal = MeshPD.sourceFile.ReadPPtr(); } m_Name = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); if (version[0] < 3 || (version[0] == 3 && version[1] < 5)) { m_Use16BitIndices = a_Stream.ReadBoolean(); a_Stream.Position += 3; } #region Index Buffer for 2.5.1 and earlier if (version[0] == 2 && version[1] <= 5) { int m_IndexBuffer_size = a_Stream.ReadInt32(); if (m_Use16BitIndices) { m_IndexBuffer = new uint[m_IndexBuffer_size / 2]; for (int i = 0; i < m_IndexBuffer_size / 2; i++) { m_IndexBuffer[i] = a_Stream.ReadUInt16(); } a_Stream.AlignStream(4); } else { m_IndexBuffer = new uint[m_IndexBuffer_size / 4]; for (int i = 0; i < m_IndexBuffer_size / 4; i++) { m_IndexBuffer[i] = a_Stream.ReadUInt32(); } } } #endregion int m_SubMeshes_size = a_Stream.ReadInt32(); for (int s = 0; s < m_SubMeshes_size; s++) { m_SubMeshes.Add(new SubMesh()); m_SubMeshes[s].firstByte = a_Stream.ReadUInt32(); m_SubMeshes[s].indexCount = a_Stream.ReadUInt32(); //what is this in case of triangle strips? m_SubMeshes[s].topology = a_Stream.ReadInt32(); //isTriStrip if (version[0] < 4) { m_SubMeshes[s].triangleCount = a_Stream.ReadUInt32(); } if (version[0] >= 3) { m_SubMeshes[s].firstVertex = a_Stream.ReadUInt32(); m_SubMeshes[s].vertexCount = a_Stream.ReadUInt32(); a_Stream.Position += 24; //Axis-Aligned Bounding Box } } #region m_Shapes for 4.1.0 and later, excluding 4.1.0 alpha if (version [0] >= 5 || (version[0] == 4 && (version[1] > 1 || (version[1] == 1 && MeshPD.sourceFile.buildType[0] != "a")))) { if (version[0] == 4 && version[1] <= 2) //4.1.0f4 - 4.2.2f1 { int m_Shapes_size = a_Stream.ReadInt32(); if (m_Shapes_size > 0) { bool stop = true; } for (int s = 0; s < m_Shapes_size; s++) //untested { string shape_name = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); a_Stream.Position += 36; //uint firstVertex, vertexCount; Vector3f aabbMinDelta, aabbMaxDelta; bool hasNormals, hasTangents } int m_ShapeVertices_size = a_Stream.ReadInt32(); a_Stream.Position += m_ShapeVertices_size * 40; //vertex positions, normals, tangents & uint index } else //4.3.0 and later { int m_ShapeVertices_size = a_Stream.ReadInt32(); a_Stream.Position += m_ShapeVertices_size * 40; //vertex positions, normals, tangents & uint index int shapes_size = a_Stream.ReadInt32(); a_Stream.Position += shapes_size * 12; //uint firstVertex, vertexCount; bool hasNormals, hasTangents int channels_size = a_Stream.ReadInt32(); for (int c = 0; c < channels_size; c++) { string channel_name = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); a_Stream.Position += 12; //uint nameHash; int frameIndex, frameCount } int fullWeights_size = a_Stream.ReadInt32(); a_Stream.Position += fullWeights_size * 4; //floats int m_BindPose_size = a_Stream.ReadInt32(); a_Stream.Position += m_BindPose_size * 16 * 4; //matrix 4x4 int m_BoneNameHashes_size = a_Stream.ReadInt32(); a_Stream.Position += m_BoneNameHashes_size * 4; //uints uint m_RootBoneNameHash = a_Stream.ReadUInt32(); } } #endregion #region Index Buffer for 2.6.0 and later if (version[0] >= 3 || (version[0] == 2 && version[1] >= 6)) { m_MeshCompression = a_Stream.ReadByte(); if (version[0] >= 4) { if (version[0] < 5) { uint m_StreamCompression = a_Stream.ReadByte(); } bool m_IsReadable = a_Stream.ReadBoolean(); bool m_KeepVertices = a_Stream.ReadBoolean(); bool m_KeepIndices = a_Stream.ReadBoolean(); } a_Stream.AlignStream(4); int m_IndexBuffer_size = a_Stream.ReadInt32(); if (m_Use16BitIndices) { m_IndexBuffer = new uint[m_IndexBuffer_size / 2]; for (int i = 0; i < m_IndexBuffer_size / 2; i++) { m_IndexBuffer[i] = a_Stream.ReadUInt16(); } a_Stream.AlignStream(4); } else { m_IndexBuffer = new uint[m_IndexBuffer_size / 4]; for (int i = 0; i < m_IndexBuffer_size / 4; i++) { m_IndexBuffer[i] = a_Stream.ReadUInt32(); } //align?? } } #endregion #region Vertex Buffer for 3.4.2 and earlier if (version[0] < 3 || (version[0] == 3 && version[1] < 5)) { m_VertexCount = a_Stream.ReadUInt32(); m_Vertices = new float[m_VertexCount * 3]; for (int v = 0; v < m_VertexCount * 3; v++) { m_Vertices[v] = a_Stream.ReadSingle(); } int m_Skin_size = a_Stream.ReadInt32(); a_Stream.Position += m_Skin_size * 32; //4x float weights & 4x int boneIndices int m_BindPose_size = a_Stream.ReadInt32(); a_Stream.Position += m_BindPose_size * 16 * 4; //matrix 4x4 int m_UV1_size = a_Stream.ReadInt32(); m_UV1 = new float[m_UV1_size * 2]; for (int v = 0; v < m_UV1_size * 2; v++) { m_UV1[v] = a_Stream.ReadSingle(); } int m_UV2_size = a_Stream.ReadInt32(); m_UV2 = new float[m_UV2_size * 2]; for (int v = 0; v < m_UV2_size * 2; v++) { m_UV2[v] = a_Stream.ReadSingle(); } if (version[0] == 2 && version[1] <= 5) { int m_TangentSpace_size = a_Stream.ReadInt32(); m_Normals = new float[m_TangentSpace_size * 3]; for (int v = 0; v < m_TangentSpace_size; v++) { m_Normals[v * 3] = a_Stream.ReadSingle(); m_Normals[v * 3 + 1] = a_Stream.ReadSingle(); m_Normals[v * 3 + 2] = a_Stream.ReadSingle(); a_Stream.Position += 16; //Vector3f tangent & float handedness } } else //2.6.0 and later { int m_Tangents_size = a_Stream.ReadInt32(); a_Stream.Position += m_Tangents_size * 16; //Vector4f int m_Normals_size = a_Stream.ReadInt32(); m_Normals = new float[m_Normals_size * 3]; for (int v = 0; v < m_Normals_size * 3; v++) { m_Normals[v] = a_Stream.ReadSingle(); } } } #endregion #region Vertex Buffer for 3.5.0 and later else { #region read vertex stream int m_Skin_size = a_Stream.ReadInt32(); a_Stream.Position += m_Skin_size * 32; //4x float weights & 4x int boneIndices if (version[0] <= 3 || (version[0] == 4 && version[1] <= 2)) { int m_BindPose_size = a_Stream.ReadInt32(); a_Stream.Position += m_BindPose_size * 16 * 4; //matrix 4x4 } int m_CurrentChannels = a_Stream.ReadInt32();//defined as uint in Unity m_VertexCount = a_Stream.ReadUInt32(); #region 3.5.0 - 3.5.7 if (version[0] < 4) { if (m_MeshCompression != 0 && version[2] == 0) //special case not just on platform 9 { a_Stream.Position += 12; } else { m_Streams = new StreamInfo[4]; for (int s = 0; s < 4; s++) { m_Streams[s] = new StreamInfo(); m_Streams[s].channelMask = new BitArray(new int[1] { a_Stream.ReadInt32() }); m_Streams[s].offset = a_Stream.ReadInt32(); m_Streams[s].stride = a_Stream.ReadInt32(); m_Streams[s].align = a_Stream.ReadUInt32(); } } } #endregion #region 4.0.0 and later else { int singleStreamStride = 0;//used tor unity 5 m_Channels = new ChannelInfo[a_Stream.ReadInt32()]; for (int c = 0; c < m_Channels.Length; c++) { m_Channels[c] = new ChannelInfo(); m_Channels[c].stream = a_Stream.ReadByte(); m_Channels[c].offset = a_Stream.ReadByte(); m_Channels[c].format = a_Stream.ReadByte(); m_Channels[c].dimension = a_Stream.ReadByte(); //calculate stride for Unity 5 singleStreamStride += m_Channels[c].dimension * (m_Channels[c].format % 2 == 0 ? 4 : 2);//fingers crossed! } if (version[0] < 5) { m_Streams = new StreamInfo[a_Stream.ReadInt32()]; for (int s = 0; s < m_Streams.Length; s++) { m_Streams[s] = new StreamInfo(); m_Streams[s].channelMask = new BitArray(new int[1] { a_Stream.ReadInt32() }); m_Streams[s].offset = a_Stream.ReadInt32(); m_Streams[s].stride = a_Stream.ReadByte(); m_Streams[s].dividerOp = a_Stream.ReadByte(); m_Streams[s].frequency = a_Stream.ReadUInt16(); } } else //it's just easier to create my own stream here { m_Streams = new StreamInfo[1]; m_Streams[0] = new StreamInfo(); m_Streams[0].channelMask = new BitArray(new int[1] { m_CurrentChannels }); m_Streams[0].offset = 0; m_Streams[0].stride = singleStreamStride; } } #endregion //actual Vertex Buffer byte[] m_DataSize = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_DataSize, 0, m_DataSize.Length); #endregion #region compute FvF byte valueBufferSize = 0; byte[] valueBuffer; float[] dstArray; if (m_Channels != null) { //it is better to loop channels instead of streams //because channels are likely to be sorted by vertex property #region 4.0.0 and later foreach (var m_Channel in m_Channels) { if (m_Channel.dimension > 0) { var m_Stream = m_Streams[m_Channel.stream]; for (int b = 0; b < 6; b++) { if (m_Stream.channelMask.Get(b)) { switch (m_Channel.format) { case 0: //32bit valueBufferSize = 4; break; case 1: //16bit valueBufferSize = 2; break; case 2: //8bit valueBufferSize = 1; m_Channel.dimension = 4;//these are actually groups of 4 components break; } valueBuffer = new byte[valueBufferSize]; dstArray = new float[m_VertexCount * m_Channel.dimension]; for (int v = 0; v < m_VertexCount; v++) { for (int d = 0; d < m_Channel.dimension; d++) { int m_DataSizeOffset = m_Stream.offset + m_Channel.offset + m_Stream.stride * v + valueBufferSize * d; Buffer.BlockCopy(m_DataSize, m_DataSizeOffset, valueBuffer, 0, valueBufferSize); dstArray[v * m_Channel.dimension + d] = bytesToFloat(valueBuffer); } } switch (b) { case 0://1 m_Vertices = dstArray; break; case 1://2 m_Normals = dstArray; break; case 2://4 m_Colors = dstArray; break; case 3://8 m_UV1 = dstArray; break; case 4://16 m_UV2 = dstArray; break; case 5://32 m_Tangents = dstArray; break; } m_Stream.channelMask.Set(b, false); //is this needed? valueBuffer = null; dstArray = null; break; //go to next channel } } } } } #endregion #region 3.5.0 - 3.5.7 else if (m_Streams != null) { foreach (var m_Stream in m_Streams) { //a stream may have multiple vertex components but without channels there are no offsets, so I assume all vertex properties are in order //Unity 3.5.x only uses floats, and that's probably why channels were introduced in Unity 4 ChannelInfo m_Channel = new ChannelInfo();//create my own channel so I can use the same methods m_Channel.offset = 0; for (int b = 0; b < 6; b++) { if (m_Stream.channelMask.Get(b)) { switch (b) { case 0: case 1: valueBufferSize = 4; m_Channel.dimension = 3; break; case 2: valueBufferSize = 1; m_Channel.dimension = 4; break; case 3: case 4: valueBufferSize = 4; m_Channel.dimension = 2; break; case 5: valueBufferSize = 4; m_Channel.dimension = 4; break; } valueBuffer = new byte[valueBufferSize]; dstArray = new float[m_VertexCount * m_Channel.dimension]; for (int v = 0; v < m_VertexCount; v++) { for (int d = 0; d < m_Channel.dimension; d++) { int m_DataSizeOffset = m_Stream.offset + m_Channel.offset + m_Stream.stride * v + valueBufferSize * d; Buffer.BlockCopy(m_DataSize, m_DataSizeOffset, valueBuffer, 0, valueBufferSize); dstArray[v * m_Channel.dimension + d] = bytesToFloat(valueBuffer); } } switch (b) { case 0: m_Vertices = dstArray; break; case 1: m_Normals = dstArray; break; case 2: m_Colors = dstArray; break; case 3: m_UV1 = dstArray; break; case 4: m_UV2 = dstArray; break; case 5: m_Tangents = dstArray; break; } m_Channel.offset += (byte)(m_Channel.dimension * valueBufferSize); //strides larger than 255 are unlikely m_Stream.channelMask.Set(b, false); //is this needed? valueBuffer = null; dstArray = null; } } } } #endregion #endregion } #endregion #region Compressed Mesh data for 2.6.0 and later - 160 bytes if (version[0] >= 3 || (version[0] == 2 && version[1] >= 6)) { //remember there can be combinations of packed and regular vertex properties PackedBitVector m_Vertices_Packed = new PackedBitVector(); m_Vertices_Packed.m_NumItems = a_Stream.ReadUInt32(); m_Vertices_Packed.m_Range = a_Stream.ReadSingle(); m_Vertices_Packed.m_Start = a_Stream.ReadSingle(); m_Vertices_Packed.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_Vertices_Packed.m_Data, 0, m_Vertices_Packed.m_Data.Length); a_Stream.AlignStream(4); m_Vertices_Packed.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment if (m_Vertices_Packed.m_NumItems > 0) { m_VertexCount = m_Vertices_Packed.m_NumItems / 3; uint[] m_Vertices_Unpacked = UnpackBitVector(m_Vertices_Packed); int bitmax = 0;//used to convert int value to float for (int b = 0; b < m_Vertices_Packed.m_BitSize; b++) { bitmax |= (1 << b); } m_Vertices = new float[m_Vertices_Packed.m_NumItems]; for (int v = 0; v < m_Vertices_Packed.m_NumItems; v++) { m_Vertices[v] = (float)m_Vertices_Unpacked[v] / bitmax * m_Vertices_Packed.m_Range + m_Vertices_Packed.m_Start; } } PackedBitVector m_UV_Packed = new PackedBitVector(); //contains both channels m_UV_Packed.m_NumItems = a_Stream.ReadUInt32(); m_UV_Packed.m_Range = a_Stream.ReadSingle(); m_UV_Packed.m_Start = a_Stream.ReadSingle(); m_UV_Packed.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_UV_Packed.m_Data, 0, m_UV_Packed.m_Data.Length); m_UV_Packed.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment if (m_UV_Packed.m_NumItems > 0) { uint[] m_UV_Unpacked = UnpackBitVector(m_UV_Packed); int bitmax = 0; for (int b = 0; b < m_Vertices_Packed.m_BitSize; b++) { bitmax |= (1 << b); } m_UV1 = new float[m_VertexCount * 2]; for (int v = 0; v < m_VertexCount * 2; v++) { m_UV1[v] = (float)m_UV_Unpacked[v] / bitmax * m_UV_Packed.m_Range + m_UV_Packed.m_Start; } if (m_UV_Packed.m_NumItems == m_VertexCount * 4) { m_UV2 = new float[m_VertexCount * 2]; for (uint v = 0; v < m_VertexCount * 2; v++) { m_UV2[v] = (float)m_UV_Unpacked[v + m_VertexCount * 2] / bitmax * m_UV_Packed.m_Range + m_UV_Packed.m_Start; } } } if (version[0] < 5) { PackedBitVector m_BindPoses_Packed = new PackedBitVector(); m_BindPoses_Packed.m_NumItems = a_Stream.ReadUInt32(); m_BindPoses_Packed.m_Range = a_Stream.ReadSingle(); m_BindPoses_Packed.m_Start = a_Stream.ReadSingle(); m_BindPoses_Packed.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_BindPoses_Packed.m_Data, 0, m_BindPoses_Packed.m_Data.Length); a_Stream.AlignStream(4); m_BindPoses_Packed.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment } PackedBitVector m_Normals_Packed = new PackedBitVector(); m_Normals_Packed.m_NumItems = a_Stream.ReadUInt32(); m_Normals_Packed.m_Range = a_Stream.ReadSingle(); m_Normals_Packed.m_Start = a_Stream.ReadSingle(); m_Normals_Packed.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_Normals_Packed.m_Data, 0, m_Normals_Packed.m_Data.Length); a_Stream.AlignStream(4); m_Normals_Packed.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment PackedBitVector m_Tangents_Packed = new PackedBitVector(); m_Tangents_Packed.m_NumItems = a_Stream.ReadUInt32(); m_Tangents_Packed.m_Range = a_Stream.ReadSingle(); m_Tangents_Packed.m_Start = a_Stream.ReadSingle(); m_Tangents_Packed.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_Tangents_Packed.m_Data, 0, m_Tangents_Packed.m_Data.Length); a_Stream.AlignStream(4); m_Tangents_Packed.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment PackedBitVector m_Weights_Packed = new PackedBitVector(); m_Weights_Packed.m_NumItems = a_Stream.ReadUInt32(); m_Weights_Packed.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_Weights_Packed.m_Data, 0, m_Weights_Packed.m_Data.Length); a_Stream.AlignStream(4); m_Weights_Packed.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment PackedBitVector m_NormalSigns_packed = new PackedBitVector(); m_NormalSigns_packed.m_NumItems = a_Stream.ReadUInt32(); m_NormalSigns_packed.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_NormalSigns_packed.m_Data, 0, m_NormalSigns_packed.m_Data.Length); a_Stream.AlignStream(4); m_NormalSigns_packed.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment if (m_Normals_Packed.m_NumItems > 0) { uint[] m_Normals_Unpacked = UnpackBitVector(m_Normals_Packed); uint[] m_NormalSigns = UnpackBitVector(m_NormalSigns_packed); int bitmax = 0; for (int b = 0; b < m_Normals_Packed.m_BitSize; b++) { bitmax |= (1 << b); } m_Normals = new float[m_Normals_Packed.m_NumItems / 2 * 3]; for (int v = 0; v < m_Normals_Packed.m_NumItems / 2; v++) { m_Normals[v * 3] = (float)((double)m_Normals_Unpacked[v * 2] / bitmax) * m_Normals_Packed.m_Range + m_Normals_Packed.m_Start; m_Normals[v * 3 + 1] = (float)((double)m_Normals_Unpacked[v * 2 + 1] / bitmax) * m_Normals_Packed.m_Range + m_Normals_Packed.m_Start; m_Normals[v * 3 + 2] = (float)Math.Sqrt(1 - m_Normals[v * 3] * m_Normals[v * 3] - m_Normals[v * 3 + 1] * m_Normals[v * 3 + 1]); if (m_NormalSigns[v] == 0) { m_Normals[v * 3 + 2] *= -1; } } } PackedBitVector m_TangentSigns = new PackedBitVector(); m_TangentSigns.m_NumItems = a_Stream.ReadUInt32(); m_TangentSigns.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_TangentSigns.m_Data, 0, m_TangentSigns.m_Data.Length); a_Stream.AlignStream(4); m_TangentSigns.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment if (version[0] >= 5) { PackedBitVector m_FloatColors = new PackedBitVector(); m_FloatColors.m_NumItems = a_Stream.ReadUInt32(); m_FloatColors.m_Range = a_Stream.ReadSingle(); m_FloatColors.m_Start = a_Stream.ReadSingle(); m_FloatColors.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_FloatColors.m_Data, 0, m_FloatColors.m_Data.Length); a_Stream.AlignStream(4); m_FloatColors.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment if (m_FloatColors.m_NumItems > 0) { uint[] m_FloatColors_Unpacked = UnpackBitVector(m_FloatColors); int bitmax = 0; for (int b = 0; b < m_Vertices_Packed.m_BitSize; b++) { bitmax |= (1 << b); } m_Colors = new float[m_FloatColors.m_NumItems]; for (int v = 0; v < m_FloatColors.m_NumItems; v++) { m_Colors[v] = (float)m_FloatColors_Unpacked[v] / bitmax * m_FloatColors.m_Range + m_FloatColors.m_Start; } } } PackedBitVector m_BoneIndices = new PackedBitVector(); m_BoneIndices.m_NumItems = a_Stream.ReadUInt32(); m_BoneIndices.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_BoneIndices.m_Data, 0, m_BoneIndices.m_Data.Length); a_Stream.AlignStream(4); m_BoneIndices.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment PackedBitVector m_Triangles = new PackedBitVector(); m_Triangles.m_NumItems = a_Stream.ReadUInt32(); m_Triangles.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_Triangles.m_Data, 0, m_Triangles.m_Data.Length); a_Stream.AlignStream(4); m_Triangles.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment if (m_Triangles.m_NumItems > 0) { m_IndexBuffer = UnpackBitVector(m_Triangles); } } #endregion #region Colors & Collision triangles for 3.4.2 and earlier if (version[0] <= 2 || (version[0] == 3 && version[1] <= 4)) // { a_Stream.Position += 24; //Axis-Aligned Bounding Box int m_Colors_size = a_Stream.ReadInt32(); m_Colors = new float[m_Colors_size * 4]; for (int v = 0; v < m_Colors_size * 4; v++) { m_Colors[v] = (float)(a_Stream.ReadByte()) / 0xFF; } int m_CollisionTriangles_size = a_Stream.ReadInt32(); a_Stream.Position += m_CollisionTriangles_size * 4; //UInt32 indices int m_CollisionVertexCount = a_Stream.ReadInt32(); } #endregion #region Compressed colors & Local AABB for 3.5.0 to 4.x.x else //vertex colors are either in streams or packed bits { if (version[0] < 5) { PackedBitVector m_Colors_Packed = new PackedBitVector(); m_Colors_Packed.m_NumItems = a_Stream.ReadUInt32(); m_Colors_Packed.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_Colors_Packed.m_Data, 0, m_Colors_Packed.m_Data.Length); a_Stream.AlignStream(4); m_Colors_Packed.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment if (m_Colors_Packed.m_NumItems > 0) { if (m_Colors_Packed.m_BitSize == 32) { //4 x 8bit color channels m_Colors = new float[m_Colors_Packed.m_Data.Length]; for (int v = 0; v < m_Colors_Packed.m_Data.Length; v++) { m_Colors[v] = (float)m_Colors_Packed.m_Data[v] / 0xFF; } } else //not tested { uint[] m_Colors_Unpacked = UnpackBitVector(m_Colors_Packed); int bitmax = 0;//used to convert int value to float for (int b = 0; b < m_Colors_Packed.m_BitSize; b++) { bitmax |= (1 << b); } m_Colors = new float[m_Colors_Packed.m_NumItems]; for (int v = 0; v < m_Colors_Packed.m_NumItems; v++) { m_Colors[v] = (float)m_Colors_Unpacked[v] / bitmax; } } } } a_Stream.Position += 24; //Axis-Aligned Bounding Box } #endregion int m_MeshUsageFlags = a_Stream.ReadInt32(); if (version[0] >= 5) { //int m_BakedConvexCollisionMesh = a_Stream.ReadInt32(); //a_Stream.Position += m_BakedConvexCollisionMesh; //int m_BakedTriangleCollisionMesh = a_Stream.ReadInt32(); //a_Stream.Position += m_BakedConvexCollisionMesh; } #region Build face indices for (int s = 0; s < m_SubMeshes_size; s++) { uint firstIndex = m_SubMeshes[s].firstByte / 2; if (!m_Use16BitIndices) { firstIndex /= 2; } if (m_SubMeshes[s].topology == 0) { for (int i = 0; i < m_SubMeshes[s].indexCount / 3; i++) { m_Indices.Add(m_IndexBuffer[firstIndex + i * 3]); m_Indices.Add(m_IndexBuffer[firstIndex + i * 3 + 1]); m_Indices.Add(m_IndexBuffer[firstIndex + i * 3 + 2]); m_materialIDs.Add(s); } } else { for (int i = 0; i < m_SubMeshes[s].indexCount - 2; i++) { uint fa = m_IndexBuffer[firstIndex + i]; uint fb = m_IndexBuffer[firstIndex + i + 1]; uint fc = m_IndexBuffer[firstIndex + i + 2]; if ((fa!=fb) && (fa!=fc) && (fc!=fb)) { m_Indices.Add(fa); if ((i % 2) == 0) { m_Indices.Add(fb); m_Indices.Add(fc); } else { m_Indices.Add(fc); m_Indices.Add(fb); } m_materialIDs.Add(s); } } } } #endregion }
public Mesh(AssetPreloadData MeshPD) { //Stream = new EndianStream(File.OpenRead(sourceFile.filePath), sourceFile.endianType); //Stream.endian = sourceFile.endianType; var version = MeshPD.sourceFile.version; a_Stream = MeshPD.sourceFile.a_Stream; a_Stream.Position = MeshPD.Offset; bool m_Use16BitIndices = true; //3.5.0 and newer always uses 16bit indices uint m_MeshCompression = 0; if (MeshPD.sourceFile.platform == -2) { uint m_ObjectHideFlags = a_Stream.ReadUInt32(); PPtr m_PrefabParentObject = MeshPD.sourceFile.ReadPPtr(); PPtr m_PrefabInternal = MeshPD.sourceFile.ReadPPtr(); } m_Name = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); if (version[0] < 3 || (version[0] == 3 && version[1] < 5)) { m_Use16BitIndices = a_Stream.ReadBoolean(); a_Stream.Position += 3; } #region Index Buffer for 2.5.1 and earlier if (version[0] == 2 && version[1] <= 5) { int m_IndexBuffer_size = a_Stream.ReadInt32(); if (m_Use16BitIndices) { m_IndexBuffer = new uint[m_IndexBuffer_size / 2]; for (int i = 0; i < m_IndexBuffer_size / 2; i++) { m_IndexBuffer[i] = a_Stream.ReadUInt16(); } a_Stream.AlignStream(4); } else { m_IndexBuffer = new uint[m_IndexBuffer_size / 4]; for (int i = 0; i < m_IndexBuffer_size / 4; i++) { m_IndexBuffer[i] = a_Stream.ReadUInt32(); } } } #endregion #region subMeshes int m_SubMeshes_size = a_Stream.ReadInt32(); for (int s = 0; s < m_SubMeshes_size; s++) { m_SubMeshes.Add(new SubMesh()); m_SubMeshes[s].firstByte = a_Stream.ReadUInt32(); m_SubMeshes[s].indexCount = a_Stream.ReadUInt32(); //what is this in case of triangle strips? m_SubMeshes[s].topology = a_Stream.ReadInt32(); //isTriStrip if (version[0] < 4) { m_SubMeshes[s].triangleCount = a_Stream.ReadUInt32(); } if (version[0] >= 3) { m_SubMeshes[s].firstVertex = a_Stream.ReadUInt32(); m_SubMeshes[s].vertexCount = a_Stream.ReadUInt32(); a_Stream.Position += 24; //Axis-Aligned Bounding Box } } #endregion #region BlendShapeData for 4.1.0 to 4.2.x, excluding 4.1.0 alpha if (version[0] == 4 && ((version[1] == 1 && MeshPD.sourceFile.buildType[0] != "a") || (version[1] > 1 && version[1] <= 2))) { int m_Shapes_size = a_Stream.ReadInt32(); if (m_Shapes_size > 0) { bool stop = true; } for (int s = 0; s < m_Shapes_size; s++) //untested { string shape_name = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); a_Stream.Position += 36; //uint firstVertex, vertexCount; Vector3f aabbMinDelta, aabbMaxDelta; bool hasNormals, hasTangents } int m_ShapeVertices_size = a_Stream.ReadInt32(); a_Stream.Position += m_ShapeVertices_size * 40; //vertex positions, normals, tangents & uint index } #endregion #region BlendShapeData and BindPose for 4.3.0 and later else if (version[0] >= 5 || (version[0] == 4 && version[1] >= 3)) { int m_ShapeVertices_size = a_Stream.ReadInt32(); if (m_ShapeVertices_size > 0) { bool stop = true; } a_Stream.Position += m_ShapeVertices_size * 40; //vertex positions, normals, tangents & uint index int shapes_size = a_Stream.ReadInt32(); a_Stream.Position += shapes_size * 12; //uint firstVertex, vertexCount; bool hasNormals, hasTangents int channels_size = a_Stream.ReadInt32(); for (int c = 0; c < channels_size; c++) { string channel_name = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); a_Stream.Position += 12; //uint nameHash; int frameIndex, frameCount } int fullWeights_size = a_Stream.ReadInt32(); a_Stream.Position += fullWeights_size * 4; //floats m_BindPose = new float[a_Stream.ReadInt32()][,]; for (int i = 0; i < m_BindPose.Length; i++) { m_BindPose[i] = new float[4,4] { { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }, { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }, { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }, { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() } }; } int m_BoneNameHashes_size = a_Stream.ReadInt32(); a_Stream.Position += m_BoneNameHashes_size * 4; //uints uint m_RootBoneNameHash = a_Stream.ReadUInt32(); } #endregion #region Index Buffer for 2.6.0 and later if (version[0] >= 3 || (version[0] == 2 && version[1] >= 6)) { m_MeshCompression = a_Stream.ReadByte(); if (version[0] >= 4) { if (version[0] < 5) { uint m_StreamCompression = a_Stream.ReadByte(); } bool m_IsReadable = a_Stream.ReadBoolean(); bool m_KeepVertices = a_Stream.ReadBoolean(); bool m_KeepIndices = a_Stream.ReadBoolean(); } a_Stream.AlignStream(4); int m_IndexBuffer_size = a_Stream.ReadInt32(); if (m_Use16BitIndices) { m_IndexBuffer = new uint[m_IndexBuffer_size / 2]; for (int i = 0; i < m_IndexBuffer_size / 2; i++) { m_IndexBuffer[i] = a_Stream.ReadUInt16(); } a_Stream.AlignStream(4); } else { m_IndexBuffer = new uint[m_IndexBuffer_size / 4]; for (int i = 0; i < m_IndexBuffer_size / 4; i++) { m_IndexBuffer[i] = a_Stream.ReadUInt32(); } a_Stream.AlignStream(4);//untested } } #endregion #region Vertex Buffer for 3.4.2 and earlier if (version[0] < 3 || (version[0] == 3 && version[1] < 5)) { m_VertexCount = a_Stream.ReadInt32(); m_Vertices = new float[m_VertexCount * 3]; for (int v = 0; v < m_VertexCount * 3; v++) { m_Vertices[v] = a_Stream.ReadSingle(); } m_Skin = new List<BoneInfluence>[a_Stream.ReadInt32()]; //m_Skin = new Dictionary<int, float>[a_Stream.ReadInt32()]; for (int s = 0; s < m_Skin.Length; s++) { m_Skin[s] = new List<BoneInfluence>(); for (int i = 0; i < 4; i++) { m_Skin[s].Add(new BoneInfluence() { weight = a_Stream.ReadSingle() }); } for (int i = 0; i < 4; i++) { m_Skin[s][i].boneIndex = a_Stream.ReadInt32(); } /*m_Skin[s] = new Dictionary<int, float>(); float[] weights = new float[4] { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }; for (int i = 0; i < 4; i++) { int boneIndex = a_Stream.ReadInt32(); m_Skin[s][boneIndex] = weights[i]; }*/ } m_BindPose = new float[a_Stream.ReadInt32()][,]; for (int i = 0; i < m_BindPose.Length; i++) { m_BindPose[i] = new float[4, 4] { { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }, { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }, { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }, { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() } }; } int m_UV1_size = a_Stream.ReadInt32(); m_UV1 = new float[m_UV1_size * 2]; for (int v = 0; v < m_UV1_size * 2; v++) { m_UV1[v] = a_Stream.ReadSingle(); } int m_UV2_size = a_Stream.ReadInt32(); m_UV2 = new float[m_UV2_size * 2]; for (int v = 0; v < m_UV2_size * 2; v++) { m_UV2[v] = a_Stream.ReadSingle(); } if (version[0] == 2 && version[1] <= 5) { int m_TangentSpace_size = a_Stream.ReadInt32(); m_Normals = new float[m_TangentSpace_size * 3]; for (int v = 0; v < m_TangentSpace_size; v++) { m_Normals[v * 3] = a_Stream.ReadSingle(); m_Normals[v * 3 + 1] = a_Stream.ReadSingle(); m_Normals[v * 3 + 2] = a_Stream.ReadSingle(); a_Stream.Position += 16; //Vector3f tangent & float handedness } } else //2.6.0 and later { int m_Tangents_size = a_Stream.ReadInt32(); a_Stream.Position += m_Tangents_size * 16; //Vector4f int m_Normals_size = a_Stream.ReadInt32(); m_Normals = new float[m_Normals_size * 3]; for (int v = 0; v < m_Normals_size * 3; v++) { m_Normals[v] = a_Stream.ReadSingle(); } } } #endregion #region Vertex Buffer for 3.5.0 and later else { #region read vertex stream m_Skin = new List<BoneInfluence>[a_Stream.ReadInt32()]; //m_Skin = new Dictionary<int, float>[a_Stream.ReadInt32()]; for (int s = 0; s < m_Skin.Length; s++) { m_Skin[s] = new List<BoneInfluence>(); for (int i = 0; i < 4; i++) { m_Skin[s].Add(new BoneInfluence() { weight = a_Stream.ReadSingle() }); } for (int i = 0; i < 4; i++) { m_Skin[s][i].boneIndex = a_Stream.ReadInt32(); } /*m_Skin[s] = new Dictionary<int, float>(); float[] weights = new float[4] { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }; for (int i = 0; i < 4; i++) { int boneIndex = a_Stream.ReadInt32(); m_Skin[s][boneIndex] = weights[i]; }*/ } if (version[0] == 3 || (version[0] == 4 && version[1] <= 2)) { m_BindPose = new float[a_Stream.ReadInt32()][,]; for (int i = 0; i < m_BindPose.Length; i++) { m_BindPose[i] = new float[4, 4] { { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }, { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }, { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }, { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() } }; } } BitArray m_CurrentChannels = new BitArray(new int[1] { a_Stream.ReadInt32() }); m_VertexCount = a_Stream.ReadInt32(); //int singleStreamStride = 0;//used tor unity 5 int streamCount = 0; #region streams for 3.5.0 - 3.5.7 if (version[0] < 4) { if (m_MeshCompression != 0 && version[2] == 0) //special case not just on platform 9 { a_Stream.Position += 12; } else { m_Streams = new StreamInfo[4]; for (int s = 0; s < 4; s++) { m_Streams[s] = new StreamInfo(); m_Streams[s].channelMask = new BitArray(new int[1] { a_Stream.ReadInt32() }); m_Streams[s].offset = a_Stream.ReadInt32(); m_Streams[s].stride = a_Stream.ReadInt32(); m_Streams[s].align = a_Stream.ReadUInt32(); } } } #endregion #region channels and streams for 4.0.0 and later else { m_Channels = new ChannelInfo[a_Stream.ReadInt32()]; for (int c = 0; c < m_Channels.Length; c++) { m_Channels[c] = new ChannelInfo(); m_Channels[c].stream = a_Stream.ReadByte(); m_Channels[c].offset = a_Stream.ReadByte(); m_Channels[c].format = a_Stream.ReadByte(); m_Channels[c].dimension = a_Stream.ReadByte(); //calculate stride for Unity 5 //singleStreamStride += m_Channels[c].dimension * (4 / (int)Math.Pow(2, m_Channels[c].format)); if (m_Channels[c].stream >= streamCount) { streamCount = m_Channels[c].stream + 1; } } if (version[0] < 5) { m_Streams = new StreamInfo[a_Stream.ReadInt32()]; for (int s = 0; s < m_Streams.Length; s++) { m_Streams[s] = new StreamInfo(); m_Streams[s].channelMask = new BitArray(new int[1] { a_Stream.ReadInt32() }); m_Streams[s].offset = a_Stream.ReadInt32(); m_Streams[s].stride = a_Stream.ReadByte(); m_Streams[s].dividerOp = a_Stream.ReadByte(); m_Streams[s].frequency = a_Stream.ReadUInt16(); } } } #endregion //actual Vertex Buffer byte[] m_DataSize = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_DataSize, 0, m_DataSize.Length); if (version[0] >= 5) //create streams { m_Streams = new StreamInfo[streamCount]; for (int s = 0; s < streamCount; s++) { m_Streams[s] = new StreamInfo(); m_Streams[s].channelMask = new BitArray(new int[1] { 0 }); m_Streams[s].offset = 0; m_Streams[s].stride = 0; foreach (var m_Channel in m_Channels) { if (m_Channel.stream == s) { m_Streams[s].stride += m_Channel.dimension * (4 / (int)Math.Pow(2, m_Channel.format)); } } if (s > 0) { m_Streams[s].offset = m_Streams[s - 1].offset + m_Streams[s - 1].stride * m_VertexCount; //sometimes there are 8 bytes between streams //this is NOT an alignment, even if sometimes it may seem so if (streamCount == 2) { m_Streams[s].offset = m_DataSize.Length - m_Streams[s].stride * m_VertexCount; } else { m_VertexCount = 0; return; } /*var absoluteOffset = a_Stream.Position + 4 + m_Streams[s].offset; if ((absoluteOffset % m_Streams[s].stride) != 0) { m_Streams[s].offset += m_Streams[s].stride - (int)(absoluteOffset % m_Streams[s].stride); }*/ } } } #endregion #region compute FvF int componentByteSize = 0; byte[] componentBytes; float[] componentsArray; #region 4.0.0 and later if (m_Channels != null) { //it is better to loop channels instead of streams //because channels are likely to be sorted by vertex property foreach (var m_Channel in m_Channels) { if (m_Channel.dimension > 0) { var m_Stream = m_Streams[m_Channel.stream]; for (int b = 0; b < 8; b++) { //in the future, try to use only m_CurrentChannels if ((version[0] < 5 && m_Stream.channelMask.Get(b)) || (version[0] >= 5 && m_CurrentChannels.Get(b))) { // in Unity 4.x the colors channel has 1 dimension, as in 1 color with 4 components if (b == 2 && m_Channel.format == 2) { m_Channel.dimension = 4; } componentByteSize = 4 / (int)Math.Pow(2, m_Channel.format); /*switch (m_Channel.format) { case 0: //32bit valueBufferSize = 4; break; case 1: //16bit valueBufferSize = 2; break; case 2: //8bit valueBufferSize = 1; m_Channel.dimension = 4;//in older versions this is 1, as in 1 color with 4 components break; }*/ componentBytes = new byte[componentByteSize]; componentsArray = new float[m_VertexCount * m_Channel.dimension]; for (int v = 0; v < m_VertexCount; v++) { int vertexOffset = m_Stream.offset + m_Channel.offset + m_Stream.stride * v; for (int d = 0; d < m_Channel.dimension; d++) { int componentOffset = vertexOffset + componentByteSize * d; Buffer.BlockCopy(m_DataSize, componentOffset, componentBytes, 0, componentByteSize); componentsArray[v * m_Channel.dimension + d] = bytesToFloat(componentBytes); } } switch (b) { case 0: m_Vertices = componentsArray; break; case 1: m_Normals = componentsArray; break; case 2: m_Colors = componentsArray; break; case 3: m_UV1 = componentsArray; break; case 4: m_UV2 = componentsArray; break; case 5: if (version[0] == 5) { m_UV3 = componentsArray; } else { m_Tangents = componentsArray; } break; case 6: m_UV4 = componentsArray; break; case 7: m_Tangents = componentsArray; break; } m_Stream.channelMask.Set(b, false); m_CurrentChannels.Set(b, false); componentBytes = null; componentsArray = null; break; //go to next channel } } } } } #endregion #region 3.5.0 - 3.5.7 else if (m_Streams != null) { foreach (var m_Stream in m_Streams) { //a stream may have multiple vertex components but without channels there are no offsets, so I assume all vertex properties are in order //Unity 3.5.x only uses floats, and that's probably why channels were introduced in Unity 4 ChannelInfo m_Channel = new ChannelInfo();//create my own channel so I can use the same methods m_Channel.offset = 0; for (int b = 0; b < 6; b++) { if (m_Stream.channelMask.Get(b)) { switch (b) { case 0: case 1: componentByteSize = 4; m_Channel.dimension = 3; break; case 2: componentByteSize = 1; m_Channel.dimension = 4; break; case 3: case 4: componentByteSize = 4; m_Channel.dimension = 2; break; case 5: componentByteSize = 4; m_Channel.dimension = 4; break; } componentBytes = new byte[componentByteSize]; componentsArray = new float[m_VertexCount * m_Channel.dimension]; for (int v = 0; v < m_VertexCount; v++) { int vertexOffset = m_Stream.offset + m_Channel.offset + m_Stream.stride * v; for (int d = 0; d < m_Channel.dimension; d++) { int m_DataSizeOffset = vertexOffset + componentByteSize * d; Buffer.BlockCopy(m_DataSize, m_DataSizeOffset, componentBytes, 0, componentByteSize); componentsArray[v * m_Channel.dimension + d] = bytesToFloat(componentBytes); } } switch (b) { case 0: m_Vertices = componentsArray; break; case 1: m_Normals = componentsArray; break; case 2: m_Colors = componentsArray; break; case 3: m_UV1 = componentsArray; break; case 4: m_UV2 = componentsArray; break; case 5: m_Tangents = componentsArray; break; } m_Channel.offset += (byte)(m_Channel.dimension * componentByteSize); //safe to cast as byte because strides larger than 255 are unlikely m_Stream.channelMask.Set(b, false); componentBytes = null; componentsArray = null; } } } } #endregion #endregion } #endregion #region Compressed Mesh data for 2.6.0 and later - 160 bytes if (version[0] >= 3 || (version[0] == 2 && version[1] >= 6)) { //remember there can be combinations of packed and regular vertex properties #region m_Vertices PackedBitVector m_Vertices_Packed = new PackedBitVector(); m_Vertices_Packed.m_NumItems = a_Stream.ReadInt32(); m_Vertices_Packed.m_Range = a_Stream.ReadSingle(); m_Vertices_Packed.m_Start = a_Stream.ReadSingle(); m_Vertices_Packed.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_Vertices_Packed.m_Data, 0, m_Vertices_Packed.m_Data.Length); a_Stream.AlignStream(4); m_Vertices_Packed.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment if (m_Vertices_Packed.m_NumItems > 0) { m_VertexCount = m_Vertices_Packed.m_NumItems / 3; uint[] m_Vertices_Unpacked = UnpackBitVector(m_Vertices_Packed); int bitmax = 0;//used to convert int value to float for (int b = 0; b < m_Vertices_Packed.m_BitSize; b++) { bitmax |= (1 << b); } m_Vertices = new float[m_Vertices_Packed.m_NumItems]; for (int v = 0; v < m_Vertices_Packed.m_NumItems; v++) { m_Vertices[v] = (float)((double)m_Vertices_Unpacked[v] / bitmax) * m_Vertices_Packed.m_Range + m_Vertices_Packed.m_Start; } } #endregion #region m_UV PackedBitVector m_UV_Packed = new PackedBitVector(); //contains all channels m_UV_Packed.m_NumItems = a_Stream.ReadInt32(); m_UV_Packed.m_Range = a_Stream.ReadSingle(); m_UV_Packed.m_Start = a_Stream.ReadSingle(); m_UV_Packed.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_UV_Packed.m_Data, 0, m_UV_Packed.m_Data.Length); a_Stream.AlignStream(4); m_UV_Packed.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment if (m_UV_Packed.m_NumItems > 0 && (bool)Properties.Settings.Default["exportUVs"]) { uint[] m_UV_Unpacked = UnpackBitVector(m_UV_Packed); int bitmax = 0; for (int b = 0; b < m_UV_Packed.m_BitSize; b++) { bitmax |= (1 << b); } m_UV1 = new float[m_VertexCount * 2]; for (int v = 0; v < m_VertexCount * 2; v++) { m_UV1[v] = (float)((double)m_UV_Unpacked[v] / bitmax) * m_UV_Packed.m_Range + m_UV_Packed.m_Start; } if (m_UV_Packed.m_NumItems >= m_VertexCount * 4) { m_UV2 = new float[m_VertexCount * 2]; for (uint v = 0; v < m_VertexCount * 2; v++) { m_UV2[v] = (float)((double)m_UV_Unpacked[v + m_VertexCount * 2] / bitmax) * m_UV_Packed.m_Range + m_UV_Packed.m_Start; } if (m_UV_Packed.m_NumItems >= m_VertexCount * 6) { m_UV3 = new float[m_VertexCount * 2]; for (uint v = 0; v < m_VertexCount * 2; v++) { m_UV3[v] = (float)((double)m_UV_Unpacked[v + m_VertexCount * 4] / bitmax) * m_UV_Packed.m_Range + m_UV_Packed.m_Start; } if (m_UV_Packed.m_NumItems == m_VertexCount * 8) { m_UV4 = new float[m_VertexCount * 2]; for (uint v = 0; v < m_VertexCount * 2; v++) { m_UV4[v] = (float)((double)m_UV_Unpacked[v + m_VertexCount * 6] / bitmax) * m_UV_Packed.m_Range + m_UV_Packed.m_Start; } } } } } #endregion #region m_BindPose if (version[0] < 5) { PackedBitVector m_BindPoses_Packed = new PackedBitVector(); m_BindPoses_Packed.m_NumItems = a_Stream.ReadInt32(); m_BindPoses_Packed.m_Range = a_Stream.ReadSingle(); m_BindPoses_Packed.m_Start = a_Stream.ReadSingle(); m_BindPoses_Packed.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_BindPoses_Packed.m_Data, 0, m_BindPoses_Packed.m_Data.Length); a_Stream.AlignStream(4); m_BindPoses_Packed.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment if (m_BindPoses_Packed.m_NumItems > 0 && (bool)Properties.Settings.Default["exportDeformers"]) { uint[] m_BindPoses_Unpacked = UnpackBitVector(m_BindPoses_Packed); int bitmax = 0;//used to convert int value to float for (int b = 0; b < m_BindPoses_Packed.m_BitSize; b++) { bitmax |= (1 << b); } m_BindPose = new float[m_BindPoses_Packed.m_NumItems / 16][,]; for (int i = 0; i < m_BindPose.Length; i++) { m_BindPose[i] = new float[4, 4]; for (int j = 0; j < 4; j++) { for (int k = 0; k < 4; k++) { m_BindPose[i][j,k] = (float)((double)m_BindPoses_Unpacked[i * 16 + j * 4 + k] / bitmax) * m_BindPoses_Packed.m_Range + m_BindPoses_Packed.m_Start; } } } } } #endregion PackedBitVector m_Normals_Packed = new PackedBitVector(); m_Normals_Packed.m_NumItems = a_Stream.ReadInt32(); m_Normals_Packed.m_Range = a_Stream.ReadSingle(); m_Normals_Packed.m_Start = a_Stream.ReadSingle(); m_Normals_Packed.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_Normals_Packed.m_Data, 0, m_Normals_Packed.m_Data.Length); a_Stream.AlignStream(4); m_Normals_Packed.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment PackedBitVector m_Tangents_Packed = new PackedBitVector(); m_Tangents_Packed.m_NumItems = a_Stream.ReadInt32(); m_Tangents_Packed.m_Range = a_Stream.ReadSingle(); m_Tangents_Packed.m_Start = a_Stream.ReadSingle(); m_Tangents_Packed.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_Tangents_Packed.m_Data, 0, m_Tangents_Packed.m_Data.Length); a_Stream.AlignStream(4); m_Tangents_Packed.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment PackedBitVector m_Weights = new PackedBitVector(); m_Weights.m_NumItems = a_Stream.ReadInt32(); m_Weights.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_Weights.m_Data, 0, m_Weights.m_Data.Length); a_Stream.AlignStream(4); m_Weights.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment #region m_Normals PackedBitVector m_NormalSigns_packed = new PackedBitVector(); m_NormalSigns_packed.m_NumItems = a_Stream.ReadInt32(); m_NormalSigns_packed.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_NormalSigns_packed.m_Data, 0, m_NormalSigns_packed.m_Data.Length); a_Stream.AlignStream(4); m_NormalSigns_packed.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment if (m_Normals_Packed.m_NumItems > 0 && (bool)Properties.Settings.Default["exportNormals"]) { uint[] m_Normals_Unpacked = UnpackBitVector(m_Normals_Packed); uint[] m_NormalSigns = UnpackBitVector(m_NormalSigns_packed); int bitmax = 0; for (int b = 0; b < m_Normals_Packed.m_BitSize; b++) { bitmax |= (1 << b); } m_Normals = new float[m_Normals_Packed.m_NumItems / 2 * 3]; for (int v = 0; v < m_Normals_Packed.m_NumItems / 2; v++) { m_Normals[v * 3] = (float)((double)m_Normals_Unpacked[v * 2] / bitmax) * m_Normals_Packed.m_Range + m_Normals_Packed.m_Start; m_Normals[v * 3 + 1] = (float)((double)m_Normals_Unpacked[v * 2 + 1] / bitmax) * m_Normals_Packed.m_Range + m_Normals_Packed.m_Start; m_Normals[v * 3 + 2] = (float)Math.Sqrt(1 - m_Normals[v * 3] * m_Normals[v * 3] - m_Normals[v * 3 + 1] * m_Normals[v * 3 + 1]); if (m_NormalSigns[v] == 0) { m_Normals[v * 3 + 2] *= -1; } } } #endregion #region m_Tangents PackedBitVector m_TangentSigns_packed = new PackedBitVector(); m_TangentSigns_packed.m_NumItems = a_Stream.ReadInt32(); m_TangentSigns_packed.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_TangentSigns_packed.m_Data, 0, m_TangentSigns_packed.m_Data.Length); a_Stream.AlignStream(4); m_TangentSigns_packed.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment if (m_Tangents_Packed.m_NumItems > 0 && (bool)Properties.Settings.Default["exportTangents"]) { uint[] m_Tangents_Unpacked = UnpackBitVector(m_Tangents_Packed); uint[] m_TangentSigns = UnpackBitVector(m_TangentSigns_packed); int bitmax = 0; for (int b = 0; b < m_Tangents_Packed.m_BitSize; b++) { bitmax |= (1 << b); } m_Tangents = new float[m_Tangents_Packed.m_NumItems / 2 * 3]; for (int v = 0; v < m_Tangents_Packed.m_NumItems / 2; v++) { m_Tangents[v * 3] = (float)((double)m_Tangents_Unpacked[v * 2] / bitmax) * m_Tangents_Packed.m_Range + m_Tangents_Packed.m_Start; m_Tangents[v * 3 + 1] = (float)((double)m_Tangents_Unpacked[v * 2 + 1] / bitmax) * m_Tangents_Packed.m_Range + m_Tangents_Packed.m_Start; m_Tangents[v * 3 + 2] = (float)Math.Sqrt(1 - m_Tangents[v * 3] * m_Tangents[v * 3] - m_Tangents[v * 3 + 1] * m_Tangents[v * 3 + 1]); if (m_TangentSigns[v] == 0) { m_Tangents[v * 3 + 2] *= -1; } } } #endregion #region m_FloatColors if (version[0] >= 5) { PackedBitVector m_FloatColors = new PackedBitVector(); m_FloatColors.m_NumItems = a_Stream.ReadInt32(); m_FloatColors.m_Range = a_Stream.ReadSingle(); m_FloatColors.m_Start = a_Stream.ReadSingle(); m_FloatColors.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_FloatColors.m_Data, 0, m_FloatColors.m_Data.Length); a_Stream.AlignStream(4); m_FloatColors.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment if (m_FloatColors.m_NumItems > 0 && (bool)Properties.Settings.Default["exportColors"]) { uint[] m_FloatColors_Unpacked = UnpackBitVector(m_FloatColors); int bitmax = 0; for (int b = 0; b < m_FloatColors.m_BitSize; b++) { bitmax |= (1 << b); } m_Colors = new float[m_FloatColors.m_NumItems]; for (int v = 0; v < m_FloatColors.m_NumItems; v++) { m_Colors[v] = (float)m_FloatColors_Unpacked[v] / bitmax * m_FloatColors.m_Range + m_FloatColors.m_Start; } } } #endregion #region m_Skin PackedBitVector m_BoneIndices = new PackedBitVector(); m_BoneIndices.m_NumItems = a_Stream.ReadInt32(); m_BoneIndices.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_BoneIndices.m_Data, 0, m_BoneIndices.m_Data.Length); a_Stream.AlignStream(4); m_BoneIndices.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment //how the hell does this work?? if (m_BoneIndices.m_NumItems > 0 && m_BoneIndices.m_NumItems == m_Weights.m_NumItems && (bool)Properties.Settings.Default["exportDeformers"]) { uint[] m_Weights_Unpacked = UnpackBitVector(m_Weights); int bitmax = 0; for (int b = 0; b < m_Weights.m_BitSize; b++) { bitmax |= (1 << b); } uint[] m_BoneIndices_Unpacked = UnpackBitVector(m_BoneIndices); m_Skin = new List<BoneInfluence>[m_BoneIndices.m_NumItems / 4]; for (int s = 0; s < m_Skin.Length; s++) { m_Skin[s] = new List<BoneInfluence>(); for (int i = 0; i < 4; i++) { m_Skin[s].Add(new BoneInfluence() { weight = (float)((double)m_Weights_Unpacked[s * 4 + i] / bitmax), boneIndex = (int)m_BoneIndices_Unpacked[s * 4 + i] }); } } } #endregion PackedBitVector m_Triangles = new PackedBitVector(); m_Triangles.m_NumItems = a_Stream.ReadInt32(); m_Triangles.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_Triangles.m_Data, 0, m_Triangles.m_Data.Length); a_Stream.AlignStream(4); m_Triangles.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment if (m_Triangles.m_NumItems > 0) { m_IndexBuffer = UnpackBitVector(m_Triangles); } } #endregion #region Colors & Collision triangles for 3.4.2 and earlier if (version[0] <= 2 || (version[0] == 3 && version[1] <= 4)) // { a_Stream.Position += 24; //Axis-Aligned Bounding Box int m_Colors_size = a_Stream.ReadInt32(); m_Colors = new float[m_Colors_size * 4]; for (int v = 0; v < m_Colors_size * 4; v++) { m_Colors[v] = (float)(a_Stream.ReadByte()) / 0xFF; } int m_CollisionTriangles_size = a_Stream.ReadInt32(); a_Stream.Position += m_CollisionTriangles_size * 4; //UInt32 indices int m_CollisionVertexCount = a_Stream.ReadInt32(); } #endregion #region Compressed colors & Local AABB for 3.5.0 to 4.x.x else //vertex colors are either in streams or packed bits { if (version[0] < 5) { PackedBitVector m_Colors_Packed = new PackedBitVector(); m_Colors_Packed.m_NumItems = a_Stream.ReadInt32(); m_Colors_Packed.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_Colors_Packed.m_Data, 0, m_Colors_Packed.m_Data.Length); a_Stream.AlignStream(4); m_Colors_Packed.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment if (m_Colors_Packed.m_NumItems > 0) { if (m_Colors_Packed.m_BitSize == 32) { //4 x 8bit color channels m_Colors = new float[m_Colors_Packed.m_Data.Length]; for (int v = 0; v < m_Colors_Packed.m_Data.Length; v++) { m_Colors[v] = (float)m_Colors_Packed.m_Data[v] / 0xFF; } } else //not tested { uint[] m_Colors_Unpacked = UnpackBitVector(m_Colors_Packed); int bitmax = 0;//used to convert int value to float for (int b = 0; b < m_Colors_Packed.m_BitSize; b++) { bitmax |= (1 << b); } m_Colors = new float[m_Colors_Packed.m_NumItems]; for (int v = 0; v < m_Colors_Packed.m_NumItems; v++) { m_Colors[v] = (float)m_Colors_Unpacked[v] / bitmax; } } } } else { uint m_UVInfo = a_Stream.ReadUInt32(); } a_Stream.Position += 24; //Axis-Aligned Bounding Box } #endregion int m_MeshUsageFlags = a_Stream.ReadInt32(); if (version[0] >= 5) { //int m_BakedConvexCollisionMesh = a_Stream.ReadInt32(); //a_Stream.Position += m_BakedConvexCollisionMesh; //int m_BakedTriangleCollisionMesh = a_Stream.ReadInt32(); //a_Stream.Position += m_BakedConvexCollisionMesh; } #region Build face indices for (int s = 0; s < m_SubMeshes_size; s++) { uint firstIndex = m_SubMeshes[s].firstByte / 2; if (!m_Use16BitIndices) { firstIndex /= 2; } if (m_SubMeshes[s].topology == 0) { for (int i = 0; i < m_SubMeshes[s].indexCount / 3; i++) { m_Indices.Add(m_IndexBuffer[firstIndex + i * 3]); m_Indices.Add(m_IndexBuffer[firstIndex + i * 3 + 1]); m_Indices.Add(m_IndexBuffer[firstIndex + i * 3 + 2]); m_materialIDs.Add(s); } } else { for (int i = 0; i < m_SubMeshes[s].indexCount - 2; i++) { uint fa = m_IndexBuffer[firstIndex + i]; uint fb = m_IndexBuffer[firstIndex + i + 1]; uint fc = m_IndexBuffer[firstIndex + i + 2]; if ((fa!=fb) && (fa!=fc) && (fc!=fb)) { m_Indices.Add(fa); if ((i % 2) == 0) { m_Indices.Add(fb); m_Indices.Add(fc); } else { m_Indices.Add(fc); m_Indices.Add(fb); } m_materialIDs.Add(s); } } } } #endregion }
public Texture2D(AssetPreloadData preloadData, bool readSwitch) { AssetsFile sourceFile = preloadData.sourceFile; EndianStream stream = preloadData.sourceFile.a_Stream; stream.Position = preloadData.Offset; if (sourceFile.platform == -2) { uint num = stream.ReadUInt32(); PPtr ptr = sourceFile.ReadPPtr(); PPtr ptr2 = sourceFile.ReadPPtr(); } this.m_Name = stream.ReadAlignedString(stream.ReadInt32()); this.m_Width = stream.ReadInt32(); this.m_Height = stream.ReadInt32(); this.m_CompleteImageSize = stream.ReadInt32(); this.m_TextureFormat = stream.ReadInt32(); this.getExtension(preloadData, this.m_TextureFormat); if (this.m_Name != "") { preloadData.Name = this.m_Name; } else { preloadData.Name = preloadData.TypeString + " #" + preloadData.uniqueID; } if ((sourceFile.version[0] < 5) || ((sourceFile.version[0] == 5) && (sourceFile.version[1] < 2))) { this.m_MipMap = stream.ReadBoolean(); } else { this.dwFlags += 0x20000; this.dwMipMapCount = stream.ReadInt32(); this.dwCaps += 0x400008; } this.m_IsReadable = stream.ReadBoolean(); this.m_ReadAllowed = stream.ReadBoolean(); stream.AlignStream(4); this.m_ImageCount = stream.ReadInt32(); this.m_TextureDimension = stream.ReadInt32(); this.m_FilterMode = stream.ReadInt32(); this.m_Aniso = stream.ReadInt32(); this.m_MipBias = stream.ReadSingle(); this.m_WrapMode = stream.ReadInt32(); if (sourceFile.version[0] >= 3) { this.m_LightmapFormat = stream.ReadInt32(); if ((sourceFile.version[0] >= 4) || (sourceFile.version[1] >= 5)) { this.m_ColorSpace = stream.ReadInt32(); } } this.image_data_size = stream.ReadInt32(); if (this.m_MipMap) { this.dwFlags += 0x20000; this.dwMipMapCount = Convert.ToInt32((double)(Math.Log((double)Math.Max(this.m_Width, this.m_Height)) / Math.Log(2.0))); this.dwCaps += 0x400008; } if (!readSwitch) { string[] textArray1 = new string[] { "Width: ", this.m_Width.ToString(), "\nHeight: ", this.m_Height.ToString(), "\nFormat: " }; preloadData.InfoText = string.Concat(textArray1); preloadData.exportSize = this.image_data_size; switch (this.m_TextureFormat) { case 1: preloadData.InfoText = preloadData.InfoText + "Alpha8"; preloadData.extension = ".dds"; preloadData.exportSize += 0x80; goto Label_0E7B; case 2: preloadData.InfoText = preloadData.InfoText + "ARGB 4.4.4.4"; preloadData.extension = ".dds"; preloadData.exportSize += 0x80; goto Label_0E7B; case 3: preloadData.InfoText = preloadData.InfoText + "BGR 8.8.8"; preloadData.extension = ".dds"; preloadData.exportSize += 0x80; goto Label_0E7B; case 4: preloadData.InfoText = preloadData.InfoText + "GRAB 8.8.8.8"; preloadData.extension = ".dds"; preloadData.exportSize += 0x80; goto Label_0E7B; case 5: preloadData.InfoText = preloadData.InfoText + "BGRA 8.8.8.8"; preloadData.extension = ".dds"; preloadData.exportSize += 0x80; goto Label_0E7B; case 7: preloadData.InfoText = preloadData.InfoText + "RGB 5.6.5"; preloadData.extension = ".dds"; preloadData.exportSize += 0x80; goto Label_0E7B; case 10: preloadData.InfoText = preloadData.InfoText + "DXT1"; preloadData.extension = ".dds"; preloadData.exportSize += 0x80; goto Label_0E7B; case 12: preloadData.InfoText = preloadData.InfoText + "DXT5"; preloadData.extension = ".dds"; preloadData.exportSize += 0x80; goto Label_0E7B; case 13: preloadData.InfoText = preloadData.InfoText + "RGBA 4.4.4.4"; preloadData.extension = ".dds"; preloadData.exportSize += 0x80; goto Label_0E7B; case 0x1c: preloadData.InfoText = preloadData.InfoText + "DXT1 Crunched"; preloadData.extension = ".crn"; goto Label_0E7B; case 0x1d: preloadData.InfoText = preloadData.InfoText + "DXT5 Crunched"; preloadData.extension = ".crn"; goto Label_0E7B; case 30: preloadData.InfoText = preloadData.InfoText + "PVRTC_RGB2"; preloadData.extension = ".pvr"; preloadData.exportSize += 0x34; goto Label_0E7B; case 0x1f: preloadData.InfoText = preloadData.InfoText + "PVRTC_RGBA2"; preloadData.extension = ".pvr"; preloadData.exportSize += 0x34; goto Label_0E7B; case 0x20: preloadData.InfoText = preloadData.InfoText + "PVRTC_RGB4"; preloadData.extension = ".pvr"; preloadData.exportSize += 0x34; goto Label_0E7B; case 0x21: preloadData.InfoText = preloadData.InfoText + "PVRTC_RGBA4"; preloadData.extension = ".pvr"; preloadData.exportSize += 0x34; goto Label_0E7B; case 0x22: preloadData.InfoText = preloadData.InfoText + "ETC_RGB4"; preloadData.extension = ".pvr"; preloadData.exportSize += 0x34; goto Label_0E7B; } preloadData.InfoText = preloadData.InfoText + "unknown"; preloadData.extension = ".tex"; } else { this.image_data = new byte[this.image_data_size]; stream.Read(this.image_data, 0, this.image_data_size); switch (this.m_TextureFormat) { case 1: this.dwFlags2 = 2; this.dwRGBBitCount = 8; this.dwRBitMask = 0; this.dwGBitMask = 0; this.dwBBitMask = 0; this.dwABitMask = 0xff; return; case 2: if (sourceFile.platform != 11) { if (sourceFile.platform == 13) { for (int j = 0; j < (this.image_data_size / 2); j++) { byte[] buffer1 = new byte[] { this.image_data[j * 2], this.image_data[(j * 2) + 1], this.image_data[j * 2], this.image_data[(j * 2) + 1] }; byte[] bytes = BitConverter.GetBytes((int)(BitConverter.ToInt32(buffer1, 0) >> 4)); this.image_data[j * 2] = bytes[0]; this.image_data[(j * 2) + 1] = bytes[1]; } } break; } for (int i = 0; i < (this.image_data_size / 2); i++) { byte num4 = this.image_data[i * 2]; this.image_data[i * 2] = this.image_data[(i * 2) + 1]; this.image_data[(i * 2) + 1] = num4; } break; case 3: for (int k = 0; k < (this.image_data_size / 3); k++) { byte num7 = this.image_data[k * 3]; this.image_data[k * 3] = this.image_data[(k * 3) + 2]; this.image_data[(k * 3) + 2] = num7; } this.dwFlags2 = 0x40; this.dwRGBBitCount = 0x18; this.dwRBitMask = 0xff0000; this.dwGBitMask = 0xff00; this.dwBBitMask = 0xff; this.dwABitMask = 0; return; case 4: for (int m = 0; m < (this.image_data_size / 4); m++) { byte num9 = this.image_data[m * 4]; this.image_data[m * 4] = this.image_data[(m * 4) + 2]; this.image_data[(m * 4) + 2] = num9; } this.dwFlags2 = 0x41; this.dwRGBBitCount = 0x20; this.dwRBitMask = 0xff0000; this.dwGBitMask = 0xff00; this.dwBBitMask = 0xff; this.dwABitMask = -16777216; return; case 5: for (int n = 0; n < (this.image_data_size / 4); n++) { byte num11 = this.image_data[n * 4]; byte num12 = this.image_data[(n * 4) + 1]; this.image_data[n * 4] = this.image_data[(n * 4) + 3]; this.image_data[(n * 4) + 1] = this.image_data[(n * 4) + 2]; this.image_data[(n * 4) + 2] = num12; this.image_data[(n * 4) + 3] = num11; } this.dwFlags2 = 0x41; this.dwRGBBitCount = 0x20; this.dwRBitMask = 0xff0000; this.dwGBitMask = 0xff00; this.dwBBitMask = 0xff; this.dwABitMask = -16777216; return; case 6: case 8: case 9: case 11: case 0x1c: case 0x1d: return; case 7: if (sourceFile.platform == 11) { for (int num13 = 0; num13 < (this.image_data_size / 2); num13++) { byte num14 = this.image_data[num13 * 2]; this.image_data[num13 * 2] = this.image_data[(num13 * 2) + 1]; this.image_data[(num13 * 2) + 1] = num14; } } this.dwFlags2 = 0x40; this.dwRGBBitCount = 0x10; this.dwRBitMask = 0xf800; this.dwGBitMask = 0x7e0; this.dwBBitMask = 0x1f; this.dwABitMask = 0; return; case 10: if (sourceFile.platform == 11) { for (int num15 = 0; num15 < (this.image_data_size / 2); num15++) { byte num16 = this.image_data[num15 * 2]; this.image_data[num15 * 2] = this.image_data[(num15 * 2) + 1]; this.image_data[(num15 * 2) + 1] = num16; } } if (this.m_MipMap) { this.dwPitchOrLinearSize = (this.m_Height * this.m_Width) / 2; } this.dwFlags2 = 4; this.dwFourCC = 0x31545844; this.dwRGBBitCount = 0; this.dwRBitMask = 0; this.dwGBitMask = 0; this.dwBBitMask = 0; this.dwABitMask = 0; return; case 12: if (sourceFile.platform == 11) { for (int num17 = 0; num17 < (this.image_data_size / 2); num17++) { byte num18 = this.image_data[num17 * 2]; this.image_data[num17 * 2] = this.image_data[(num17 * 2) + 1]; this.image_data[(num17 * 2) + 1] = num18; } } if (this.m_MipMap) { this.dwPitchOrLinearSize = (this.m_Height * this.m_Width) / 2; } this.dwFlags2 = 4; this.dwFourCC = 0x35545844; this.dwRGBBitCount = 0; this.dwRBitMask = 0; this.dwGBitMask = 0; this.dwBBitMask = 0; this.dwABitMask = 0; return; case 13: for (int num19 = 0; num19 < (this.image_data_size / 2); num19++) { byte[] buffer3 = new byte[] { this.image_data[num19 * 2], this.image_data[(num19 * 2) + 1], this.image_data[num19 * 2], this.image_data[(num19 * 2) + 1] }; byte[] buffer2 = BitConverter.GetBytes((int)(BitConverter.ToInt32(buffer3, 0) >> 4)); this.image_data[num19 * 2] = buffer2[0]; this.image_data[(num19 * 2) + 1] = buffer2[1]; } this.dwFlags2 = 0x41; this.dwRGBBitCount = 0x10; this.dwRBitMask = 0xf00; this.dwGBitMask = 240; this.dwBBitMask = 15; this.dwABitMask = 0xf000; return; case 30: this.pvrPixelFormat = 0L; return; case 0x1f: this.pvrPixelFormat = 1L; return; case 0x20: this.pvrPixelFormat = 2L; return; case 0x21: this.pvrPixelFormat = 3L; return; case 0x22: this.pvrPixelFormat = 0x16L; return; default: return; } this.dwFlags2 = 0x41; this.dwRGBBitCount = 0x10; this.dwRBitMask = 0xf00; this.dwGBitMask = 240; this.dwBBitMask = 15; this.dwABitMask = 0xf000; return; } Label_0E7B: switch (this.m_FilterMode) { case 0: preloadData.InfoText = preloadData.InfoText + "\nFilter Mode: Point "; break; case 1: preloadData.InfoText = preloadData.InfoText + "\nFilter Mode: Bilinear "; break; case 2: preloadData.InfoText = preloadData.InfoText + "\nFilter Mode: Trilinear "; break; } AssetPreloadData data = preloadData; string[] textArray2 = new string[] { data.InfoText, "\nAnisotropic level: ", this.m_Aniso.ToString(), "\nMip map bias: ", this.m_MipBias.ToString() }; data.InfoText = string.Concat(textArray2); switch (this.m_WrapMode) { case 0: preloadData.InfoText = preloadData.InfoText + "\nWrap mode: Repeat"; break; case 1: preloadData.InfoText = preloadData.InfoText + "\nWrap mode: Clamp"; break; } }
public static void WriteFile(Unity_Studio.EndianStream stream, string file, int offset, int size, Ogg ogg) { // Write to disk using (BinaryWriter writer = new BinaryWriter(File.Open(file, FileMode.Create))) { // Only support header CRC 3605052372 for now OggVorbisHeader head = new OggVorbisHeader(); HeaderPacketBuilder hpb = new HeaderPacketBuilder(); CodecSetup cSetup = new CodecSetup(null); cSetup.BlockSizes[0] = 256; cSetup.BlockSizes[1] = 2048; VorbisInfo info = new VorbisInfo(cSetup, (int)ogg.channels, (int)ogg.frequency, 0); OggPacket headerInfo = hpb.BuildInfoPacket(info); Comments comments = new Comments(); if (ogg.loopStart > 0 && ogg.loopEnd > 0) { comments.AddTag("LOOP_START", ogg.loopStart.ToString()); comments.AddTag("LOOP_END", ogg.loopEnd.ToString()); } OggPacket headerComment = hpb.BuildCommentsPacket(comments); OggPacket headerSetup = new OggPacket(OggVorbisHeader.GetHeader(ogg.crc32), false, 0, 2); OggStream output = new OggStream(1); output.PacketIn(headerInfo); output.PacketIn(headerComment); output.PacketIn(headerSetup); stream.Position = offset; UInt16 packetSize = stream.ReadUInt16(); int prevPacketNo = 2; int prevGranulePos = 0; while (packetSize > 0) { OggPacket packet = new OggPacket(stream.ReadBytes(packetSize), false, 0, prevPacketNo + 1); byte firstByte = packet.PacketData[0]; // OK for stereo int granuleSize = 128; if ((firstByte & 2) != 0) { granuleSize = 1024; } if (ogg.channels == 1) { granuleSize /= 4; } packet.GranulePosition = prevGranulePos + granuleSize; if (stream.Position + 2 < offset + size) { packetSize = stream.ReadUInt16(); } else { packetSize = 0; } packet.EndOfStream = packetSize == 0; prevGranulePos = packet.GranulePosition; prevPacketNo = packet.PacketNumber; output.PacketIn(packet); OggPage page = null; if (output.PageOut(out page, true)) { writer.Write(page.Header); writer.Write(page.Body); } } //float vorbis_quality = ((ogg.quality - 1) + (ogg.quality - 100) * 0.1f) / 99.0f; //VorbisInfo.InitVariableBitRate(ogg.channels, ogg.frequency, ogg.) //writer.Write(); writer.Close(); } }
private void ReadFormat6(EndianStream b_Stream, bool padding = false) { var bundleSize = b_Stream.ReadInt64(); int compressedSize = b_Stream.ReadInt32(); int uncompressedSize = b_Stream.ReadInt32(); int flag = b_Stream.ReadInt32(); if (padding) { b_Stream.ReadByte(); } byte[] blocksInfoBytes; if ((flag & 0x80) != 0)//at end of file { var position = b_Stream.Position; b_Stream.Position = b_Stream.BaseStream.Length - compressedSize; blocksInfoBytes = b_Stream.ReadBytes(compressedSize); b_Stream.Position = position; } else { blocksInfoBytes = b_Stream.ReadBytes(compressedSize); } EndianStream blocksInfo; switch (flag & 0x3F) { default: //None { blocksInfo = new EndianStream(new MemoryStream(blocksInfoBytes), EndianType.BigEndian); break; } case 1: //LZMA { blocksInfo = new EndianStream(SevenZipHelper.StreamDecompress(new MemoryStream(blocksInfoBytes)), EndianType.BigEndian); break; } case 2: //LZ4 case 3: //LZ4HC { byte[] uncompressedBytes = new byte[uncompressedSize]; using (var mstream = new MemoryStream(blocksInfoBytes)) { var decoder = new Lz4DecoderStream(mstream); decoder.Read(uncompressedBytes, 0, uncompressedSize); decoder.Dispose(); } blocksInfo = new EndianStream(new MemoryStream(uncompressedBytes), EndianType.BigEndian); break; } //case 4:LZHAM? } using (blocksInfo) { blocksInfo.Position = 0x10; int blockcount = blocksInfo.ReadInt32(); EndianStream assetsData; var assetsDataStream = new MemoryStream(); for (int i = 0; i < blockcount; i++) { uncompressedSize = blocksInfo.ReadInt32(); compressedSize = blocksInfo.ReadInt32(); flag = blocksInfo.ReadInt16(); var compressedBytes = b_Stream.ReadBytes(compressedSize); switch (flag & 0x3F) { default: //None { assetsDataStream.Write(compressedBytes, 0, compressedSize); break; } case 1: //LZMA { var uncompressedBytes = new byte[uncompressedSize]; using (var mstream = new MemoryStream(compressedBytes)) { var decoder = SevenZipHelper.StreamDecompress(mstream, uncompressedSize); decoder.Read(uncompressedBytes, 0, uncompressedSize); decoder.Dispose(); } assetsDataStream.Write(uncompressedBytes, 0, uncompressedSize); break; } case 2: //LZ4 case 3: //LZ4HC { var uncompressedBytes = new byte[uncompressedSize]; using (var mstream = new MemoryStream(compressedBytes)) { var decoder = new Lz4DecoderStream(mstream); decoder.Read(uncompressedBytes, 0, uncompressedSize); decoder.Dispose(); } assetsDataStream.Write(uncompressedBytes, 0, uncompressedSize); break; } //case 4:LZHAM? } } assetsData = new EndianStream(assetsDataStream, EndianType.BigEndian); using (assetsData) { var entryinfo_count = blocksInfo.ReadInt32(); for (int i = 0; i < entryinfo_count; i++) { var memFile = new MemoryAssetsFile(); var entryinfo_offset = blocksInfo.ReadInt64(); var entryinfo_size = blocksInfo.ReadInt64(); var unknown = blocksInfo.ReadInt32(); memFile.fileName = blocksInfo.ReadStringToNull(); assetsData.Position = entryinfo_offset; var buffer = new byte[entryinfo_size]; assetsData.Read(buffer, 0, (int)entryinfo_size); memFile.memStream = new MemoryStream(buffer); MemoryAssetsFileList.Add(memFile); } } } }
public static void Write(byte[] data, string file) { Unity_Studio.EndianStream stream = new Unity_Studio.EndianStream(new System.IO.MemoryStream(data), Unity_Studio.EndianType.LittleEndian); // Because constructor is broken stream.endian = Unity_Studio.EndianType.LittleEndian; string magic = stream.ReadASCII(4); if (!magic.Equals("FSB5")) { return; } uint version = stream.ReadUInt32(); uint numSamples = stream.ReadUInt32(); uint sampleHeadersSize = stream.ReadUInt32(); uint nameTableSize = stream.ReadUInt32(); uint dataSize = stream.ReadUInt32(); uint mode = stream.ReadUInt32(); string zero = stream.ReadASCII(8); string hash = stream.ReadASCII(16); string dummy = stream.ReadASCII(8); long nameOffset = stream.Position + sampleHeadersSize; long baseOffset = nameOffset + nameTableSize; // Only support Vorbis if (mode != (int)FSBAudioFormat.FMOD_SOUND_FORMAT_VORBIS) { return; } for (int i = 0; i < numSamples; i++) { Ogg ogg = new Ogg(); uint offset = stream.ReadUInt32(); bool extraHeaders = (offset & 0x01) != 0; uint type = offset & ((1 << 7) - 1); offset = (offset >> 7) * 0x20; ogg.channels = (type >> 5) + 1; ogg.frequency = 44100; switch ((type >> 1) & ((1 << 4) - 1)) { case 0: ogg.frequency = 4000; break; case 1: ogg.frequency = 8000; break; case 2: ogg.frequency = 11000; break; case 3: ogg.frequency = 12000; break; case 4: ogg.frequency = 16000; break; case 5: ogg.frequency = 22050; break; case 6: ogg.frequency = 24000; break; case 7: ogg.frequency = 32000; break; case 8: ogg.frequency = 44100; break; case 9: ogg.frequency = 48000; break; case 10: ogg.frequency = 96000; break; default: ogg.frequency = 44100; break; } uint unknown = stream.ReadUInt32() >> 2; while (extraHeaders) { byte dataByte = stream.ReadByte(); extraHeaders = (dataByte & 0x01) != 0; long extraLen = dataByte >> 1; extraLen += stream.ReadByte() << 7; extraLen += stream.ReadByte() << 15; dataByte = stream.ReadByte(); if (dataByte == 0x02) { ogg.channels = stream.ReadByte(); extraLen -= 1; } if (dataByte == 0x04) { ogg.frequency = stream.ReadUInt32(); extraLen -= 4; } if (dataByte == 0x06) { ogg.loopStart = stream.ReadUInt32(); ogg.loopEnd = stream.ReadUInt32(); extraLen -= 8; } if (dataByte == 0x16) { ogg.crc32 = stream.ReadUInt32(); extraLen -= 4; } stream.Position += extraLen; } long nextFilePos = stream.Position; long size = stream.ReadUInt32(); if (size == 0) { size = dataSize + baseOffset; } else { size = ((size >> 7) * 0x20) + baseOffset; } if (size < 0 || size > data.Length) { size = data.Length; } long fileOffset = baseOffset + offset; size -= fileOffset; if (i == 0) { WriteFile(stream, file, (int)fileOffset, (int)size, ogg); } else { WriteFile(stream, file + i, (int)fileOffset, (int)size, ogg); } stream.Position = nextFilePos; } stream.Dispose(true); }
public AssetsFile(string fileName, EndianStream fileStream) { //if (memFile != null) { Stream = new EndianStream(memFile, endianType); } //else { Stream = new EndianStream(File.OpenRead(fileName), endianType); } a_Stream = fileStream; filePath = fileName; int tableSize = a_Stream.ReadInt32(); int dataEnd = a_Stream.ReadInt32(); fileGen = a_Stream.ReadInt32(); int dataOffset = a_Stream.ReadInt32(); sharedAssetsList[0].fileName = Path.GetFileName(fileName); //reference itself because sharedFileIDs start from 1 switch (fileGen) { case 6://2.5.0 - 2.6.1 { a_Stream.Position = (dataEnd - tableSize); a_Stream.Position += 1; break; } case 7://3.0.0 beta { a_Stream.Position = (dataEnd - tableSize); a_Stream.Position += 1; m_Version = a_Stream.ReadStringToNull(); break; } case 8://3.0.0 - 3.4.2 { a_Stream.Position = (dataEnd - tableSize); a_Stream.Position += 1; m_Version = a_Stream.ReadStringToNull(); platform = a_Stream.ReadInt32(); break; } case 9://3.5.0 - 4.6.x { a_Stream.Position += 4;//azero m_Version = a_Stream.ReadStringToNull(); platform = a_Stream.ReadInt32(); break; } case 14://5.0.0 beta and final case 15://5.0.1 and up { a_Stream.Position += 4;//azero m_Version = a_Stream.ReadStringToNull(); platform = a_Stream.ReadInt32(); baseDefinitions = a_Stream.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); //endianType = EndianType.LittleEndian; a_Stream.endian = EndianType.LittleEndian; } switch (platform) { case -2: platformStr = "Unity Package"; break; case 4: platformStr = "OSX"; break; case 5: platformStr = "PC"; break; case 6: platformStr = "Web"; break; case 7: platformStr = "Web streamed"; break; case 9: platformStr = "iOS"; break; case 10: platformStr = "PS3"; break; case 11: platformStr = "Xbox 360"; break; case 13: platformStr = "Android"; break; case 16: platformStr = "Google NaCl"; break; case 21: platformStr = "WP8"; break; case 25: platformStr = "Linux"; break; } int baseCount = a_Stream.ReadInt32(); for (int i = 0; i < baseCount; i++) { if (fileGen < 14) { int classID = a_Stream.ReadInt32(); string baseType = a_Stream.ReadStringToNull(); string baseName = a_Stream.ReadStringToNull(); a_Stream.Position += 20; int memberCount = a_Stream.ReadInt32(); StringBuilder cb = new StringBuilder(); for (int m = 0; m < memberCount; m++) { readBase(cb, 1); } var aClass = new ClassStrStruct() { ID = classID, Text = (baseType + " " + baseName), members = cb.ToString() }; aClass.SubItems.Add(classID.ToString()); ClassStructures.Add(classID, aClass); } else { readBase5(); } } if (fileGen >= 7 && fileGen < 14) {a_Stream.Position += 4;}//azero int assetCount = a_Stream.ReadInt32(); #region asset preload table string assetIDfmt = "D" + assetCount.ToString().Length.ToString(); //format for unique ID for (int i = 0; i < assetCount; i++) { //each table entry is aligned individually, not the whole table if (fileGen >= 14) { a_Stream.AlignStream(4); } AssetPreloadData asset = new AssetPreloadData(); if (fileGen < 14) { asset.m_PathID = a_Stream.ReadInt32(); } else { asset.m_PathID = a_Stream.ReadInt64(); } asset.Offset = a_Stream.ReadInt32(); asset.Offset += dataOffset; asset.Size = a_Stream.ReadInt32(); asset.Type1 = a_Stream.ReadInt32(); asset.Type2 = a_Stream.ReadUInt16(); a_Stream.Position += 2; if (fileGen >= 15) { byte unknownByte = a_Stream.ReadByte(); //this is a single byte, not an int32 //the next entry is aligned after this //but not the last! if (unknownByte != 0) { bool investigate = true; } } asset.TypeString = asset.Type2.ToString(); if (UnityClassID.Names[asset.Type2] != null) { asset.TypeString = UnityClassID.Names[asset.Type2]; } asset.uniqueID = i.ToString(assetIDfmt); asset.exportSize = asset.Size; asset.sourceFile = this; preloadTable.Add(asset.m_PathID, asset); #region read BuildSettings to get version for unity 2.x files if (asset.Type2 == 141 && fileGen == 6) { long nextAsset = a_Stream.Position; BuildSettings BSettings = new BuildSettings(asset); m_Version = BSettings.m_Version; a_Stream.Position = nextAsset; } #endregion } #endregion buildType = m_Version.Split(new string[] { ".", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" }, StringSplitOptions.RemoveEmptyEntries); string[] strver = (m_Version.Split(new string[] { ".", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "\n" }, StringSplitOptions.RemoveEmptyEntries)); version = Array.ConvertAll(strver, int.Parse); 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 = a_Stream.ReadInt32(); for (int i = 0; i < sharedFileCount; i++) { UnityShared shared = new UnityShared(); shared.aName = a_Stream.ReadStringToNull(); a_Stream.Position += 20; string sharedFileName = a_Stream.ReadStringToNull(); //relative path shared.fileName = sharedFileName.Replace("/", "\\"); sharedAssetsList.Add(shared); } }
private static void Read(StringBuilder sb, List <ClassMember> members, EndianStream a_Stream) { for (int i = 0; i < members.Count; i++) { var member = members[i]; var level = member.Level; var varTypeStr = member.Type; var varNameStr = member.Name; object value = null; var align = (member.Flag & 0x4000) != 0; var append = true; if (varTypeStr == "SInt8")//sbyte { value = a_Stream.ReadSByte(); } else if (varTypeStr == "UInt8")//byte { value = a_Stream.ReadByte(); } else if (varTypeStr == "short" || varTypeStr == "SInt16")//Int16 { value = a_Stream.ReadInt16(); } else if (varTypeStr == "UInt16" || varTypeStr == "unsigned short")//UInt16 { value = a_Stream.ReadUInt16(); } else if (varTypeStr == "int" || varTypeStr == "SInt32")//Int32 { value = a_Stream.ReadInt32(); } else if (varTypeStr == "UInt32" || varTypeStr == "unsigned int")//UInt32 { value = a_Stream.ReadUInt32(); } else if (varTypeStr == "long long" || varTypeStr == "SInt64")//Int64 { value = a_Stream.ReadInt64(); } else if (varTypeStr == "UInt64" || varTypeStr == "unsigned long long")//UInt64 { value = a_Stream.ReadUInt64(); } else if (varTypeStr == "float")//float { value = a_Stream.ReadSingle(); } else if (varTypeStr == "double")//double { value = a_Stream.ReadDouble(); } else if (varTypeStr == "bool")//bool { value = a_Stream.ReadBoolean(); } else if (varTypeStr == "string")//string { append = false; var str = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); sb.AppendFormat("{0}{1} {2} = \"{3}\"\r\n", (new string('\t', level)), varTypeStr, varNameStr, str); i += 3; //skip } else if (varTypeStr == "Array") //Array { append = false; if ((members[i - 1].Flag & 0x4000) != 0) { align = true; } sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level)), varTypeStr, varNameStr); var size = a_Stream.ReadInt32(); sb.AppendFormat("{0}{1} {2} = {3}\r\n", (new string('\t', level)), "int", "size", size); var array = ReadArray(members, level, i); for (int j = 0; j < size; j++) { sb.AppendFormat("{0}[{1}]\r\n", (new string('\t', level + 1)), j); Read(sb, array, a_Stream); } i += array.Count + 1;//skip } else { append = false; align = false; sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level)), varTypeStr, varNameStr); } if (append) { sb.AppendFormat("{0}{1} {2} = {3}\r\n", (new string('\t', level)), varTypeStr, varNameStr, value); } if (align) { a_Stream.AlignStream(4); } } }