public void AddReplacer(byte[] data, int type, ushort monoType, bool isAsset) { int id = isAsset ? assetId : sceneId; AssetsReplacer replacer = new AssetsReplacerFromMemory(0, id, type, monoType, data); if (IsAsset(type)) { assetReplacers.Add(replacer); } else if (type == 0x72) { sceneMonoReplacers.Add(replacer); } else { sceneReplacers.Add(replacer); } if (isAsset) { assetId++; } else { sceneId++; } }
private static void ReplacePointers(AssetsFileInstance file, AssetFileInfoEx info, long pathId) { var baseField = am.GetATI(file.file, info).GetBaseField(); FindNestedPointers(file, baseField, info, true); FinalizeAsset(file, baseField, info); byte[] baseFieldData; using (MemoryStream ms = new MemoryStream()) using (AssetsFileWriter w = new AssetsFileWriter(ms)) { w.bigEndian = false; // Copy all data from base field into byte array baseField.Write(w); baseFieldData = ms.ToArray(); } AssetsReplacer replacer = new AssetsReplacerFromMemory(0, (ulong)pathId, (int)info.curFileType, 0xFFFF, baseFieldData); if (IsAsset(info)) { assetReplacers.Add(replacer); } //else if (info.curFileType == 0x73) monoReplacers.Add(replacer); else { sceneReplacers.Add(replacer); } }
public async Task <bool> BatchImport(Window win, AssetWorkspace workspace, List <AssetContainer> selection) { OpenFolderDialog ofd = new OpenFolderDialog(); ofd.Title = "Select import directory"; string dir = await ofd.ShowAsync(win); if (dir != null && dir != string.Empty) { ImportBatch dialog = new ImportBatch(workspace, selection, dir, ".png"); List <ImportBatchInfo> batchInfos = await dialog.ShowDialog <List <ImportBatchInfo> >(win); foreach (ImportBatchInfo batchInfo in batchInfos) { AssetContainer cont = batchInfo.cont; AssetTypeValueField baseField = workspace.GetBaseField(cont); string file = batchInfo.importFile; byte[] byteData = File.ReadAllBytes(file); baseField.Get("m_Script").GetValue().Set(byteData); byte[] savedAsset = baseField.WriteToByteArray(); var replacer = new AssetsReplacerFromMemory( 0, cont.PathId, (int)cont.ClassId, cont.MonoId, savedAsset); workspace.AddReplacer(cont.FileInstance, replacer, new MemoryStream(savedAsset)); } return(true); } return(false); }
//replaces the PPtr entries in each asset with the new pathId //(.Key with .Value in the references dictionary) and fixes some //specific problems with assets like GameObject or Texture2D //(stored in sceneReplacers and assetReplacers) public void ReplaceReferences(AssetsFileInstance inst, AssetFileInfoEx inf, long pathId) { AssetTypeValueField baseField = am.GetATI(inst.file, inf).GetBaseField(); FixAssetPre(inst, baseField, inf); ReplaceReferencesRecurse(inst, baseField, inf); FixAssetPost(inst, baseField, inf); byte[] baseFieldData; using (MemoryStream ms = new MemoryStream()) using (AssetsFileWriter w = new AssetsFileWriter(ms)) { w.bigEndian = false; baseField.Write(w); baseFieldData = ms.ToArray(); } AssetsReplacer replacer = new AssetsReplacerFromMemory(0, pathId, (int)inf.curFileType, 0xFFFF, baseFieldData); if (IsAsset(inf)) { assetReplacers.Add(replacer); } else if (inf.curFileType == 0x72) { sceneMonoReplacers.Add(replacer); } else { sceneReplacers.Add(replacer); } }
public void AddReplacer(byte[] data, int type, ushort monoType) { AssetsReplacer replacer = new AssetsReplacerFromMemory(0, sceneId, type, monoType, data); if (type != 0x72) { sceneReplacers.Add(replacer); } sceneId++; }
public void ReplaceReferences(AssetsFileInstance inst, AssetFileInfoEx inf, long pathId) { AssetTypeValueField baseField = am.GetATI(inst.file, inf).GetBaseField(); ReplaceReferencesRecurse(inst, baseField, inf); //FixAsset(baseField, inf); byte[] baseFieldData = baseField.WriteToByteArray(); AssetsReplacer replacer = new AssetsReplacerFromMemory(0, pathId, (int)inf.curFileType, 0xFFFF, baseFieldData); if (inf.curFileType != 0x72) { sceneReplacers.Add(replacer); } }
private void ImportAssets() { var inf = currentFile.table.GetAssetInfo("MyBoringAsset"); var baseField = helper.GetATI(currentFile.file, inf).GetBaseField(); baseField.Get("m_Name") .GetValue() .Set("MyCoolAsset"); var newGoBytes = baseField.WriteToByteArray(); //AssetsReplacerFromMemory's monoScriptIndex should always be 0xFFFF unless it's a MonoBehaviour var repl = new AssetsReplacerFromMemory(0, inf.index, (int)inf.curFileType, 0xFFFF, newGoBytes); var writer = new AssetsFileWriter(File.OpenWrite("resources-modified.assets")); currentFile.file.Write(writer, 1, new AssetsReplacer[] { repl }.ToList(), 1); }
public async Task <bool> SingleImport(Window win, AssetWorkspace workspace, List <AssetContainer> selection) { AssetContainer cont = selection[0]; OpenFileDialog ofd = new OpenFileDialog(); AssetTypeValueField baseField = workspace.GetBaseField(cont); ofd.Title = "Open text file"; ofd.Filters = new List <FileDialogFilter>() { new FileDialogFilter() { Name = "TXT file", Extensions = new List <string>() { "txt" } } }; string[] fileList = await ofd.ShowAsync(win); if (fileList.Length == 0) { return(false); } string file = fileList[0]; if (file != null && file != string.Empty) { byte[] byteData = File.ReadAllBytes(file); baseField.Get("m_Script").GetValue().Set(byteData); byte[] savedAsset = baseField.WriteToByteArray(); var replacer = new AssetsReplacerFromMemory( 0, cont.PathId, (int)cont.ClassId, cont.MonoId, savedAsset); workspace.AddReplacer(cont.FileInstance, replacer, new MemoryStream(savedAsset)); } return(false); }
public async Task <bool> ExecutePlugin(Window win, AssetWorkspace workspace, List <AssetContainer> selection) { for (int i = 0; i < selection.Count; i++) { selection[i] = new AssetContainer(selection[i], TextureHelper.GetByteArrayTexture(workspace, selection[i])); } OpenFolderDialog ofd = new OpenFolderDialog(); ofd.Title = "Select import directory"; string dir = await ofd.ShowAsync(win); if (dir != null && dir != string.Empty) { ImportBatch dialog = new ImportBatch(workspace, selection, dir, ".png"); List <ImportBatchInfo> batchInfos = await dialog.ShowDialog <List <ImportBatchInfo> >(win); bool success = await ImportTextures(win, batchInfos); if (success) { //some of the assets may not get modified, but //uabe still makes replacers for those anyway foreach (AssetContainer cont in selection) { byte[] savedAsset = cont.TypeInstance.WriteToByteArray(); var replacer = new AssetsReplacerFromMemory( 0, cont.PathId, (int)cont.ClassId, cont.MonoId, savedAsset); workspace.AddReplacer(cont.FileInstance, replacer, new MemoryStream(savedAsset)); } return(true); } else { return(false); } } return(false); }
public async Task <bool> ExecutePlugin(Window win, AssetWorkspace workspace, List <AssetContainer> selection) { AssetContainer cont = selection[0]; AssetTypeValueField texBaseField = TextureHelper.GetByteArrayTexture(workspace, cont).GetBaseField(); TextureFile texFile = TextureFile.ReadTextureFile(texBaseField); EditDialog dialog = new EditDialog(texFile.m_Name, texFile, texBaseField); bool saved = await dialog.ShowDialog <bool>(win); if (saved) { byte[] savedAsset = texBaseField.WriteToByteArray(); var replacer = new AssetsReplacerFromMemory( 0, cont.PathId, (int)cont.ClassId, cont.MonoId, savedAsset); workspace.AddReplacer(cont.FileInstance, replacer, new MemoryStream(savedAsset)); return(true); } return(false); }
public async Task <bool> ExecutePlugin(Window win, AssetWorkspace workspace, List <AssetExternal> selection) { AssetExternal tex = selection[0]; AssetTypeValueField texBaseField = tex.instance.GetBaseField(); TextureFile texFile = TextureFile.ReadTextureFile(texBaseField); EditDialog dialog = new EditDialog(texFile.m_Name, texFile, texBaseField); bool saved = await dialog.ShowDialog <bool>(win); if (saved) { byte[] savedAsset = texBaseField.WriteToByteArray(); var replacer = new AssetsReplacerFromMemory( 0, tex.info.index, (int)tex.info.curFileType, AssetHelper.GetScriptIndex(tex.file.file, tex.info), savedAsset); workspace.AddReplacer(tex.file, replacer, new MemoryStream(savedAsset)); return(true); } return(false); }
private static object ParseReplacer(AssetsFileReader reader, bool prefReplacersInMemory) { short replacerType = reader.ReadInt16(); byte fileType = reader.ReadByte(); if (fileType == 0) //BundleReplacer { string oldName = reader.ReadCountStringInt16(); string newName = reader.ReadCountStringInt16(); bool hasSerializedData = reader.ReadByte() != 0; //guess long replacerCount = reader.ReadInt64(); List <AssetsReplacer> replacers = new List <AssetsReplacer>(); for (int i = 0; i < replacerCount; i++) { AssetsReplacer assetReplacer = (AssetsReplacer)ParseReplacer(reader, prefReplacersInMemory); replacers.Add(assetReplacer); } if (replacerType == 4) //BundleReplacerFromAssets { //we have to null the assetsfile here and call init later BundleReplacer replacer = new BundleReplacerFromAssets(oldName, newName, null, replacers, 0); return(replacer); } } else if (fileType == 1) //AssetsReplacer { byte unknown01 = reader.ReadByte(); //always 1 int fileId = reader.ReadInt32(); long pathId = reader.ReadInt64(); int classId = reader.ReadInt32(); ushort monoScriptIndex = reader.ReadUInt16(); List <AssetPPtr> preloadDependencies = new List <AssetPPtr>(); int preloadDependencyCount = reader.ReadInt32(); for (int i = 0; i < preloadDependencyCount; i++) { AssetPPtr pptr = new AssetPPtr(reader.ReadInt32(), reader.ReadInt64()); preloadDependencies.Add(pptr); } if (replacerType == 0) //remover { AssetsReplacer replacer = new AssetsRemover(fileId, pathId, classId, monoScriptIndex); if (preloadDependencyCount != 0) { replacer.SetPreloadDependencies(preloadDependencies); } return(replacer); } else if (replacerType == 2) //adder/replacer? { Hash128? propertiesHash = null; Hash128? scriptHash = null; ClassDatabaseFile?classData = null; AssetsReplacer replacer; bool flag1 = reader.ReadByte() != 0; //no idea, couldn't get it to be 1 if (flag1) { throw new NotSupportedException("you just found a file with the mysterious flag1 set, send the file to nes"); } bool flag2 = reader.ReadByte() != 0; //has properties hash if (flag2) { propertiesHash = new Hash128(reader); } bool flag3 = reader.ReadByte() != 0; //has script hash if (flag3) { scriptHash = new Hash128(reader); } bool flag4 = reader.ReadByte() != 0; //has cldb if (flag4) { classData = new ClassDatabaseFile(); classData.Read(reader); } long bufLength = reader.ReadInt64(); if (prefReplacersInMemory) { byte[] buf = reader.ReadBytes((int)bufLength); replacer = new AssetsReplacerFromMemory(fileId, pathId, classId, monoScriptIndex, buf); } else { replacer = new AssetsReplacerFromStream(fileId, pathId, classId, monoScriptIndex, reader.BaseStream, reader.Position, bufLength); } if (propertiesHash != null) { replacer.SetPropertiesHash(propertiesHash.Value); } if (scriptHash != null) { replacer.SetScriptIDHash(scriptHash.Value); } if (scriptHash != null) { replacer.SetTypeInfo(classData, null, false); //idk what the last two are supposed to do } if (preloadDependencyCount != 0) { replacer.SetPreloadDependencies(preloadDependencies); } return(replacer); } } return(null); }
public static byte[] CreateBundleFromLevel(AssetsManager am, AssetsFileInstance inst) { EditorUtility.DisplayProgressBar("HKEdit", "Reading Files...", 0f); am.UpdateDependencies(); //quicker asset id lookup for (int i = 0; i < am.files.Count; i++) { AssetsFileInstance afi = am.files[i]; EditorUtility.DisplayProgressBar("HKEdit", "Generating QLTs", (float)i / am.files.Count); afi.table.GenerateQuickLookupTree(); } //setup AssetsFile file = inst.file; AssetsFileTable table = inst.table; string folderName = Path.GetDirectoryName(inst.path); List <AssetFileInfoEx> infos = table.pAssetFileInfo.ToList(); List <string> fileNames = new List <string>(); Dictionary <AssetID, byte[]> deps = new Dictionary <AssetID, byte[]>(); fileNames.Add(inst.name); //add own ids to list so we don't reread them foreach (AssetFileInfoEx info in infos) { if (info.curFileType != 1) { continue; } AssetID id = new AssetID(inst.name, (long)info.index); deps.Add(id, null); } //look through each field in each asset in this file for (int i = 0; i < infos.Count; i++) { AssetFileInfoEx info = infos[i]; if (info.curFileType != 1) { continue; } EditorUtility.DisplayProgressBar("HKEdit", "Crawling PPtrs", (float)i / infos.Count); ReferenceCrawler.CrawlPPtrs(am, inst, info.index, fileNames, deps); } //add typetree data for dependencies long curId = 1; List <Type_0D> types = new List <Type_0D>(); List <string> typeNames = new List <string>(); List <AssetsReplacer> assets = new List <AssetsReplacer>(); Dictionary <string, AssetsFileInstance> insts = new Dictionary <string, AssetsFileInstance>(); //asset id is our custom id that uses filename/pathid instead of fileid/pathid //asset id to path id Dictionary <AssetID, long> aidToPid = new Dictionary <AssetID, long>(); //script id to mono id Dictionary <ScriptID, ushort> sidToMid = new Dictionary <ScriptID, ushort>(); uint lastId = 0; ushort nextMonoId = 0; int depCount = 0; foreach (KeyValuePair <AssetID, byte[]> dep in deps) { EditorUtility.DisplayProgressBar("HKEdit", "Fixing Dependencies", (float)depCount / deps.Keys.Count); AssetID id = dep.Key; byte[] assetData = dep.Value; AssetsFileInstance afInst = null; if (insts.ContainsKey(id.fileName)) { afInst = insts[id.fileName]; } else { afInst = am.files.First(f => f.name == id.fileName); } if (afInst == null) { continue; } AssetFileInfoEx inf = afInst.table.getAssetInfo((ulong)id.pathId); if (lastId != inf.curFileType) { lastId = inf.curFileType; } ClassDatabaseType clType = AssetHelper.FindAssetClassByID(am.classFile, inf.curFileType); string clName = clType.name.GetString(am.classFile); ushort monoIndex = 0xFFFF; if (inf.curFileType != 0x72) { if (!typeNames.Contains(clName)) { Type_0D type0d = C2T5.Cldb2TypeTree(am.classFile, clName); type0d.classId = (int)inf.curFileType; //? types.Add(type0d); typeNames.Add(clName); } } else { //unused for now AssetTypeValueField baseField = am.GetATI(afInst.file, inf).GetBaseField(); AssetTypeValueField m_Script = baseField.Get("m_Script"); AssetTypeValueField scriptBaseField = am.GetExtAsset(afInst, m_Script).instance.GetBaseField(); string m_ClassName = scriptBaseField.Get("m_ClassName").GetValue().AsString(); string m_Namespace = scriptBaseField.Get("m_Namespace").GetValue().AsString(); string m_AssemblyName = scriptBaseField.Get("m_AssemblyName").GetValue().AsString(); ScriptID sid = new ScriptID(m_ClassName, m_Namespace, m_AssemblyName); if (!sidToMid.ContainsKey(sid)) { MonoClass mc = new MonoClass(); mc.Read(m_ClassName, Path.Combine(Path.Combine(Path.GetDirectoryName(inst.path), "Managed"), m_AssemblyName), afInst.file.header.format); Type_0D type0d = C2T5.Cldb2TypeTree(am.classFile, clName); TemplateFieldToType0D typeConverter = new TemplateFieldToType0D(); TypeField_0D[] monoFields = typeConverter.TemplateToTypeField(mc.children, type0d); type0d.pStringTable = typeConverter.stringTable; type0d.stringTableLen = (uint)type0d.pStringTable.Length; type0d.scriptIndex = nextMonoId; type0d.pTypeFieldsEx = type0d.pTypeFieldsEx.Concat(monoFields).ToArray(); type0d.typeFieldsExCount = (uint)type0d.pTypeFieldsEx.Length; types.Add(type0d); sidToMid.Add(sid, nextMonoId); nextMonoId++; } monoIndex = sidToMid[sid]; } aidToPid.Add(id, curId); AssetsReplacer rep = new AssetsReplacerFromMemory(0, (ulong)curId, (int)inf.curFileType, monoIndex, assetData); assets.Add(rep); curId++; depCount++; } byte[] blankData = BundleCreator.CreateBlankAssets(ver, types); AssetsFile blankFile = new AssetsFile(new AssetsFileReader(new MemoryStream(blankData))); EditorUtility.DisplayProgressBar("HKEdit", "Writing first file...", 0f); byte[] data = null; using (MemoryStream ms = new MemoryStream()) using (AssetsFileWriter writer = new AssetsFileWriter(ms)) { blankFile.Write(writer, 0, assets.ToArray(), 0); data = ms.ToArray(); } //File.WriteAllBytes("debug.assets", data); MemoryStream msn = new MemoryStream(data); AssetsManager amn = new AssetsManager(); amn.classFile = am.classFile; AssetsFileInstance instn = amn.LoadAssetsFile(msn, ((FileStream)inst.file.reader.BaseStream).Name, false); instn.table.GenerateQuickLookupTree(); deps.Clear(); List <AssetsReplacer> assetsn = new List <AssetsReplacer>(); //gameobject id to mono id Dictionary <long, long> gidToMid = new Dictionary <long, long>(); long nextBehaviourId = (long)instn.table.pAssetFileInfo.Max(i => i.index) + 1; CreateEditDifferTypeTree(amn.classFile, instn); CreateSceneMetadataTypeTree(amn.classFile, instn); Random rand = new Random(); rand.Next(); foreach (KeyValuePair <AssetID, long> kvp in aidToPid) { AssetFileInfoEx inf = instn.table.getAssetInfo((ulong)kvp.Value); if (inf.curFileType == 0x01) { gidToMid.Add(kvp.Value, nextBehaviourId); assetsn.Add(CreateEditDifferMonoBehaviour(kvp.Value, kvp.Key, nextBehaviourId++, rand)); } } for (int i = 0; i < instn.table.pAssetFileInfo.Length; i++) { AssetFileInfoEx inf = instn.table.pAssetFileInfo[i]; EditorUtility.DisplayProgressBar("HKEdit", "Crawling PPtrs", (float)i / instn.table.pAssetFileInfo.Length); ReferenceCrawler.CrawlReplacePPtrs(amn, instn, inf.index, fileNames, deps, aidToPid, gidToMid); } //add monoscript assets to preload table to make unity happy List <AssetPPtr> preloadPptrs = new List <AssetPPtr>(); preloadPptrs.Add(new AssetPPtr(1, 11500000)); preloadPptrs.Add(new AssetPPtr(2, 11500000)); foreach (KeyValuePair <AssetID, byte[]> dep in deps) { AssetID id = dep.Key; byte[] assetData = dep.Value; long pid = id.pathId; if (pid == 1) { assetData = AddMetadataMonobehaviour(assetData, nextBehaviourId); } AssetFileInfoEx inf = instn.table.getAssetInfo((ulong)pid); ushort monoId = instn.file.typeTree.pTypes_Unity5[inf.curFileTypeOrIndex].scriptIndex; assetsn.Add(new AssetsReplacerFromMemory(0, (ulong)pid, (int)inf.curFileType, monoId, assetData)); if (inf.curFileType == 0x73) { preloadPptrs.Add(new AssetPPtr(0, (ulong)pid)); } } List <long> usedIds = assetsn.Select(a => (long)a.GetPathID()).ToList(); //will break if no gameobjects but I don't really care at this point assetsn.Add(CreateSceneMetadataMonoBehaviour(1, nextBehaviourId++, inst.name, usedIds)); instn.file.preloadTable.items = preloadPptrs.ToArray(); instn.file.preloadTable.len = (uint)instn.file.preloadTable.items.Length; //add dependencies to monobehaviours List <AssetsFileDependency> fileDeps = new List <AssetsFileDependency>(); AddScriptDependency(fileDeps, Constants.editDifferMsEditorScriptHash, Constants.editDifferLsEditorScriptHash); AddScriptDependency(fileDeps, Constants.sceneMetadataMsEditorScriptHash, Constants.sceneMetadataLsEditorScriptHash); instn.file.dependencies.pDependencies = fileDeps.ToArray(); instn.file.dependencies.dependencyCount = (uint)fileDeps.Count; EditorUtility.DisplayProgressBar("HKEdit", "Writing second file...", 0f); byte[] datan = null; using (MemoryStream ms = new MemoryStream()) using (AssetsFileWriter writer = new AssetsFileWriter(ms)) { instn.file.Write(writer, 0, assetsn.ToArray(), 0); datan = ms.ToArray(); } EditorUtility.ClearProgressBar(); return(datan); }