public void AddReplacer(AssetsFileInstance forFile, AssetsReplacer replacer, Stream? previewStream = null) { AssetsFile assetsFile = forFile.file; AssetID assetId = new AssetID(forFile.path, replacer.GetPathID()); if (NewAssets.ContainsKey(assetId)) RemoveReplacer(forFile, NewAssets[assetId], true); NewAssets[assetId] = replacer; //make stream to use as a replacement to the one from file if (previewStream == null) { MemoryStream newStream = new MemoryStream(); AssetsFileWriter newWriter = new AssetsFileWriter(newStream); replacer.Write(newWriter); newStream.Position = 0; previewStream = newStream; } NewAssetDatas[assetId] = previewStream; if (!(replacer is AssetsRemover)) { AssetsFileReader reader = new AssetsFileReader(previewStream); AssetContainer cont = new AssetContainer( reader, 0, replacer.GetPathID(), (uint)replacer.GetClassID(), replacer.GetMonoScriptID(), (uint)previewStream.Length, forFile); LoadedAssets[assetId] = cont; } else { LoadedAssets.Remove(assetId); } if (ItemUpdated != null) ItemUpdated(forFile, assetId); Modified = true; }
//AssetsFile public static ulong WriteFix(this AssetsFile file, AssetsFileWriter writer, ulong filePos, AssetsReplacer[] pReplacers, uint fileID, ClassDatabaseFile typeMeta = null) { file.header.Write(writer.Position, writer); for (int i = 0; i < pReplacers.Length; i++) { AssetsReplacer replacer = pReplacers[i]; if (!file.typeTree.pTypes_Unity5.Any(t => t.classId == replacer.GetClassID())) { Type_0D type = new Type_0D() { classId = replacer.GetClassID(), unknown16_1 = 0, scriptIndex = 0xFFFF, unknown5 = 0, unknown6 = 0, unknown7 = 0, unknown8 = 0, typeFieldsExCount = 0, stringTableLen = 0, pStringTable = "" }; file.typeTree.pTypes_Unity5.Concat(new Type_0D[] { type }); } } file.typeTree.Write(writer.Position, writer, file.header.format); int initialSize = (int)(AssetFileInfo.GetSize(file.header.format) * file.AssetCount); int newSize = (int)(AssetFileInfo.GetSize(file.header.format) * (file.AssetCount + pReplacers.Length)); int appendedSize = newSize - initialSize; file.reader.Position = file.AssetTablePos; List <AssetFileInfo> originalAssetInfos = new List <AssetFileInfo>(); List <AssetFileInfo> assetInfos = new List <AssetFileInfo>(); List <AssetsReplacer> currentReplacers = pReplacers.ToList(); uint currentOffset = 0; //-write all original assets, modify sizes if needed and skip those to be removed for (int i = 0; i < file.AssetCount; i++) { AssetFileInfo info = new AssetFileInfo(); info.Read(file.header.format, file.reader.Position, file.reader, file.reader.bigEndian); originalAssetInfos.Add(info); AssetsReplacer replacer = currentReplacers.FirstOrDefault(n => n.GetPathID() == info.index); if (replacer != null) { currentReplacers.Remove(replacer); if (replacer.GetReplacementType() == AssetsReplacementType.AssetsReplacement_AddOrModify) { int classIndex = Array.FindIndex(file.typeTree.pTypes_Unity5, t => t.classId == replacer.GetClassID()); info = new AssetFileInfo() { index = replacer.GetPathID(), offs_curFile = currentOffset, curFileSize = (uint)replacer.GetSize(), curFileTypeOrIndex = (uint)classIndex, inheritedUnityClass = (ushort)replacer.GetClassID(), //-what is this scriptIndex = replacer.GetMonoScriptID(), unknown1 = 0 }; } else if (replacer.GetReplacementType() == AssetsReplacementType.AssetsReplacement_Remove) { continue; } } currentOffset += info.curFileSize; uint pad = 8 - (currentOffset % 8); if (pad != 8) { currentOffset += pad; } assetInfos.Add(info); } //-write new assets while (currentReplacers.Count > 0) { AssetsReplacer replacer = currentReplacers.First(); if (replacer.GetReplacementType() == AssetsReplacementType.AssetsReplacement_AddOrModify) { int classIndex = Array.FindIndex(file.typeTree.pTypes_Unity5, t => t.classId == replacer.GetClassID()); AssetFileInfo info = new AssetFileInfo() { index = replacer.GetPathID(), offs_curFile = currentOffset, curFileSize = (uint)replacer.GetSize(), curFileTypeOrIndex = (uint)classIndex, inheritedUnityClass = (ushort)replacer.GetClassID(), scriptIndex = replacer.GetMonoScriptID(), unknown1 = 0 }; currentOffset += info.curFileSize; uint pad = 8 - (currentOffset % 8); if (pad != 8) { currentOffset += pad; } assetInfos.Add(info); } currentReplacers.Remove(replacer); } writer.Write(assetInfos.Count); writer.Align(); for (int i = 0; i < assetInfos.Count; i++) { assetInfos[i].Write(file.header.format, writer.Position, writer); } file.preloadTable.Write(writer.Position, writer, file.header.format); file.dependencies.Write(writer.Position, writer, file.header.format); uint metadataSize = (uint)writer.Position - 0x13; //-for padding only. if all initial data before assetData is more than 0x1000, this is skipped while (writer.Position < 0x1000 /*header.offs_firstFile*/) { writer.Write((byte)0x00); } writer.Align16(); uint offs_firstFile = (uint)writer.Position; for (int i = 0; i < assetInfos.Count; i++) { AssetFileInfo info = assetInfos[i]; AssetsReplacer replacer = pReplacers.FirstOrDefault(n => n.GetPathID() == info.index); if (replacer != null) { if (replacer.GetReplacementType() == AssetsReplacementType.AssetsReplacement_AddOrModify) { replacer.Write(writer.Position, writer); writer.Align8(); } else if (replacer.GetReplacementType() == AssetsReplacementType.AssetsReplacement_Remove) { continue; } } else { AssetFileInfo originalInfo = originalAssetInfos.FirstOrDefault(n => n.index == info.index); if (originalInfo != null) { file.reader.Position = file.header.offs_firstFile + originalInfo.offs_curFile; byte[] assetData = file.reader.ReadBytes((int)originalInfo.curFileSize); writer.Write(assetData); writer.Align8(); } } } file.header.offs_firstFile = offs_firstFile; ulong fileSizeMarker = writer.Position; file.reader.Position = file.header.offs_firstFile; writer.Position = 0; file.header.metadataSize = metadataSize; file.header.fileSize = (uint)fileSizeMarker; file.header.Write(writer.Position, writer); return(writer.Position); }