public override Stream GetSinglePlane(Stream inputStream, uint depthlevel) { if (Mipmaps > 1) { throw new Exception("Don't know how to deal with volume textures with mipmaps."); } if (!(Format == TextureFormat.DXT1a || Format == TextureFormat.DXT1b || Format == TextureFormat.DXT5a || Format == TextureFormat.DXT5b)) { throw new Exception("Volume textures only implemented for DXT formats."); } // Format reference: https://www.khronos.org/registry/OpenGL/extensions/NV/NV_texture_compression_vtc.txt uint bytecount = GetByteCountSingleDepthPlane(0); uint group = depthlevel / 4u; uint texInGroupBefore = depthlevel % 4u; uint texInGroupAfter = 3u - texInGroupBefore; // special handling for last group if depth not divisible by 4 uint nonDivisiblePlanesAtEnd = Depth % 4; uint groupCount = Util.Align(Depth, 4u) / 4; if (nonDivisiblePlanesAtEnd != 0 && group == (groupCount - 1u)) { texInGroupAfter = (nonDivisiblePlanesAtEnd - texInGroupBefore) - 1u; } uint bytesPerTexLine; switch (Format) { case TextureFormat.DXT1a: case TextureFormat.DXT1b: bytesPerTexLine = 8; break; case TextureFormat.DXT5a: case TextureFormat.DXT5b: bytesPerTexLine = 16; break; default: throw new Exception("Unexpected format during volume texture plane fetching: " + Format + "."); } // skip to correct group inputStream.DiscardBytes(group * bytecount * 4u); // copy texture MemoryStream s = new MemoryStream((int)bytecount); for (uint i = 0; i < bytecount; i += bytesPerTexLine) { inputStream.DiscardBytes(texInGroupBefore * bytesPerTexLine); Util.CopyStream(inputStream, s, bytesPerTexLine); inputStream.DiscardBytes(texInGroupAfter * bytesPerTexLine); } return(s); }
public Stream GetSinglePlane_DepthBeforeMip(Stream inputStream, uint depthlevel) { Stream s = new MemoryStream(); for (int i = 0; i < Mipmaps; ++i) { uint bytecount = GetByteCountSingleDepthPlane(i); uint planesBeforeCurrent = depthlevel; uint planesAfterCurrent = Depth - depthlevel - 1; inputStream.DiscardBytes(planesBeforeCurrent * bytecount); Util.CopyStream(inputStream, s, bytecount); inputStream.DiscardBytes(planesAfterCurrent * bytecount); } return(s); }
public static void ReadAlign(this Stream s, long alignment) { while (s.Position % alignment != 0) { s.DiscardBytes(1); } }
public static void ReadAlign(this Stream s, long alignment, long offset = 0) { while ((s.Position - offset) % alignment != 0) { s.DiscardBytes(1); } }
public g1tTexture(Stream stream, EndianUtils.Endianness endian) { Mipmaps = (byte)stream.ReadByte(); byte format = (byte)stream.ReadByte(); byte dimensions = (byte)stream.ReadByte(); byte unknown4 = (byte)stream.ReadByte(); byte unknown5 = (byte)stream.ReadByte(); byte unknown6 = (byte)stream.ReadByte(); byte unknown7 = (byte)stream.ReadByte(); byte unknown8 = (byte)stream.ReadByte(); if (endian == EndianUtils.Endianness.LittleEndian) { Mipmaps = Mipmaps.SwapEndian4Bits(); dimensions = dimensions.SwapEndian4Bits(); unknown4 = unknown4.SwapEndian4Bits(); unknown5 = unknown5.SwapEndian4Bits(); unknown6 = unknown6.SwapEndian4Bits(); unknown7 = unknown7.SwapEndian4Bits(); unknown8 = unknown8.SwapEndian4Bits(); } if (unknown8 == 0x01) { stream.DiscardBytes(0x0C); } switch (format) { case 0x00: Format = Textures.TextureFormat.ABGR; BitPerPixel = 32; break; case 0x01: Format = Textures.TextureFormat.RGBA; BitPerPixel = 32; break; case 0x06: Format = Textures.TextureFormat.DXT1a; BitPerPixel = 4; break; case 0x08: Format = Textures.TextureFormat.DXT5; BitPerPixel = 8; break; case 0x12: Format = Textures.TextureFormat.DXT5; BitPerPixel = 8; break; // swizzled from vita case 0x5B: Format = Textures.TextureFormat.DXT5; BitPerPixel = 8; break; // unsure what the difference to 0x08 is default: throw new Exception(String.Format("g1t: Unknown Format ({0:X2})", format)); } Width = (uint)(1 << (dimensions >> 4)); Height = (uint)(1 << (dimensions & 0x0F)); uint highestMipmapSize = (Width * Height * BitPerPixel) / 8; long textureSize = highestMipmapSize; for (int i = 0; i < Mipmaps - 1; ++i) { textureSize += highestMipmapSize / (4 << (i * 2)); } Data = new byte[textureSize]; stream.Read(Data, 0, Data.Length); }
private bool LoadFile(Stream stream, EndianUtils.Endianness?endianParam, TextUtils.GameTextEncoding encoding) { EndianUtils.Endianness endian; if (endianParam == null) { uint magic = stream.ReadUInt32().FromEndian(EndianUtils.Endianness.BigEndian); if (magic == 0x53453320) { endian = EndianUtils.Endianness.BigEndian; } else if (magic == 0x20334553) { endian = EndianUtils.Endianness.LittleEndian; } else { Console.WriteLine("Invalid magic: " + magic); return(false); } } else { endian = endianParam.Value; uint magic = stream.ReadUInt32().FromEndian(endian); if (magic != 0x53453320) { Console.WriteLine("Invalid magic: " + magic); return(false); } } stream.DiscardBytes(8); // unknown DataBegin = stream.ReadUInt32().FromEndian(endian); stream.DiscardBytes(4); // unknown FileCount = stream.ReadUInt32().FromEndian(endian); Filenames = new List <string>((int)FileCount); for (uint i = 0; i < FileCount; ++i) { Filenames.Add(stream.ReadSizedString(48, encoding).TrimNull()); } Data = stream; return(true); }
private bool LoadFile( Stream stream, uint textPointerLocationDiff ) { string magic = stream.ReadAscii( 8 ); uint alwaysSame = stream.ReadUInt32().SwapEndian(); uint filesize = stream.ReadUInt32().SwapEndian(); uint lengthSection1 = stream.ReadUInt32().SwapEndian(); stream.Position = 0x50; int textPointerDiffDiff = (int)stream.ReadUInt32().SwapEndian(); stream.Position = 0x20; uint textStart = stream.ReadUInt32().SwapEndian(); int textPointerDiff = (int)stream.ReadUInt32().SwapEndian() - textPointerDiffDiff; EntryList = new List<ScenarioFileEntry>(); // i wonder what the actual logic behind this is... uint textPointersLocation = ( lengthSection1 + 0x80 ).Align( 0x10 ) + textPointerLocationDiff; // + 0x1888; // + 0x1B4C // diff of 2C4 // Actually this isn't constant, dammit. if ( textStart != textPointersLocation ) { stream.Position = textPointersLocation; while ( true ) { long loc = stream.Position; stream.DiscardBytes( 8 ); uint[] ptrs = new uint[4]; ptrs[0] = stream.ReadUInt32().SwapEndian(); ptrs[1] = stream.ReadUInt32().SwapEndian(); ptrs[2] = stream.ReadUInt32().SwapEndian(); ptrs[3] = stream.ReadUInt32().SwapEndian(); if ( stream.Position > textStart ) { break; } if ( ptrs.Any( x => x == 0 ) ) { break; } if ( ptrs.Any( x => x + textPointerDiff < textStart ) ) { break; } if ( ptrs.Any( x => x + textPointerDiff >= filesize ) ) { break; } var s = new ScenarioFileEntry(); s.Pointer = (uint)loc; stream.Position = ptrs[0] + textPointerDiff; s.JpName = stream.ReadShiftJisNullterm(); stream.Position = ptrs[1] + textPointerDiff; s.JpText = stream.ReadShiftJisNullterm(); stream.Position = ptrs[2] + textPointerDiff; s.EnName = stream.ReadShiftJisNullterm(); stream.Position = ptrs[3] + textPointerDiff; s.EnText = stream.ReadShiftJisNullterm(); EntryList.Add( s ); stream.Position = loc + 0x18; } } return true; }
public Stream GetSinglePlane_MipBeforeDepth(Stream inputStream, uint depthlevel) { Stream s = new MemoryStream(); uint planesBeforeCurrent = depthlevel; uint planesAfterCurrent = Depth - depthlevel - 1; uint sum = 0u; for (int i = 0; i < Mipmaps; ++i) { uint bytecount = GetByteCountSingleDepthPlane(i); sum += bytecount; } if (Format == TextureFormat.DXT1a || Format == TextureFormat.DXT1b || Format == TextureFormat.DXT5a || Format == TextureFormat.DXT5b) { // this feels stupid?? sum = Util.Align(sum, 0x80u); } inputStream.DiscardBytes(planesBeforeCurrent * sum); Util.CopyStream(inputStream, s, sum); inputStream.DiscardBytes(planesAfterCurrent * sum); return(s); }
private static void ReadStringsInBlocks(List <MainDolString> output, IRomMapper dol, Stream stream, long pos, int byteSizeTotal, int blockSize, int stringsPerBlock, bool keepInvalid) { stream.Position = pos; int count = byteSizeTotal / blockSize; long[] positions = new long[stringsPerBlock]; uint[] ramAddresses = new uint[stringsPerBlock]; uint[] romAddresses = new uint[stringsPerBlock]; string[] strings = new string[stringsPerBlock]; uint[] stringByteCounts = new uint[stringsPerBlock]; for (int i = 0; i < count; ++i) { for (int j = 0; j < stringsPerBlock; ++j) { positions[j] = stream.Position; ramAddresses[j] = stream.ReadUInt32().FromEndian(EndianUtils.Endianness.BigEndian); } stream.DiscardBytes((uint)(blockSize - 4 * stringsPerBlock)); bool isValid = false; for (int j = 0; j < stringsPerBlock; ++j) { if (ramAddresses[j] == 0) { romAddresses[j] = 0; strings[j] = null; stringByteCounts[j] = 0; } else { romAddresses[j] = dol.MapRamToRom(ramAddresses[j]); long tmp = stream.Position; stream.Position = romAddresses[j]; string s = stream.ReadNulltermString(TextUtils.GameTextEncoding.ShiftJIS); uint bytesRead = (uint)(stream.Position - romAddresses[j]); stream.Position = tmp; strings[j] = s; stringByteCounts[j] = bytesRead; isValid = true; } } if (isValid || keepInvalid) { for (int j = 0; j < stringsPerBlock; ++j) { output.Add(new MainDolString((uint)positions[j], romAddresses[j], strings[j], stringByteCounts[j])); } } } }
private bool LoadFile(Stream stream, Util.Endianness endian, Util.GameTextEncoding encoding) { string magic = stream.ReadAscii(4); if (magic != "SE3 ") { return(false); } stream.DiscardBytes(8); // unknown DataBegin = stream.ReadUInt32().FromEndian(endian); stream.DiscardBytes(4); // unknown FileCount = stream.ReadUInt32().FromEndian(endian); Filenames = new List <string>((int)FileCount); for (uint i = 0; i < FileCount; ++i) { Filenames.Add(stream.ReadSizedString(48, encoding).TrimNull()); } Data = stream; return(true); }
private bool LoadFile( Stream stream ) { string magic = stream.ReadAscii( 8 ); uint entrySize = stream.ReadUInt32().SwapEndian(); uint synopsisCount = stream.ReadUInt32().SwapEndian(); uint unknown = stream.ReadUInt32().SwapEndian(); stream.DiscardBytes( 0xC ); SynopsisList = new List<SynopsisEntry>( (int)synopsisCount ); for ( uint i = 0; i < synopsisCount; ++i ) { SynopsisEntry l = new SynopsisEntry( stream ); SynopsisList.Add( l ); } return true; }
private bool LoadFile(Stream stream, EndianUtils.Endianness endian) { string magic = stream.ReadAscii(8); uint unknown1 = stream.ReadUInt32().FromEndian(endian); uint entryCount = stream.ReadUInt32().FromEndian(endian); uint unknown2 = stream.ReadUInt32().FromEndian(endian); stream.DiscardBytes(12); BattleBookEntryList = new List <BattleBookEntry>((int)entryCount); for (uint i = 0; i < entryCount; ++i) { BattleBookEntry e = new BattleBookEntry(stream, endian); BattleBookEntryList.Add(e); } return(true); }
private static List <string> ParseBookFunction(Stream s, long end, EndianUtils.Endianness e) { List <string> text = new List <string>(); short dataCounter = s.ReadInt16(e); for (int i = 0; i < dataCounter; ++i) { s.DiscardBytes(0x26); } List <byte> sb = new List <byte>(); List <byte> contentbytes = new List <byte>(); ReadString(s, sb, contentbytes); string str = Encoding.UTF8.GetString(sb.ToArray()); text.AddRange(str.Split(new string[] { "\\n" }, StringSplitOptions.None)); return(text); }
private bool LoadFile(Stream stream) { string magic = stream.ReadAscii(8); uint entrySize = stream.ReadUInt32().SwapEndian(); uint synopsisCount = stream.ReadUInt32().SwapEndian(); uint unknown = stream.ReadUInt32().SwapEndian(); stream.DiscardBytes(0xC); SynopsisList = new List <SynopsisEntry>((int)synopsisCount); for (uint i = 0; i < synopsisCount; ++i) { SynopsisEntry l = new SynopsisEntry(stream); SynopsisList.Add(l); } return(true); }
private bool LoadFile(Stream stream, EndianUtils.Endianness endian) { string magic = stream.ReadAscii(8); if (magic != "SYNPDAT\0") { throw new Exception("Invalid magic."); } uint entrySize = stream.ReadUInt32().FromEndian(endian); uint synopsisCount = stream.ReadUInt32().FromEndian(endian); uint unknown = stream.ReadUInt32().FromEndian(endian); stream.DiscardBytes(0xC); SynopsisList = new List <SynopsisEntry>((int)synopsisCount); for (uint i = 0; i < synopsisCount; ++i) { SynopsisEntry l = new SynopsisEntry(stream, endian); SynopsisList.Add(l); } return(true); }
private bool LoadFile(Stream stream, EndianUtils.Endianness endian, TextUtils.GameTextEncoding encoding, uint textPointerLocationDiff) { string magic = stream.ReadAscii(8); uint alwaysSame = stream.ReadUInt32().FromEndian(endian); uint filesize = stream.ReadUInt32().FromEndian(endian); uint lengthSection1 = stream.ReadUInt32().FromEndian(endian); stream.Position = 0x50; int textPointerDiffDiff = (int)stream.ReadUInt32().FromEndian(endian); stream.Position = 0x20; uint textStart = stream.ReadUInt32().FromEndian(endian); int textPointerDiff = (int)stream.ReadUInt32().FromEndian(endian) - textPointerDiffDiff; EntryList = new List <ScenarioFileEntry>(); // i wonder what the actual logic behind this is... uint textPointersLocation = (lengthSection1 + 0x80).Align(0x10) + textPointerLocationDiff; // + 0x1888; // + 0x1B4C // diff of 2C4 // Actually this isn't constant, dammit. if (textStart != textPointersLocation) { stream.Position = textPointersLocation; while (true) { long loc = stream.Position; stream.DiscardBytes(8); uint[] ptrs = new uint[4]; ptrs[0] = stream.ReadUInt32().FromEndian(endian); ptrs[1] = stream.ReadUInt32().FromEndian(endian); ptrs[2] = stream.ReadUInt32().FromEndian(endian); ptrs[3] = stream.ReadUInt32().FromEndian(endian); if (stream.Position > textStart) { break; } if (ptrs.Any(x => x == 0)) { break; } if (ptrs.Any(x => x + textPointerDiff < textStart)) { break; } if (ptrs.Any(x => x + textPointerDiff >= filesize)) { break; } var s = new ScenarioFileEntry(); s.Pointer = (uint)loc; s.JpName = stream.ReadNulltermStringFromLocationAndReset(ptrs[0] + textPointerDiff, encoding); s.JpText = stream.ReadNulltermStringFromLocationAndReset(ptrs[1] + textPointerDiff, encoding); s.EnName = stream.ReadNulltermStringFromLocationAndReset(ptrs[2] + textPointerDiff, encoding); s.EnText = stream.ReadNulltermStringFromLocationAndReset(ptrs[3] + textPointerDiff, encoding); EntryList.Add(s); stream.Position = loc + 0x18; } } return(true); }
// some skit files reuse the same JP string in cases where the english text is different, this expands this to have a separate entry for each JP string public static (Stream newTssStream, SCS wscsnew) MultiplyOutSkitTss(DuplicatableStream stream, SCS wscsorig) { stream.Position = 0; Stream s = stream.CopyToMemory(); uint magic = s.ReadUInt32().FromEndian(EndianUtils.Endianness.BigEndian); uint codeStart = s.ReadUInt32().FromEndian(EndianUtils.Endianness.BigEndian); uint unknown3 = s.ReadUInt32().FromEndian(EndianUtils.Endianness.BigEndian); uint dataStart = s.ReadUInt32().FromEndian(EndianUtils.Endianness.BigEndian); uint unknown5 = s.ReadUInt32().FromEndian(EndianUtils.Endianness.BigEndian); uint codeLength = s.ReadUInt32().FromEndian(EndianUtils.Endianness.BigEndian); uint dataLength = s.ReadUInt32().FromEndian(EndianUtils.Endianness.BigEndian); uint unknown8 = s.ReadUInt32().FromEndian(EndianUtils.Endianness.BigEndian); List <(long pos, int number, long len)> strings = new List <(long pos, int number, long len)>(); s.Position = codeStart; while (s.Position < (codeStart + codeLength + 0xC - 1)) { if (s.ReadUInt32().FromEndian(EndianUtils.Endianness.BigEndian) == 0x01000000) { if (s.PeekUInt64().FromEndian(EndianUtils.Endianness.BigEndian) == 0x0E000008040C0004) { s.DiscardBytes(8); uint offsetOfOffset = s.ReadUInt32().FromEndian(EndianUtils.Endianness.BigEndian); long pos = s.Position; s.Position = dataStart + offsetOfOffset; uint offset = s.ReadUInt32().FromEndian(EndianUtils.Endianness.BigEndian); long stringpos = dataStart + offset; s.Position = stringpos; string str = s.ReadNulltermString(TextUtils.GameTextEncoding.ShiftJIS); // must have specific format if (MatchesSkitFormat(str)) { int num = SCS.DecodeNumber(str.Substring(4, str.Length - 5)); strings.Add((stringpos, num, str.Length)); } s.Position = pos; } } } SortedSet <int> reservedNumbers = new SortedSet <int>(); for (int i = 0; i < wscsorig.Entries.Count; ++i) { reservedNumbers.Add(i); } foreach (var d in strings) { if (reservedNumbers.Contains(d.number)) { reservedNumbers.Remove(d.number); } } List <string> newscs = new List <string>(wscsorig.Entries); List <(int oldIdx, int newIdx)> idxs = new List <(int oldIdx, int newIdx)>(); int currentIndex = 0; foreach (var d in strings) { while (reservedNumbers.Contains(currentIndex)) { ++currentIndex; } string numstr = SCS.EncodeNumber(currentIndex); string resultstr = "\x1F(1," + numstr + ")"; if (resultstr.Length > d.len) { throw new Exception("don't know how to inject this"); } s.Position = d.pos; s.WriteShiftJisNullterm(resultstr); PutString(newscs, wscsorig.Entries[d.number], currentIndex); ++currentIndex; } s.Position = 0; return(s, new SCS(newscs)); }
public g1tTexture( Stream stream, Util.Endianness endian ) { Mipmaps = (byte)stream.ReadByte(); byte format = (byte)stream.ReadByte(); byte dimensions = (byte)stream.ReadByte(); byte unknown4 = (byte)stream.ReadByte(); byte unknown5 = (byte)stream.ReadByte(); byte unknown6 = (byte)stream.ReadByte(); byte unknown7 = (byte)stream.ReadByte(); byte unknown8 = (byte)stream.ReadByte(); if ( endian == Util.Endianness.LittleEndian ) { Mipmaps = Mipmaps.SwapEndian4Bits(); dimensions = dimensions.SwapEndian4Bits(); unknown4 = unknown4.SwapEndian4Bits(); unknown5 = unknown5.SwapEndian4Bits(); unknown6 = unknown6.SwapEndian4Bits(); unknown7 = unknown7.SwapEndian4Bits(); unknown8 = unknown8.SwapEndian4Bits(); } if ( unknown8 == 0x01 ) { stream.DiscardBytes( 0x0C ); } switch ( format ) { case 0x00: Format = Textures.TextureFormat.ABGR; BitPerPixel = 32; break; case 0x01: Format = Textures.TextureFormat.RGBA; BitPerPixel = 32; break; case 0x06: Format = Textures.TextureFormat.DXT1; BitPerPixel = 4; break; case 0x08: Format = Textures.TextureFormat.DXT5; BitPerPixel = 8; break; default: throw new Exception( String.Format( "g1t: Unknown Format ({0:X2})", format ) ); } Width = (uint)( 1 << ( dimensions >> 4 ) ); Height = (uint)( 1 << ( dimensions & 0x0F ) ); uint highestMipmapSize = ( Width * Height * BitPerPixel ) / 8; long textureSize = highestMipmapSize; for ( int i = 0; i < Mipmaps - 1; ++i ) { textureSize += highestMipmapSize / ( 4 << ( i * 2 ) ); } Data = new byte[textureSize]; stream.Read( Data, 0, Data.Length ); }
private bool LoadFile( Stream stream ) { string magic = stream.ReadAscii( 8 ); uint filesize = stream.ReadUInt32().SwapEndian(); uint modelDefStart = stream.ReadUInt32().SwapEndian(); uint modelDefCount = stream.ReadUInt32().SwapEndian(); uint refStringStart = stream.ReadUInt32().SwapEndian(); uint customStart = stream.ReadUInt32().SwapEndian(); uint customCount = stream.ReadUInt32().SwapEndian(); uint otherStart = stream.ReadUInt32().SwapEndian(); uint otherCount = stream.ReadUInt32().SwapEndian(); uint u20BsectionStart = stream.ReadUInt32().SwapEndian(); uint u20BsectionCount = stream.ReadUInt32().SwapEndian(); uint u80sectionStart = stream.ReadUInt32().SwapEndian(); uint u80sectionCount = stream.ReadUInt32().SwapEndian(); stream.DiscardBytes( 8 ); ModelDefList = new List<CharacterModelDefinition>( (int)modelDefCount ); stream.Position = modelDefStart; for ( uint i = 0; i < modelDefCount; ++i ) { ModelDefList.Add( new CharacterModelDefinition( stream, refStringStart ) ); } ModelCustomList = new List<CustomModelAddition>( (int)customCount ); stream.Position = customStart; for ( uint i = 0; i < customCount; ++i ) { ModelCustomList.Add( new CustomModelAddition( stream, refStringStart ) ); } ModelOtherList = new List<OtherModelAddition>( (int)otherCount ); stream.Position = otherStart; for ( uint i = 0; i < otherCount; ++i ) { ModelOtherList.Add( new OtherModelAddition( stream, refStringStart ) ); } U20BList = new List<Unknown0x20byteAreaB>( (int)u20BsectionCount ); stream.Position = u20BsectionStart; for ( uint i = 0; i < u20BsectionCount; ++i ) { U20BList.Add( new Unknown0x20byteAreaB( stream, refStringStart ) ); } U80List = new List<Unknown0x80byteArea>( (int)u80sectionCount ); stream.Position = u80sectionStart; for ( uint i = 0; i < u80sectionCount; ++i ) { U80List.Add( new Unknown0x80byteArea( stream, refStringStart ) ); } foreach ( var model in ModelDefList ) { model.Custom = new CustomModelAddition[model.CustomCount]; for ( int i = 0; i < model.Custom.Length; ++i ) { model.Custom[i] = ModelCustomList[(int)model.CustomIndex + i]; } model.Other = new OtherModelAddition[model.OtherCount]; for ( int i = 0; i < model.Other.Length; ++i ) { model.Other[i] = ModelOtherList[(int)model.OtherIndex + i]; } model.Unknown0x20Area = new Unknown0x20byteAreaB[model.Unknown0x20AreaCount]; for ( int i = 0; i < model.Unknown0x20Area.Length; ++i ) { model.Unknown0x20Area[i] = U20BList[(int)model.Unknown0x20AreaIndex + i]; } model.Unknown0x80Area = new Unknown0x80byteArea[model.Unknown0x80AreaCount]; for ( int i = 0; i < model.Unknown0x80Area.Length; ++i ) { model.Unknown0x80Area[i] = U80List[(int)model.Unknown0x80AreaIndex + i]; } } return true; }
private bool LoadFile(Stream stream) { string magic = stream.ReadAscii(8); uint filesize = stream.ReadUInt32().SwapEndian(); uint modelDefStart = stream.ReadUInt32().SwapEndian(); uint modelDefCount = stream.ReadUInt32().SwapEndian(); uint refStringStart = stream.ReadUInt32().SwapEndian(); uint customStart = stream.ReadUInt32().SwapEndian(); uint customCount = stream.ReadUInt32().SwapEndian(); uint otherStart = stream.ReadUInt32().SwapEndian(); uint otherCount = stream.ReadUInt32().SwapEndian(); uint u20BsectionStart = stream.ReadUInt32().SwapEndian(); uint u20BsectionCount = stream.ReadUInt32().SwapEndian(); uint u80sectionStart = stream.ReadUInt32().SwapEndian(); uint u80sectionCount = stream.ReadUInt32().SwapEndian(); stream.DiscardBytes(8); ModelDefList = new List <CharacterModelDefinition>((int)modelDefCount); stream.Position = modelDefStart; for (uint i = 0; i < modelDefCount; ++i) { ModelDefList.Add(new CharacterModelDefinition(stream, refStringStart)); } ModelCustomList = new List <CustomModelAddition>((int)customCount); stream.Position = customStart; for (uint i = 0; i < customCount; ++i) { ModelCustomList.Add(new CustomModelAddition(stream, refStringStart)); } ModelOtherList = new List <OtherModelAddition>((int)otherCount); stream.Position = otherStart; for (uint i = 0; i < otherCount; ++i) { ModelOtherList.Add(new OtherModelAddition(stream, refStringStart)); } U20BList = new List <Unknown0x20byteAreaB>((int)u20BsectionCount); stream.Position = u20BsectionStart; for (uint i = 0; i < u20BsectionCount; ++i) { U20BList.Add(new Unknown0x20byteAreaB(stream, refStringStart)); } U80List = new List <Unknown0x80byteArea>((int)u80sectionCount); stream.Position = u80sectionStart; for (uint i = 0; i < u80sectionCount; ++i) { U80List.Add(new Unknown0x80byteArea(stream, refStringStart)); } foreach (var model in ModelDefList) { model.Custom = new CustomModelAddition[model.CustomCount]; for (int i = 0; i < model.Custom.Length; ++i) { model.Custom[i] = ModelCustomList[(int)model.CustomIndex + i]; } model.Other = new OtherModelAddition[model.OtherCount]; for (int i = 0; i < model.Other.Length; ++i) { model.Other[i] = ModelOtherList[(int)model.OtherIndex + i]; } model.Unknown0x20Area = new Unknown0x20byteAreaB[model.Unknown0x20AreaCount]; for (int i = 0; i < model.Unknown0x20Area.Length; ++i) { model.Unknown0x20Area[i] = U20BList[(int)model.Unknown0x20AreaIndex + i]; } model.Unknown0x80Area = new Unknown0x80byteArea[model.Unknown0x80AreaCount]; for (int i = 0; i < model.Unknown0x80Area.Length; ++i) { model.Unknown0x80Area[i] = U80List[(int)model.Unknown0x80AreaIndex + i]; } } return(true); }