public static byte[] CreateBundleFromLevel(AssetsManager am, AssetsFileInstance inst) { AssetsFile file = inst.file; AssetsFileTable table = inst.table; string folderName = Path.GetDirectoryName(inst.path); ulong pathId = 2; List <AssetsReplacer> assets = new List <AssetsReplacer>(); Dictionary <AssetID, ulong> assetMap = new Dictionary <AssetID, ulong>(); //get all sprites int i = 0; List <AssetFileInfoEx> infos = table.GetAssetsOfType(0xD4); List <ulong> spriteIds = new List <ulong>(); foreach (AssetFileInfoEx info in infos) { //honestly this is a really trash way to do this //we have a better scene exporter but it would //take some work to fix it up and block certain assets EditorUtility.DisplayProgressBar("HKEdit", "Creating scene bundle", i / (float)infos.Count); AssetTypeValueField baseField = GetBaseField(am, file, info); AssetTypeValueField m_Sprite = baseField.Get("m_Sprite"); AssetFileInfoEx spriteInfo = am.GetExtAsset(inst, m_Sprite, true).info; AssetsFileInstance spriteInst; if (m_Sprite.Get("m_FileID").GetValue().AsInt() == 0) { spriteInst = inst; } else { spriteInst = inst.dependencies[m_Sprite.Get("m_FileID").GetValue().AsInt() - 1]; } int spriteFileId = m_Sprite.Get("m_FileID").GetValue().AsInt(); long spritePathId = m_Sprite.Get("m_PathID").GetValue().AsInt64(); if (assetMap.ContainsKey(new AssetID(Path.GetFileName(spriteInst.path), spritePathId)) || (spriteFileId == 0 && spritePathId == 0)) { i++; continue; } AssetTypeValueField spriteBaseField = GetBaseField(am, spriteInst.file, spriteInfo); AssetTypeValueField m_RD = spriteBaseField.Get("m_RD"); AssetTypeValueField texture = m_RD.Get("texture"); AssetTypeValueField alphaTexture = m_RD.Get("alphaTexture"); AssetsFileInstance textureInst, alphaTextureInst; if (texture.Get("m_FileID").GetValue().AsInt() == 0) { textureInst = spriteInst; } else { textureInst = spriteInst.dependencies[texture.Get("m_FileID").GetValue().AsInt() - 1]; } if (alphaTexture.Get("m_FileID").GetValue().AsInt() == 0) { alphaTextureInst = spriteInst; } else { alphaTextureInst = spriteInst.dependencies[alphaTexture.Get("m_FileID").GetValue().AsInt() - 1]; } AssetTypeInstance textureAti = am.GetExtAsset(spriteInst, texture, false).instance; AssetTypeInstance alphaTextureAti = am.GetExtAsset(spriteInst, alphaTexture, false).instance; ulong textureId = 0, alphaTextureId = 0; if (textureAti != null) { AssetID id = new AssetID(Path.GetFileName(textureInst.path), texture.Get("m_PathID").GetValue().AsInt64()); if (!assetMap.ContainsKey(id)) { textureId = pathId; assetMap.Add(id, pathId); assets.Add(TextureConverter.ConvertTexture(textureAti.GetBaseField(), pathId++, folderName)); } else { textureId = assetMap[id]; } } if (alphaTextureAti != null) { AssetID id = new AssetID(Path.GetFileName(alphaTextureInst.path), alphaTexture.Get("m_PathID").GetValue().AsInt64()); if (!assetMap.ContainsKey(id)) { alphaTextureId = pathId; assetMap.Add(id, pathId); assets.Add(TextureConverter.ConvertTexture(alphaTextureAti.GetBaseField(), pathId++, folderName)); } else { alphaTextureId = assetMap[id]; } } AssetTypeValueField m_Materials = baseField.Get("m_Materials").Get("Array"); if (m_Materials.GetValue().AsArray().size > 0) { AssetTypeValueField material = baseField.Get("m_Materials").Get("Array")[0]; AssetsFileInstance materialInst; int materialFileId = material.Get("m_FileID").GetValue().AsInt(); if (materialFileId == 0) { materialInst = inst; } else { materialInst = inst.dependencies[materialFileId - 1]; } AssetID materialId = new AssetID(Path.GetFileName(materialInst.path), material.Get("m_PathID").GetValue().AsInt64()); if (!assetMap.ContainsKey(materialId)) { AssetTypeValueField materialBaseField = am.GetExtAsset(inst, material).instance.GetBaseField(); AssetTypeValueField shader = materialBaseField.Get("m_Shader"); ulong shaderPathId = RecurseShaderDependencies(am, materialInst, pathId, shader, assets, assetMap, out pathId); assetMap.Add(materialId, pathId); assets.Add(MaterialConverter.ConvertMaterial(materialBaseField, pathId++, shaderPathId)); } } assetMap.Add(new AssetID(Path.GetFileName(spriteInst.path), spritePathId), pathId); spriteIds.Add(pathId); assets.Add(SpriteConverter.ConvertSprite(spriteBaseField, pathId++, textureId, alphaTextureId)); i++; } assetMap.Add(new AssetID(0), pathId); assets.Add(HeaderInformation.CreateHeaderInformation(assetMap, pathId++)); assets.Insert(0, BundleMeta.CreateBundleInformation(assetMap, spriteIds, 1)); //assets.Add(BundleMeta.CreateBundleInformation(assetMap, 1)); //todo: pull from original assets file, cldb is not always update to date List <Type_0D> types = new List <Type_0D> { FixTypeTree(C2T5.Cldb2TypeTree(am.classFile, 0x8E)), //AssetBundle FixTypeTree(C2T5.Cldb2TypeTree(am.classFile, 0x1C)), //Texture2D FixTypeTree(C2T5.Cldb2TypeTree(am.classFile, 0x31)), //TextAsset FixTypeTree(C2T5.Cldb2TypeTree(am.classFile, 0xD4)), //SpriteRenderer FixTypeTree(C2T5.Cldb2TypeTree(am.classFile, 0xD5)), //Sprite //FixTypeTree(C2T5.Cldb2TypeTree(am.classFile, 0x31)), //TextAsset FixTypeTree(C2T5.Cldb2TypeTree(am.classFile, 0x15)), //Material FixTypeTree(C2T5.Cldb2TypeTree(am.classFile, 0x30)) //Shader }; const string ver = "2017.4.10f1"; //const string ver = "2018.2.1f1"; byte[] blankData = BundleCreator.CreateBlankAssets(ver, types); AssetsFile blankFile = new AssetsFile(new AssetsFileReader(new MemoryStream(blankData))); byte[] data = null; using (MemoryStream ms = new MemoryStream()) using (AssetsFileWriter writer = new AssetsFileWriter(ms)) { blankFile.WriteFix(writer, 0, assets.ToArray(), 0); data = ms.ToArray(); } EditorUtility.DisplayProgressBar("HKEdit", "Creating bundle", 1); using (MemoryStream ms = new MemoryStream()) using (AssetsFileWriter writer = new AssetsFileWriter(ms)) { BundleCreator.CreateBlankBundle(ver, data.Length).Write(writer, data); return(ms.ToArray()); } }
public static byte[] CreateBundleFromLevel(AssetsManager am, /*byte[] data,*/ AssetsFileInstance inst, string sceneName, DiffFile diffFile, string bunPath) { AssetsFile file = inst.file; AssetsFileTable table = inst.table; string folderName = Path.GetDirectoryName(inst.path); //string sceneName = Path.GetFileNameWithoutExtension(inst.path) + "_mod"; List <AssetsReplacer> assetsSA = new List <AssetsReplacer>(); List <AssetFileInfoEx> infos = table.pAssetFileInfo.ToList(); //List<int> typeIds = new List<int>(); //foreach (AssetFileInfoEx info in infos) //{ // int typeId = (int)info.curFileType; // if (!typeIds.Contains(typeId) && typeId != 0x72) // typeIds.Add(typeId); //} assetsSA.Add(PreloadData.CreatePreloadData(1)); assetsSA.Add(BundleMeta.CreateBundleInformation(sceneName, 2)); //todo: pull from original assets file, cldb is not always update to date List <Type_0D> types = new List <Type_0D>(); //foreach (int typeId in typeIds) //{ // types.Add(C2T5.Cldb2TypeTree(am.classFile, typeId)); //} List <Type_0D> typesSA = new List <Type_0D> { C2T5.Cldb2TypeTree(am.classFile, 0x96), //PreloadData C2T5.Cldb2TypeTree(am.classFile, 0x8E) //AssetBundle }; const string ver = "2017.4.10f1"; List <AssetsReplacer> replacers = new List <AssetsReplacer>(); //UnityEngine.Debug.Log("HKWE DM " + diffFile.magic); //UnityEngine.Debug.Log("HKWE GC " + diffFile.changes.Count + diffFile.adds.Count + diffFile.removes.Count); //AssetsReplacerFromMemory mem = MoveTest.RunMoveTest(table.getAssetInfo(2642), am.GetATI(file, table.getAssetInfo(2642)).GetBaseField(), 2642) as AssetsReplacerFromMemory; foreach (GameObjectChange goChange in diffFile.changes) { //UnityEngine.Debug.Log("HKWE GO " + goChange.pathId); foreach (ComponentChangeOrAdd compChange in goChange.changes) { AssetFileInfoEx goInfo = table.getAssetInfo((ulong)goChange.pathId); AssetTypeValueField goBaseField = am.GetATI(file, goInfo).GetBaseField(); AssetTypeValueField compPptr = goBaseField.Get("m_Component").Get("Array")[(uint)compChange.componentIndex].Get("component"); AssetsManager.AssetExternal compExt = am.GetExtAsset(inst, compPptr); AssetFileInfoEx compInfo = compExt.info; AssetTypeValueField compBaseField = compExt.instance.GetBaseField(); //UnityEngine.Debug.Log("HKWE LR " + compInfo.index); AssetsReplacer imAlreadyReplacer = ComponentDiffReplacer.DiffComponent(compInfo, compBaseField, am.classFile, compChange, compInfo.index); replacers.Add(imAlreadyReplacer); } } AssetsManager amBun = new AssetsManager(); //we create a new manager because the two filenames will probably conflict amBun.classFile = am.classFile; //we can just reuse the classfile which is kinda hacky AssetsFileInstance bunInst = amBun.LoadAssetsFile(new MemoryStream(GetBundleData(bunPath, 0)), "HKWEDiffs", false); //placeholder path since we have no deps //rearrange the pathids immediately after the //last one from the level to keep unity happy ulong levelLargestPathID = 0; foreach (AssetFileInfoEx inf in table.pAssetFileInfo) { if (inf.index > levelLargestPathID) { levelLargestPathID = inf.index; } } ReferenceCrawler.ReorderIds(amBun, bunInst, levelLargestPathID + 1); byte[] bunSAInst = GetBundleData(bunPath, 1); //HashSet<ulong> addedDeps = new HashSet<ulong>(); foreach (AssetFileInfoEx inf in bunInst.table.pAssetFileInfo) { replacers.Add(MakeReplacer(inf.index, am, bunInst, inst, inf, bunSAInst, types)); } //foreach (GameObjectInfo inf in diffFile.infos) //{ // Debug.Log("7"); // ulong bunPathId = GetBundlePathId(amBun, bunInst, inf); // // AssetFileInfoEx objInf = bunInst.table.getAssetInfo(bunPathId); // replacers.Add(MakeReplacer(bunPathId, am, bunInst, inst, objInf, bunSAInst, types)); // // List<ulong> deps = ReferenceCrawler.CrawlPPtrs(amBun, bunInst, bunPathId); // foreach (ulong dep in deps) // { // if (!addedDeps.Contains(dep)) // { // addedDeps.Add(dep); // AssetFileInfoEx depInf = bunInst.table.getAssetInfo(dep); // //if (depInf.curFileType == 0x01 || depInf.curFileType == 0x04 || depInf.curFileType == 0xD4 || depInf.curFileType == 0x15 || depInf.curFileType == 0xD5) // //{ // // continue; // //} // replacers.Add(MakeReplacer(dep, am, bunInst, inst, depInf, bunSAInst, types)); // } // } // ////its possible to get a collision but very unlikely since unity already randomizes ids which are 8 bytes long // ////there's nothing here to test if a collision would be created so just hope that you don't win the lottery // //ulong bunPathId = GetBundlePathId(amBun, bunInst, inf); // ////AssetFileInfoEx afInf = bunInst.table.getAssetInfo(bunPathId); // ////replacers.Add(MakeReplacer(bunPathId, afInf, bunInst.stream)); // //List<ulong> deps = ReferenceCrawler.CrawlPPtrs(am, bunInst, bunPathId); // ////if (info.curFileType == 0x01 || info.curFileType == 0x04 || info.curFileType == 0xD4) // ////{ // //// continue; // ////} // //foreach (ulong dep in deps) // //{ // // AssetFileInfoEx depInf = bunInst.table.getAssetInfo(dep); // // //MakeReplacer(dep, am, bunInst, inst, depInf, bunSAInst, types); // // AssetsReplacerFromMemory ar = MakeReplacer(dep, am, bunInst, inst, depInf, bunSAInst, types); // // //todo- I guess this was just for testing purposes to block out everything, remove this at some point // // if (depInf.curFileType == 0x01 || depInf.curFileType == 0x04 || depInf.curFileType == 0xD4 || depInf.curFileType == 0x15 || depInf.curFileType == 0xD5) //depInf.curFileType == 0x1C // // { // // continue; // // } // // replacers.Add(ar); // //} //} byte[] data = null; using (MemoryStream ms = new MemoryStream()) using (AssetsFileWriter writer = new AssetsFileWriter(ms)) { //file.typeTree.hasTypeTree = true; //so we don't have to calculate hashes //foreach (Type_0D type in file.typeTree.pTypes_Unity5) //{ // if (!types.Any(t => t.classId == type.classId)) // { // types.Insert(0, C2T5.Cldb2TypeTree(am.classFile, type.classId)); // } //} file.typeTree.pTypes_Unity5 = file.typeTree.pTypes_Unity5.Concat(types.ToArray()).ToArray(); //file.typeTree.pTypes_Unity5 = types.ToArray(); file.typeTree.fieldCount = (uint)file.typeTree.pTypes_Unity5.Length; //file.typeTree.fieldCount = (uint)types.Count; file.Write(writer, 0, replacers.ToArray(), 0); data = ms.ToArray(); } //File.WriteAllBytes("_bundlefinal1.unity3d", data); byte[] blankDataSA = BundleCreator.CreateBlankAssets(ver, typesSA); AssetsFile blankFileSA = new AssetsFile(new AssetsFileReader(new MemoryStream(blankDataSA))); byte[] dataSA = null; using (MemoryStream ms = new MemoryStream()) using (AssetsFileWriter writer = new AssetsFileWriter(ms)) { blankFileSA.Write(writer, 0, assetsSA.ToArray(), 0); dataSA = ms.ToArray(); } using (MemoryStream ms = new MemoryStream()) using (AssetsFileWriter writer = new AssetsFileWriter(ms)) { AssetsBundleFile bundle = BundleCreator.CreateBlankBundle(ver, data.Length, dataSA.Length, sceneName); bundle.Write(writer); writer.Write(dataSA); writer.Write(data); return(ms.ToArray()); } }