static AssetObject LoadObject(EndianStream es, int format, TypeMeta types) { var obj = new AssetObject(); obj.PathId = es.ReadUInt64(); obj.DataOfs = es.ReadUInt32(); obj.Size = es.ReadUInt32(); if (format < 17) { obj.TypeId = es.ReadInt32(); obj.ClassId = es.ReadInt16(); } else { obj.TypeId = es.ReadInt32(); obj.ClassId = types.ClassIds[obj.TypeId]; } if (format <= 16) { es.ReadInt16(); } if (format == 15 || format == 16) { es.ReadByte(); } return(obj); }
private void ParseBundleFormat(EndianStream stream) { int bundleSize = stream.ReadInt32(); short unused16 = stream.ReadInt16(); int offset = stream.ReadInt16(); int unused32 = stream.ReadInt32(); int lzmaChunkCount = stream.ReadInt32(); if (lzmaChunkCount != 1) { // see original project, it support only 1 chunk throw new Exception($"Found lzma with {lzmaChunkCount} chunks"); } MemoryStream memStream = IsBundlePacked ? new MemoryStream() : null; for (int i = 0; i < lzmaChunkCount; i++) { int lzmaSize = stream.ReadInt32(); int decompressedSize = stream.ReadInt32(); stream.BaseStream.Position = offset; switch (Signature) { case BundleSignature.UnityRaw: ParseBundleFiles(stream); break; case BundleSignature.UnityWeb: case BundleSignature.HexFA: memStream.Position = 0; SevenZipHelper.DecompressLZMASizeStream(stream.BaseStream, lzmaSize, memStream); using (EndianStream decompressStream = new EndianStream(memStream, EndianType.BigEndian)) { ParseBundleFiles(decompressStream); } break; default: throw new Exception($"Unsupported bundle signature '{Signature}'"); } offset += lzmaSize; } }
public void Load(EndianStream es, int format) { ClassIds = new List <int>(); Hashes = new Dictionary <int, byte[]>(); TypeTrees = new Dictionary <int, TreeNode>(); version = es.ReadStringToNull(); target = (BuildTarget)es.ReadInt32(); Debug.WriteLine(version + " target " + target); if (format >= 13) { var hasTypeTrees = es.ReadByte() != 0; var num = es.ReadInt32(); for (int i = 0; i < num; i++) { int classId = es.ReadInt32(); if (format >= 17) { var unk0 = es.ReadByte(); var scriptId = es.ReadInt16(); if (classId == 114) { if (scriptId >= 0) { classId = -2 - scriptId; } else { classId = -1; } } } ClassIds.Add(classId); Hashes.Add(classId, es.ReadBytes(classId < 0 ? 32 : 16)); if (hasTypeTrees) { TypeTrees.Add(classId, LoadTree(es, format)); } } } }
/// <summary> /// Load the usermap's Header /// </summary> public void LoadHeader() { _forgeHeader = new Header(); _forgeStream.SeekTo(0x42); _forgeHeader.CreationDate = _forgeStream.ReadInt32(); _forgeStream.SeekTo(0x48); _forgeHeader.CreationVarientName = _forgeStream.ReadUTF16(0x1F); _forgeStream.SeekTo(0x68); _forgeHeader.CreationVarientDescription = _forgeStream.ReadAscii(0x80); _forgeStream.SeekTo(0xE8); _forgeHeader.CreationVarientAuthor = _forgeStream.ReadAscii(0x13); _forgeStream.SeekTo(0x114); _forgeHeader.ModificationDate = _forgeStream.ReadInt32(); _forgeStream.SeekTo(0x150); _forgeHeader.VarientName = _forgeStream.ReadUTF16(0x1F); _forgeStream.SeekTo(0x170); _forgeHeader.VarientDescription = _forgeStream.ReadAscii(0x80); _forgeStream.SeekTo(0x1F0); _forgeHeader.VarientAuthor = _forgeStream.ReadAscii(0x13); _forgeStream.SeekTo(0x228); _forgeHeader.MapID = _forgeStream.ReadInt32(); _forgeStream.SeekTo(0x246); _forgeHeader.SpawnedObjectCount = _forgeStream.ReadInt16(); _forgeStream.SeekTo(0x24C); _forgeHeader.WorldBoundsXMin = _forgeStream.ReadFloat(); _forgeHeader.WorldBoundsXMax = _forgeStream.ReadFloat(); _forgeHeader.WorldBoundsYMin = _forgeStream.ReadFloat(); _forgeHeader.WorldBoundsYMax = _forgeStream.ReadFloat(); _forgeHeader.WorldBoundsZMin = _forgeStream.ReadFloat(); _forgeHeader.WorldBoundsZMax = _forgeStream.ReadFloat(); _forgeStream.SeekTo(0x268); _forgeHeader.MaximiumBudget = _forgeStream.ReadFloat(); _forgeHeader.CurrentBudget = _forgeStream.ReadFloat(); }
public ItemPlacementChunk(EndianStream stream) { Offset = stream.Position; ChunkType = (ItemChunkType)stream.ReadInt16(); stream.SeekTo(stream.Position + 0x0A); TagIndex = stream.ReadInt32(); SpawnCoords = new ItemSpawnCoords() { X = stream.ReadFloat(), Y = stream.ReadFloat(), Z = stream.ReadFloat(), Yaw = stream.ReadFloat(), Pitch = stream.ReadFloat(), Roll = stream.ReadFloat() }; stream.SeekTo(stream.Position + 0x16); stream.ReadByte(); Team = stream.ReadByte(); SpareClips = stream.ReadByte(); RespawnTime = stream.ReadByte(); stream.SeekTo(stream.Position + 0x12); }
private void ReadBase5(EndianStream stream) { int classID = stream.ReadInt32(); if (IsReadSubClass) { // same class ID with different subclasses coored several times but we need unique class ID // so create unique class ID and store corresponding class ID stream.BaseStream.Position++; int uniqueClassID; int subClassID = stream.ReadInt16(); if (subClassID == -1) { // no subclass. that meen that class ID is unique by itself uniqueClassID = classID; } else if (subClassID >= 0) { // ordinal class ID should be >= 0, so we can use whole negative int range uniqueClassID = -1 - subClassID; } else { throw new Exception($"Invalid type value {subClassID} for asset file {Name}"); } ClassIDMap id = new ClassIDMap(uniqueClassID, classID); m_classIDs.Add(id); if (classID == (int)ClassIDType.MonoBehaviour) { stream.BaseStream.Position += 16; } classID = uniqueClassID; } else if (classID < 0) { stream.BaseStream.Position += 16; } stream.BaseStream.Position += 16; if (BaseDefinitions) { ClassStruct classStruct = new ClassStruct(); classStruct.ClassID = classID; int memberCount = stream.ReadInt32(); if (memberCount < 0) { throw new Exception($"Invalid member count {memberCount}"); } int stringSize = stream.ReadInt32(); if (stringSize < 0) { throw new Exception($"Invalid string size {stringSize}"); } long stringPosition = stream.BaseStream.Position + memberCount * ClassMember.ClassSize; List <ClassMember> members = new List <ClassMember>(); for (int i = 0; i < memberCount; i++) { ReadClassMember5(stream, classStruct, members, stringPosition); } stream.BaseStream.Position += stringSize; classStruct.Members = members.ToArray(); AddClassStruct(classStruct); } }
public override void Read(EndianStream stream) { base.Read(stream); Enabled = stream.ReadBoolean(); if (IsReadAlign) { stream.AlignStream(AlignType.Align4); } CastShadows = stream.ReadByte(); ReceiveShadows = stream.ReadByte(); if (IsReadAlign) { stream.AlignStream(AlignType.Align4); } if (IsReadMotionVector) { MotionVectors = stream.ReadByte(); LightProbeUsage = stream.ReadByte(); ReflectionProbeUsage = stream.ReadByte(); stream.AlignStream(AlignType.Align4); } if (IsSmallLightIndex) { LightmapIndex = stream.ReadByte(); } else { LightmapIndex = stream.ReadUInt16(); } if (IsReadLightDynamic) { LightmapIndexDynamic = stream.ReadUInt16(); } if (IsReadTileOffset) { LightmapTilingOffset.Read(stream); } if (IsReadTileDynamic) { LightmapTilingOffsetDynamic.Read(stream); } m_materials = stream.ReadArray(() => new PPtr <Material>(AssetsFile)); if (IsReadSubsetIndices) { m_subsetIndices = stream.ReadUInt32Array(); } else { StaticBatchInfo.Read(stream); } StaticBatchRoot.Read(stream); if (IsReadUseLight) { UseLightProbes = stream.ReadBoolean(); stream.AlignStream(AlignType.Align4); if (IsReadReflectUsage) { ReflectionProbeUsage = stream.ReadInt32(); } } ProbeAnchor.Read(stream); if (IsReadLightOverride) { LightProbeVolumeOverride.Read(stream); } stream.AlignStream(AlignType.Align4); SortingLayerID = stream.ReadInt32(); if (IsReadLayer) { SortingLayer = stream.ReadInt16(); } SortingOrder = stream.ReadInt16(); stream.AlignStream(AlignType.Align4); }
/// <summary> /// Load the gpd's Campaign Skulls /// </summary> public void LoadCampaignSkulls() { _gpdCampaignSkulls = new List <Skull>(); // Load Gold Skulls _gpdStream.SeekTo(0x356E); BitArray goldSkullsBitmask = new BitArray(BitConverter.GetBytes(_gpdStream.ReadInt16())); for (int skullBitmaskIndex = 0; skullBitmaskIndex < 9; skullBitmaskIndex++) { Skull skull = new Skull(); skull.Enabled = goldSkullsBitmask[skullBitmaskIndex]; skull.SkullType = SkullType.Gold; skull.Name = (SkullName)skullBitmaskIndex; #region Skill Description switch (skullBitmaskIndex) { case 0: skull.Description = "Death carries a heavy price..."; break; case 1: skull.Description = "Bash your way to better health."; break; case 2: skull.Description = "Your foes always make every saving throw."; break; case 3: skull.Description = "Pull pin. Count to three. Throw."; break; case 4: skull.Description = "You'll miss those eyes in the back of your head."; break; case 5: skull.Description = "Trust us. Bring a magazine."; break; case 6: skull.Description = "Field promotions for everyone!"; break; case 7: skull.Description = "What was once resistance is now immunity."; break; case 8: skull.Description = "Coverage under the covenant Health Plan."; break; } #endregion _gpdCampaignSkulls.Add(skull); } _gpdStream.SeekTo(0x3573); goldSkullsBitmask = new BitArray(BitConverter.GetBytes((int)(_gpdStream.ReadByte() >> 1))); if (goldSkullsBitmask.Length != 0) { for (int skullBitmaskIndex = 0; skullBitmaskIndex < 4; skullBitmaskIndex++) { Skull skull = new Skull(); skull.Enabled = goldSkullsBitmask[skullBitmaskIndex]; skull.SkullType = SkullType.Silver; skull.Name = (SkullName)(skullBitmaskIndex + 9); #region Skill Description switch (skullBitmaskIndex) { case 0: skull.Description = "Shoot from the hip."; break; case 1: skull.Description = "More bang for your buck."; break; case 2: skull.Description = "Light a match..."; break; case 3: skull.Description = "But a dog beat me over the fence."; break; } #endregion _gpdCampaignSkulls.Add(skull); } } }
// returns list of materials public static void ReadBundleStream(EndianStream b_Stream, out List <string> materials, out List <string> gameObjects) { materials = null; gameObjects = null; var header = b_Stream.ReadStringToNull(); if (header == "UnityFS") { var ver1 = b_Stream.ReadInt32(); var ver2 = b_Stream.ReadStringToNull(); var ver3 = b_Stream.ReadStringToNull(); long bundleSize = ver1 < 6 ? b_Stream.ReadInt32() : b_Stream.ReadInt64(); var cHdrSize = b_Stream.ReadInt32(); var uHdrSize = b_Stream.ReadInt32(); var hdrFlags = b_Stream.ReadInt32(); var compression = hdrFlags & 0x3f; var eofMetadata = (hdrFlags & 0x80) != 0; long pos = 0; if (eofMetadata) { pos = b_Stream.Position; b_Stream.BaseStream.Seek(-cHdrSize, SeekOrigin.End); } var data = decompress(b_Stream.ReadBytes(cHdrSize), uHdrSize, compression); if (eofMetadata) { b_Stream.Position = pos; } var hdr = new EndianStream(new MemoryStream(data), EndianType.BigEndian); var guid = hdr.ReadBytes(16); var numBlocks = hdr.ReadInt32(); var blocks = new BlockInfo[numBlocks]; for (int i = 0; i < numBlocks; i++) { var uSize = hdr.ReadInt32(); var cSize = hdr.ReadInt32(); var flags = hdr.ReadInt16(); blocks[i] = new BlockInfo() { uSize = uSize, cSize = cSize, flags = flags }; } var storage = new Storage(blocks, b_Stream); var numParts = hdr.ReadInt32(); for (int i = 0; i < numParts; i++) { var ofs = hdr.ReadInt64(); var size = hdr.ReadInt64(); var status = hdr.ReadInt32(); var name = hdr.ReadStringToNull(); var part = new BundlePart() { stream = new StreamPart(storage, ofs, size), name = name }; if (i == 0) //(status & 4) != 0) { LoadAssetFile(new StreamPart(storage, ofs, size), out materials, out gameObjects); } } } else { throw new Exception("Unknown header: " + (header[0] > 'A' && header[0] < 'Z' ? header.Substring(0, 8) : string.Join(" ", header.Substring(0, 8).ToCharArray().Select(c => ((int)c).ToString("X2"))))); } }
static object ReadValue(EndianStream es, TreeNode type) { object v; var t = type.type; switch (t) { case "bool": v = es.ReadByte() != 0; break; case "SInt8": v = es.ReadSByte(); break; case "UInt8": v = es.ReadByte(); break; case "SInt16": v = es.ReadInt16(); break; case "UInt16": v = es.ReadUInt16(); break; case "SInt32": case "int": v = es.ReadInt32(); break; case "UInt32": case "unsigned int": v = es.ReadUInt32(); break; case "SInt64": v = es.ReadInt64(); break; case "UInt64": v = es.ReadUInt64(); break; case "float": es.AlignStream(4); v = es.ReadSingle(); break; case "double": es.AlignStream(4); v = es.ReadDouble(); break; case "string": var ssize = es.ReadInt32(); v = UTF8Encoding.UTF8.GetString(es.ReadBytes(ssize)); if (type.children[0].postAlign) { es.AlignStream(4); } break; default: var firstChild = type.children.Any() ? type.children[0] : null; if (type.isArray) { firstChild = type; } if (t.StartsWith("PPtr<")) { v = new FilePtr() { FileID = es.ReadInt32(), PathID = es.ReadInt64() }; } else if (firstChild != null && firstChild.isArray) { var size = es.ReadInt32(); var arrayType = firstChild.children[1]; if (arrayType.type == "char" || arrayType.type == "UInt8") { v = es.ReadBytes(size); } else { var a = new object[size]; for (int i = 0; i < size; i++) { a[i] = ReadValue(es, arrayType); } v = a; } if (firstChild.postAlign) { es.AlignStream(4); } } else if (t == "pair") { v = Tuple.Create <object, object>(ReadValue(es, type.children[0]), ReadValue(es, type.children[1])); } else { var o = new Dictionary <string, object>(); foreach (var child in type.children) { o.Add(child.name, ReadValue(es, child)); } v = o; } break; } if (type.postAlign) { es.AlignStream(4); } return(v); }
/// <summary> /// Load the STFS Container's MetaData /// </summary> public void LoadMetaData() { _stfsMetaData = new xMetaData(); _stfsStream.SeekTo(0x22C); // Read License Entries _stfsMetaData.LicensingEntries = new xMetaData.LicensingEntry(); _stfsMetaData.LicensingEntries.LicenseID = _stfsStream.ReadInt64(); _stfsMetaData.LicensingEntries.LicenseBits = _stfsStream.ReadInt32(); _stfsMetaData.LicensingEntries.LicenseFlags = _stfsStream.ReadInt32(); _stfsStream.SeekTo(0x32C); _stfsMetaData.ContentID = _stfsStream.ReadBlock(0x14); _stfsMetaData.HeaderSize = _stfsStream.ReadUInt32(); _stfsMetaData.ContentType = (ContentTypes)_stfsStream.ReadInt32(); _stfsMetaData.MetadataVersion = _stfsStream.ReadInt32(); _stfsMetaData.ContentSize = _stfsStream.ReadInt64(); _stfsMetaData.MediaID = _stfsStream.ReadUInt32(); _stfsMetaData.Version = _stfsStream.ReadInt32(); _stfsMetaData.BaseVersion = _stfsStream.ReadInt32(); _stfsMetaData.TitleID = _stfsStream.ReadUInt32(); _stfsMetaData.Platform = (PackagePlatform)_stfsStream.ReadByte(); _stfsMetaData.ExecutableType = _stfsStream.ReadByte(); _stfsMetaData.DiskNumber = _stfsStream.ReadByte(); _stfsMetaData.DiskInSet = _stfsStream.ReadByte(); _stfsMetaData.SaveGameID = _stfsStream.ReadUInt32(); _stfsMetaData.ConsoleID = _stfsStream.ReadBlock(0x5); _stfsMetaData.ProfileID = _stfsStream.ReadBlock(0x8); _stfsMetaData.VolumeDescriptor = new xMetaData.xVolumeDescription(); _stfsMetaData.VolumeDescriptor.VolumeDescriptorSize = _stfsStream.ReadByte(); _stfsStream.ReadByte(); _stfsStream.ReadByte(); _stfsMetaData.VolumeDescriptor.FileTableBlockCount = _stfsStream.ReadInt16(); _stfsMetaData.VolumeDescriptor.FileTableBlockNumber = _stfsStream.ReadInt24(); _stfsMetaData.VolumeDescriptor.TopHashTableHash = _stfsStream.ReadBlock(0x14); _stfsMetaData.VolumeDescriptor.TotalAllocatedBlockCount = _stfsStream.ReadInt32(); _stfsMetaData.VolumeDescriptor.TotalUnallocatedBlockCount = _stfsStream.ReadInt32(); _stfsStream.SeekTo(0x39D); _stfsMetaData.DataFileCount = _stfsStream.ReadInt32(); _stfsMetaData.DataFileCombinedSize = _stfsStream.ReadInt64(); _stfsStream.SeekTo(0x3FD); _stfsMetaData.DeviceID = _stfsStream.ReadBlock(0x14); _stfsMetaData.DisplayName = _stfsStream.ReadUTF16(); _stfsStream.SeekTo(0xD11); _stfsMetaData.DisplayDescription = _stfsStream.ReadUTF16(); _stfsStream.SeekTo(0x1611); _stfsMetaData.PublisherName = _stfsStream.ReadUTF16(); _stfsStream.SeekTo(0x1691); _stfsMetaData.TitleName = _stfsStream.ReadUTF16(); _stfsStream.SeekTo(0x1711); _stfsMetaData.TransferFlags = (TransferFlags)_stfsStream.ReadByte(); _stfsMetaData.ThumbnailImage = new xMetaData.xMetaImage(); _stfsMetaData.TitleThumbnailImage = new xMetaData.xMetaImage(); _stfsMetaData.ThumbnailImage.ImageSize = _stfsStream.ReadInt32(); _stfsMetaData.TitleThumbnailImage.ImageSize = _stfsStream.ReadInt32(); _stfsMetaData.ThumbnailImage.Image = _stfsStream.ReadBlock(_stfsMetaData.ThumbnailImage.ImageSize); _stfsStream.SeekTo(0x571A); _stfsMetaData.TitleThumbnailImage.Image = _stfsStream.ReadBlock(_stfsMetaData.TitleThumbnailImage.ImageSize); }
/// <summary> /// Read block infos and create uncompressed stream with corresponding data /// </summary> /// <param name="blockStream">Stream with block infos</param> /// <param name="blockPosition">BlockInfos position within block stream</param> /// <param name="dataStream">Stream with compressed data</param> /// <param name="dataPosition">CompressedData position within data stream</param> /// <returns>Uncompressed data stream</returns> private EndianStream ParseBundle6BlockInfo(EndianStream blockStream, ref long blockPosition, EndianStream dataStream, ref long dataPosition) { // dataStream and blockStream could be same stream. so we should handle this situation properly MemoryStream memStream = null; EndianStream resultStream = null; long read = 0; blockStream.BaseStream.Position = blockPosition; blockStream.BaseStream.Position += 0x10; int blockCount = blockStream.ReadInt32(); blockPosition = blockStream.BaseStream.Position; for (int i = 0; i < blockCount; i++) { // prepare block position blockStream.BaseStream.Position = blockPosition; int decompressSize = blockStream.ReadInt32(); int compressSize = blockStream.ReadInt32(); int flag = blockStream.ReadInt16(); blockPosition = blockStream.BaseStream.Position; dataStream.BaseStream.Position = dataPosition; BundleCompressType compressType = (BundleCompressType)(flag & 0x3F); if (i == 0) { if (compressType == BundleCompressType.None) { resultStream = dataStream; m_isNewDataStream = false; } else { memStream = new MemoryStream(); resultStream = new EndianStream(memStream, EndianType.BigEndian); m_isNewDataStream = true; } } else { if (compressType != BundleCompressType.None && !m_isNewDataStream) { // TODO: if first block is none compressed then we should create stream and copy all previous blocks into it // but for now just throw exception throw new NotImplementedException("None compression"); } } switch (compressType) { case BundleCompressType.None: if (m_isNewDataStream) { if (decompressSize != compressSize) { throw new Exception($"Compressed {compressSize} and decompressed {decompressSize} sizes differ"); } dataStream.BaseStream.CopyStream(memStream, compressSize); } break; case BundleCompressType.LZMA: SevenZipHelper.DecompressLZMAStream(dataStream.BaseStream, compressSize, memStream, decompressSize); break; case BundleCompressType.LZ4: case BundleCompressType.LZ4HZ: using (Lz4Stream lzStream = new Lz4Stream(dataStream.BaseStream, compressSize)) { lzStream.Read(memStream, decompressSize); } break; default: throw new NotImplementedException($"Bundle compression '{compressType}' isn't supported"); } dataPosition += compressSize; read += compressSize; if (m_isNewDataStream) { if (dataPosition != dataStream.BaseStream.Position) { throw new Exception($"Read data length is differ from compressed size for {i}th block"); } } } // update position acording to result stream if (m_isNewDataStream) { dataPosition = 0; } else { dataPosition -= read; } return(resultStream); }