private void GenerateTtrTree(Type_0D type) { ttr_tree.Nodes.Clear(); List <TreeNode> treeNodeStack = new List <TreeNode>(); TypeField_0D baseField = type.typeFieldsEx[0]; TreeNode rootNode = ttr_tree.Nodes.Add(TypeFieldToString(baseField, type)); rootNode.Tag = baseField; treeNodeStack.Add(rootNode); for (int i = 1; i < type.typeFieldsEx.Length; i++) { TypeField_0D field = type.typeFieldsEx[i]; TreeNode parentNode = treeNodeStack[field.depth - 1]; TreeNode node = parentNode.Nodes.Add(TypeFieldToString(field, type)); node.Tag = field; if (treeNodeStack.Count > field.depth) { treeNodeStack[field.depth] = node; } else { treeNodeStack.Add(node); } } }
private void Ttr_list_SelectedIndexChanged(object sender, EventArgs e) { Type_0D type = file.typeTree.pTypes_Unity5[ttr_list.SelectedIndex]; if (type.typeFieldsExCount == 0) { ClassDatabaseType cldt = cldb.classes.First(c => c.classId == type.classId); ttr_type.Text = cldt.name.GetString(cldb); } else { TypeField_0D baseField = type.pTypeFieldsEx[0]; ttr_type.Text = baseField.GetTypeString(type.pStringTable); } ttr_typeid.Text = type.classId.ToString(); ttr_scriptid.Text = type.scriptIndex.ToString(); if (type.unknown5 != 0 || type.unknown6 != 0 || type.unknown7 != 0 || type.unknown8 != 0) { ttr_hash.Text = $"{type.unknown5.ToString("x8")}{type.unknown6.ToString("x8")}{type.unknown7.ToString("x8")}{type.unknown8.ToString("x8")}"; } else { ttr_hash.Text = ""; } if (type.unknown1 != 0 || type.unknown2 != 0 || type.unknown3 != 0 || type.unknown4 != 0) { ttr_monohash.Text = $"{type.unknown1.ToString("x8")}{type.unknown2.ToString("x8")}{type.unknown3.ToString("x8")}{type.unknown4.ToString("x8")}"; } else { ttr_monohash.Text = ""; } }
private static void CreateSceneMetadataTypeTree(ClassDatabaseFile cldb, AssetsFileInstance inst) { Type_0D type = C2T5.Cldb2TypeTree(cldb, 0x72); type.scriptIndex = 0x0001; type.unknown1 = Constants.sceneMetadataScriptNEHash[0]; type.unknown2 = Constants.sceneMetadataScriptNEHash[1]; type.unknown3 = Constants.sceneMetadataScriptNEHash[2]; type.unknown4 = Constants.sceneMetadataScriptNEHash[3]; TypeTreeEditor editor = new TypeTreeEditor(type); TypeField_0D baseField = type.pTypeFieldsEx[0]; uint sceneName = editor.AddField(baseField, editor.CreateTypeField("string", "sceneName", 1, uint.MaxValue, 0, false, false, Flags.AnyChildUsesAlignBytesFlag)); uint Array = editor.AddField(editor.type.pTypeFieldsEx[sceneName], editor.CreateTypeField("Array", "Array", 2, uint.MaxValue, 0, true, true, Flags.HideInEditorMask)); editor.AddField(editor.type.pTypeFieldsEx[Array], editor.CreateTypeField("int", "size", 3, 4, 0, false, false, Flags.HideInEditorMask)); editor.AddField(editor.type.pTypeFieldsEx[Array], editor.CreateTypeField("char", "data", 3, 1, 0, false, false, Flags.HideInEditorMask)); uint usedIds = editor.AddField(baseField, editor.CreateTypeField("vector", "usedIds", 1, uint.MaxValue, 0, false, false, Flags.AnyChildUsesAlignBytesFlag)); uint Array2 = editor.AddField(editor.type.pTypeFieldsEx[usedIds], editor.CreateTypeField("Array", "Array", 2, uint.MaxValue, 0, true, true)); editor.AddField(editor.type.pTypeFieldsEx[Array2], editor.CreateTypeField("int", "size", 3, 4, 0, false)); editor.AddField(editor.type.pTypeFieldsEx[Array2], editor.CreateTypeField("SInt64", "data", 3, 8, 0, false)); editor.AddField(baseField, editor.CreateTypeField("int", "hkweVersion", 1, 4, 0, false)); type = editor.SaveType(); inst.file.typeTree.pTypes_Unity5 = inst.file.typeTree.pTypes_Unity5.Concat(new Type_0D[] { type }).ToArray(); inst.file.typeTree.fieldCount++; }
///////////////////////////////////////////////////////// private static Type_0D CreateEditDifferTypeTree(ClassDatabaseFile cldb) { Type_0D type = C2T5.Cldb2TypeTree(cldb, 0x72); type.scriptIndex = 0x0000; type.unknown1 = Constants.editDifferScriptNEHash[0]; type.unknown2 = Constants.editDifferScriptNEHash[1]; type.unknown3 = Constants.editDifferScriptNEHash[2]; type.unknown4 = Constants.editDifferScriptNEHash[3]; TypeTreeEditor editor = new TypeTreeEditor(type); TypeField_0D baseField = type.pTypeFieldsEx[0]; editor.AddField(baseField, editor.CreateTypeField("unsigned int", "fileId", 1, 4, 0, false)); editor.AddField(baseField, editor.CreateTypeField("UInt64", "pathId", 1, 8, 0, false)); editor.AddField(baseField, editor.CreateTypeField("UInt64", "origPathId", 1, 8, 0, false)); editor.AddField(baseField, editor.CreateTypeField("UInt8", "newAsset", 1, 1, 0, true)); uint componentIds = editor.AddField(baseField, editor.CreateTypeField("vector", "componentIds", 1, uint.MaxValue, 0, false, false, Flags.AnyChildUsesAlignBytesFlag)); uint Array = editor.AddField(editor.type.pTypeFieldsEx[componentIds], editor.CreateTypeField("Array", "Array", 2, uint.MaxValue, 0, true, true)); editor.AddField(editor.type.pTypeFieldsEx[Array], editor.CreateTypeField("int", "size", 3, 4, 0, false)); editor.AddField(editor.type.pTypeFieldsEx[Array], editor.CreateTypeField("SInt64", "data", 3, 8, 0, false)); editor.AddField(baseField, editor.CreateTypeField("int", "instanceId", 1, 4, 0, false)); type = editor.SaveType(); return(type); }
private void XRefsDialog_Load(object sender, EventArgs e) { List <AssetID> xrefs = map.GetXRefs(id); if (xrefs == null) { xrefList.Items.Add("[no xrefs]"); } else { foreach (AssetID id in xrefs) { int instIndex = am.files.FindIndex(f => Path.GetFileName(f.path).ToLower() == Path.GetFileName(id.fileName).ToLower()); if (instIndex != -1) { AssetsFileInstance xrefInst = am.files[instIndex]; AssetsFile xrefFile = xrefInst.file; AssetFileInfoEx xrefInf = xrefInst.table.GetAssetInfo(id.pathID); uint fixedId = AssetHelper.FixAudioID(xrefInf.curFileType); bool hasTypeTree = xrefFile.typeTree.hasTypeTree; string assetName = AssetHelper.GetAssetNameFast(xrefFile, am.classFile, xrefInf); string typeName; if (hasTypeTree) { Type_0D xrefType = AssetHelper.FindTypeTreeTypeByID(xrefFile.typeTree, fixedId); typeName = xrefType.typeFieldsEx[0].GetTypeString(xrefType.stringTable); } else { ClassDatabaseType xrefType = AssetHelper.FindAssetClassByID(am.classFile, fixedId); typeName = xrefType.name.GetString(am.classFile); } xrefList.Items.Add(new ListBoxInfo($"{id.fileName} {id.pathID} ({typeName} {assetName})", id)); } else { xrefList.Items.Add(new ListBoxInfo($"{id.fileName} {id.pathID}", id)); } } } }
public uint _fmt; //not stored here in the .assets file, the variable is just to remember the .assets file version public ulong Read(ulong absFilePos, AssetsFileReader reader, uint version, bool bigEndian) { unityVersion = reader.ReadNullTerminated(); this.version = reader.ReadUInt32(); hasTypeTree = reader.ReadBoolean(); fieldCount = reader.ReadUInt32(); pTypes_Unity5 = new Type_0D[fieldCount]; for (int i = 0; i < fieldCount; i++) { Type_0D type0d = new Type_0D(); type0d.Read(hasTypeTree, reader.Position, reader, version, version, bigEndian); pTypes_Unity5[i] = type0d; } if (version < 0x0E) { dwUnknown = reader.ReadUInt24(); } _fmt = version; //-todo: figure out what the heck this is for. if ver = -1 on write does it set it to default or something? return(reader.Position); }//Minimum AssetsFile format : 6
public ulong Read(ulong absFilePos, AssetsFileReader reader, uint version, bool bigEndian) { unityVersion = reader.ReadNullTerminated(); this.version = reader.ReadUInt32(); hasTypeTree = reader.ReadBoolean(); fieldCount = reader.ReadUInt32(); pTypes_Unity5 = new Type_0D[fieldCount]; for (int i = 0; i < fieldCount; i++) { Type_0D type0d = new Type_0D(); type0d.Read(hasTypeTree, reader.Position, reader, version, version, bigEndian); pTypes_Unity5[i] = type0d; } if (version < 0x0E) { dwUnknown = reader.ReadUInt32(); } _fmt = version; return(reader.Position); }
private void Ttr_list_SelectedIndexChanged(object sender, EventArgs e) { TypeTree typeTree = file.typeTree; Type_0D type = typeTree.unity5Types[ttr_list.SelectedIndex]; if (type.typeFieldsExCount == 0) { ClassDatabaseType cldt = cldb.classes.First(c => c.classId == type.classId); ttr_type.Text = cldt.name.GetString(cldb); } else { TypeField_0D baseField = type.typeFieldsEx[0]; ttr_type.Text = baseField.GetTypeString(type.stringTable); } ttr_typeid.Text = type.classId.ToString(); ttr_scriptid.Text = type.scriptIndex.ToString(); if (type.typeHash1 != 0 || type.typeHash2 != 0 || type.typeHash3 != 0 || type.typeHash4 != 0) { ttr_hash.Text = $"{type.typeHash1.ToString("x8")}{type.typeHash2.ToString("x8")}{type.typeHash3.ToString("x8")}{type.typeHash4.ToString("x8")}"; } else { ttr_hash.Text = ""; } if (type.scriptHash1 != 0 || type.scriptHash2 != 0 || type.scriptHash3 != 0 || type.scriptHash4 != 0) { ttr_monohash.Text = $"{type.scriptHash1.ToString("x8")}{type.scriptHash2.ToString("x8")}{type.scriptHash3.ToString("x8")}{type.scriptHash4.ToString("x8")}"; } else { ttr_monohash.Text = ""; } if (typeTree.hasTypeTree) { GenerateTtrTree(type); } }
public AssetTypeTemplateField GetTemplateField(AssetsFile file, uint type, ushort scriptIndex) { uint fixedId = AssetHelper.FixAudioID(type); bool hasTypeTree = file.typeTree.hasTypeTree; AssetTypeTemplateField baseField = new AssetTypeTemplateField(); if (hasTypeTree) { Type_0D type0d = Extensions.FindTypeTreeTypeByID(file.typeTree, fixedId, scriptIndex); if (type0d != null && type0d.typeFieldsExCount > 0) baseField.From0D(type0d, 0); else //fallback to cldb baseField.FromClassDatabase(am.classFile, AssetHelper.FindAssetClassByID(am.classFile, fixedId), 0); } else { baseField.FromClassDatabase(am.classFile, AssetHelper.FindAssetClassByID(am.classFile, fixedId), 0); } return baseField; }
private static Type_0D CreateTk2dEmuTypeTree(ClassDatabaseFile cldb) { Type_0D type = C2T5.Cldb2TypeTree(cldb, 0x72); type.scriptIndex = 0x0001; type.scriptHash1 = Constants.tk2dEmuScriptNEHash[0]; type.scriptHash2 = Constants.tk2dEmuScriptNEHash[1]; type.scriptHash3 = Constants.tk2dEmuScriptNEHash[2]; type.scriptHash4 = Constants.tk2dEmuScriptNEHash[3]; TypeTreeEditor editor = new TypeTreeEditor(type); TypeField_0D baseField = type.typeFieldsEx[0]; uint vertices = editor.AddField(baseField, editor.CreateTypeField("vector", "vertices", 1, -1, 0, false, false, Flags.AnyChildUsesAlignBytesFlag)); uint Array = editor.AddField(editor.type.typeFieldsEx[vertices], editor.CreateTypeField("Array", "Array", 2, -1, 0, true, true)); editor.AddField(editor.type.typeFieldsEx[Array], editor.CreateTypeField("int", "size", 3, 4, 0, false)); uint data = editor.AddField(editor.type.typeFieldsEx[Array], editor.CreateTypeField("Vector3", "data", 3, -1, 0, false)); editor.AddField(editor.type.typeFieldsEx[data], editor.CreateTypeField("float", "x", 4, 4, 0, false)); editor.AddField(editor.type.typeFieldsEx[data], editor.CreateTypeField("float", "y", 4, 4, 0, false)); editor.AddField(editor.type.typeFieldsEx[data], editor.CreateTypeField("float", "z", 4, 4, 0, false)); uint uvs = editor.AddField(baseField, editor.CreateTypeField("vector", "uvs", 1, -1, 0, false, false, Flags.AnyChildUsesAlignBytesFlag)); Array = editor.AddField(editor.type.typeFieldsEx[uvs], editor.CreateTypeField("Array", "Array", 2, -1, 0, true, true)); editor.AddField(editor.type.typeFieldsEx[Array], editor.CreateTypeField("int", "size", 3, 4, 0, false)); data = editor.AddField(editor.type.typeFieldsEx[Array], editor.CreateTypeField("Vector2", "data", 3, -1, 0, false)); editor.AddField(editor.type.typeFieldsEx[data], editor.CreateTypeField("float", "x", 4, 4, 0, false)); editor.AddField(editor.type.typeFieldsEx[data], editor.CreateTypeField("float", "y", 4, 4, 0, false)); uint indices = editor.AddField(baseField, editor.CreateTypeField("vector", "indices", 1, -1, 0, false, false, Flags.AnyChildUsesAlignBytesFlag)); Array = editor.AddField(editor.type.typeFieldsEx[indices], editor.CreateTypeField("Array", "Array", 2, -1, 0, true, true)); editor.AddField(editor.type.typeFieldsEx[Array], editor.CreateTypeField("int", "size", 3, 4, 0, false)); editor.AddField(editor.type.typeFieldsEx[Array], editor.CreateTypeField("int", "data", 3, 4, 0, false)); type = editor.SaveType(); return(type); }
///////////////////////////////////////////////////////// private static void CreateEditDifferTypeTree(ClassDatabaseFile cldb, AssetsFileInstance inst) { Type_0D type = C2T5.Cldb2TypeTree(cldb, 0x72); type.scriptIndex = 0x0000; type.unknown1 = Constants.editDifferScriptNEHash[0]; type.unknown2 = Constants.editDifferScriptNEHash[1]; type.unknown3 = Constants.editDifferScriptNEHash[2]; type.unknown4 = Constants.editDifferScriptNEHash[3]; TypeTreeEditor editor = new TypeTreeEditor(type); TypeField_0D baseField = type.pTypeFieldsEx[0]; editor.AddField(baseField, editor.CreateTypeField("unsigned int", "fileId", 1, 4, 0, false)); editor.AddField(baseField, editor.CreateTypeField("UInt64", "pathId", 1, 8, 0, false)); editor.AddField(baseField, editor.CreateTypeField("UInt64", "origPathId", 1, 8, 0, false)); editor.AddField(baseField, editor.CreateTypeField("UInt8", "newAsset", 1, 1, 0, true)); editor.AddField(baseField, editor.CreateTypeField("int", "instanceId", 1, 4, 0, false)); type = editor.SaveType(); inst.file.typeTree.pTypes_Unity5 = inst.file.typeTree.pTypes_Unity5.Concat(new Type_0D[] { type }).ToArray(); inst.file.typeTree.fieldCount++; }
public static Type_0D FixTypeTree(Type_0D tt) { //if basefield isn't 3, unity won't load the bundle tt.pTypeFieldsEx[0].version = 3; return(tt); }
public TypeField_0D[] TemplateToTypeField(AssetTypeTemplateField[] fields, Type_0D stringTableType) { return(TemplateToTypeField(fields, stringTableType.pStringTable)); }
public static Type_0D Cldb2TypeTree(ClassDatabaseFile classes, int id) { ClassDatabaseType type = classes.classes.Where(c => c.classId == id).First(); Type_0D type0d = new Type_0D() { classId = type.classId, typeFieldsExCount = (uint)type.fields.Count, scriptIndex = 0xFFFF, unknown16_1 = 0, scriptHash1 = 0, scriptHash2 = 0, scriptHash3 = 0, scriptHash4 = 0, typeHash1 = 0, typeHash2 = 0, typeHash3 = 0, typeHash4 = 0 }; string stringTable = ""; Dictionary <string, uint> strTableList = new Dictionary <string, uint>(); Dictionary <string, uint> defTableList = new Dictionary <string, uint>(); uint strTablePos = 0; uint defTablePos = 0; string[] defaultTable = Type_0D.strTable.Split('\0'); foreach (string entry in defaultTable) { if (entry != "") { defTableList.Add(entry, defTablePos); defTablePos += (uint)entry.Length + 1; } } List <TypeField_0D> field0ds = new List <TypeField_0D>(); for (int i = 0; i < type.fields.Count; i++) { ClassDatabaseTypeField field = type.fields[i]; string fieldName = field.fieldName.GetString(classes); string typeName = field.typeName.GetString(classes); uint fieldNamePos = 0xFFFFFFFF; uint typeNamePos = 0xFFFFFFFF; if (strTableList.ContainsKey(fieldName)) { fieldNamePos = strTableList[fieldName]; } else if (defTableList.ContainsKey(fieldName)) { fieldNamePos = defTableList[fieldName] + 0x80000000; } else { fieldNamePos = strTablePos; strTableList.Add(fieldName, strTablePos); strTablePos += (uint)fieldName.Length + 1; } if (strTableList.ContainsKey(typeName)) { typeNamePos = strTableList[typeName]; } else if (defTableList.ContainsKey(typeName)) { typeNamePos = defTableList[typeName] + 0x80000000; } else { typeNamePos = strTablePos; strTableList.Add(typeName, strTablePos); strTablePos += (uint)typeName.Length + 1; } field0ds.Add(new TypeField_0D() { depth = field.depth, flags = field.flags2, index = (uint)i, isArray = field.isArray, nameStringOffset = fieldNamePos, size = field.size, typeStringOffset = typeNamePos, version = field.version }); } List <KeyValuePair <string, uint> > sortedStrTableList = strTableList.OrderBy(n => n.Value).ToList(); foreach (KeyValuePair <string, uint> entry in sortedStrTableList) { stringTable += entry.Key + '\0'; } type0d.stringTable = stringTable; type0d.stringTableLen = (uint)stringTable.Length; type0d.typeFieldsEx = field0ds.ToArray(); return(type0d); }
public static string GetAssetNameFast(AssetsFile file, ClassDatabaseFile cldb, AssetFileInfoEx info) { ClassDatabaseType type = FindAssetClassByID(cldb, info.curFileType); AssetsFileReader reader = file.reader; if (file.typeTree.hasTypeTree) { Type_0D ttType = file.typeTree.unity5Types[info.curFileTypeOrIndex]; string ttTypeName = ttType.typeFieldsEx[0].GetTypeString(ttType.stringTable); if (ttType.typeFieldsEx.Length == 0) { return(type.name.GetString(cldb)); //fallback to cldb } if (ttType.typeFieldsEx.Length > 1 && ttType.typeFieldsEx[1].GetNameString(ttType.stringTable) == "m_Name") { reader.Position = info.absoluteFilePos; return(reader.ReadCountStringInt32()); } //todo, use the typetree since we have it already, there could be extra fields else if (ttTypeName == "GameObject") { reader.Position = info.absoluteFilePos; int size = reader.ReadInt32(); int componentSize = file.header.format > 0x10 ? 0x0c : 0x10; reader.Position += size * componentSize; reader.Position += 0x04; return(reader.ReadCountStringInt32()); } else if (ttTypeName == "MonoBehaviour") { reader.Position = info.absoluteFilePos; reader.Position += 0x1c; string name = reader.ReadCountStringInt32(); if (name != "") { return(name); } } return(ttTypeName); } string typeName = type.name.GetString(cldb); if (type.fields.Count == 0) { return(type.name.GetString(cldb)); } if (type.fields.Count > 1 && type.fields[1].fieldName.GetString(cldb) == "m_Name") { reader.Position = info.absoluteFilePos; return(reader.ReadCountStringInt32()); } else if (typeName == "GameObject") { reader.Position = info.absoluteFilePos; int size = reader.ReadInt32(); int componentSize = file.header.format > 0x10 ? 0x0c : 0x10; reader.Position += size * componentSize; reader.Position += 0x04; return(reader.ReadCountStringInt32()); } else if (typeName == "MonoBehaviour") { reader.Position = info.absoluteFilePos; reader.Position += 0x1c; string name = reader.ReadCountStringInt32(); if (name != "") { return(name); } } return(typeName); }
public TypeTreeEditor(Type_0D type) { NullToDict(strTableList, ref strTablePos, type.stringTable); NullToDict(defTableList, ref defTablePos, Type_0D.strTable); this.type = type; }
private ObservableCollection <AssetInfoDataGridItem> MakeDataGridItems() { dataGridItems = new ObservableCollection <AssetInfoDataGridItem>(); bool usingTypeTree = assetsFile.file.typeTree.hasTypeTree; foreach (AssetFileInfoEx info in assetsFile.table.assetFileInfo) { string name; string container; string type; int fileId; long pathId; int size; string modified; ClassDatabaseType cldbType = AssetHelper.FindAssetClassByID(am.classFile, info.curFileType); name = AssetHelper.GetAssetNameFast(assetsFile.file, am.classFile, info); //handles both cldb and typetree container = string.Empty; fileId = 0; pathId = info.index; size = (int)info.curFileSize; modified = ""; if (usingTypeTree) { Type_0D ttType = assetsFile.file.typeTree.unity5Types[info.curFileTypeOrIndex]; if (ttType.typeFieldsEx.Length != 0) { type = ttType.typeFieldsEx[0].GetTypeString(ttType.stringTable); } else { if (cldbType != null) { type = cldbType.name.GetString(am.classFile); } else { type = $"0x{info.curFileType:X8}"; } } } else { if (cldbType != null) { type = cldbType.name.GetString(am.classFile); } else { type = $"0x{info.curFileType:X8}"; } } if (info.curFileType == 0x01) { name = $"GameObject {name}"; } if (name == string.Empty) { name = "Unnamed asset"; } var item = new AssetInfoDataGridItem() { Name = name, Container = container, Type = type, TypeID = info.curFileType, FileID = fileId, PathID = pathId, Size = size, Modified = modified }; dataGridItems.Add(item); } return(dataGridItems); }
public static void GenerateDiffFile(AssetsManager am, AssetsFileInstance buildInst, AssetsFileInstance sceneInst, HKWEMeta meta) { EditorUtility.DisplayProgressBar("HKEdit", "Reading dependencies...", 0.5f); am.UpdateDependencies(); ClassDatabaseFile cldb = am.classFile; DiffData result = new DiffData() { goChanges = new List <GameObjectChange>(), goAdditions = new List <GameObjectAddition>() }; Dictionary <EditDifferData, long> differToSceneId = new Dictionary <EditDifferData, long>(); Dictionary <long, EditDifferData> buildIdToDiffer = new Dictionary <long, EditDifferData>(); List <EditDifferData> differData = new List <EditDifferData>(); AssetsFileTable sceneTable = sceneInst.table; List <AssetFileInfoEx> sceneGos = sceneTable.GetAssetsOfType(0x01); for (int i = 0; i < sceneGos.Count; i++) { if (i % 100 == 0) { EditorUtility.DisplayProgressBar("HKEdit", "Finding diff IDs... (step 1/3)", (float)i / sceneGos.Count); } AssetFileInfoEx inf = sceneGos[i]; AssetTypeValueField baseField = am.GetATI(sceneInst.file, inf).GetBaseField(); AssetTypeValueField editDifferMono = GetEDMono(am, sceneInst, baseField); EditDifferData diff = new EditDifferData() { fileId = editDifferMono.Get("fileId").GetValue().AsInt(), pathId = editDifferMono.Get("pathId").GetValue().AsInt64(), origPathId = editDifferMono.Get("origPathId").GetValue().AsInt64(), newAsset = editDifferMono.Get("newAsset").GetValue().AsBool() }; buildIdToDiffer[diff.origPathId] = diff; differToSceneId[diff] = inf.index; differData.Add(diff); } ////////////////////////// AssetsFileTable origTable = buildInst.table; List <AssetFileInfoEx> origGos = origTable.GetAssetsOfType(0x01); List <long> origDeletIds = new List <long>(); //int nextBundleId = 1; //// == delete changes == // //for (int i = 0; i < origGos.Count; i++) //{ // if (i % 100 == 0) // EditorUtility.DisplayProgressBar("HKEdit", "Checking for deletes... (step 2/3)", (float)i / origGos.Count); // AssetFileInfoEx inf = sceneGos[i]; // if (!differData.Any(d => d.origPathId == inf.index)) // { // GameObjectChange change = new GameObjectChange // { // flags = GameObjectChangeFlags.Deleted // }; // result.goChanges.Add(change); // origDeletIds.Add(inf.index); // } //} // == add changes == // //to get this working in a built game, we need //built assets (ie pngs -> texture2d) the problem //is there's no easy way to direct unity to do that //without loading the scene and using unity's api //but we can pull out assets into a prefab and build //the prefab but there are problems with duplicate //dependencies being copied, so we pack them all //into one place so that doesn't happen //(for reference, in hkwe1, each gameobject got //its own prefab) //find dependencies ReferenceCrawlerBundle createdCrawler = new ReferenceCrawlerBundle(am); //assets created by the user in the ditor ReferenceCrawlerBundle existingCrawler = new ReferenceCrawlerBundle(am); //assets that already existed in the scene for (int i = 0; i < differData.Count; i++) { if (i % 100 == 0) { EditorUtility.DisplayProgressBar("HKEdit", "Checking for additions... (step 2/3)", (float)i / differData.Count); } EditDifferData dat = differData[i]; if (dat.newAsset) { long sceneId = differToSceneId[dat]; AssetFileInfoEx inf = sceneInst.table.GetAssetInfo(sceneId); createdCrawler.SetReferences(sceneInst, inf); GameObjectAddition addition = new GameObjectAddition { bundleId = createdCrawler.GetNextId(), //? sceneId = dat.pathId, dependencies = new List <GameObjectAdditionDependency>() }; //nextBundleId++; foreach (KeyValuePair <AssetID, AssetID> goRef in createdCrawler.references) { addition.dependencies.Add(new GameObjectAdditionDependency { sceneId = goRef.Key.pathId, bundleId = goRef.Value.pathId }); } result.goAdditions.Add(addition); } else { long newPathId = differToSceneId[dat]; AssetFileInfoEx inf = sceneInst.table.GetAssetInfo(newPathId); existingCrawler.SetReferences(sceneInst, inf); } } //load up all created assets into a prefab List <Type_0D> types = new List <Type_0D>(); List <string> typeNames = new List <string>(); foreach (AssetsReplacer rep in createdCrawler.sceneReplacers) { ClassDatabaseType clType = AssetHelper.FindAssetClassByID(cldb, (uint)rep.GetClassID()); string clName = clType.name.GetString(cldb); if (!typeNames.Contains(clName)) { Type_0D type0d = C2T5.Cldb2TypeTree(cldb, clName); type0d.classId = clType.classId; types.Add(type0d); typeNames.Add(clName); } } List <AssetsReplacer> replacers = new List <AssetsReplacer>(); replacers.Add(CreatePrefabAsset(2)); //better hope id 2 is a gameobject replacers.AddRange(createdCrawler.sceneReplacers); AssetsFile createdFile = new AssetsFile(new AssetsFileReader(new MemoryStream(BundleCreator.CreateBlankAssets(ver, types)))); byte[] data; using (MemoryStream ms = new MemoryStream()) using (AssetsFileWriter writer = new AssetsFileWriter(ms)) { createdFile.Write(writer, 0, replacers, 0); data = ms.ToArray(); } }
private string TypeFieldToString(TypeField_0D field, Type_0D type) { string stringTable = type.stringTable; return($"{field.GetTypeString(stringTable)} {field.GetNameString(stringTable)}"); }
public static Type_0D Cldb2TypeTree(ClassDatabaseFile classes, int id) { ClassDatabaseType type = classes.classes.Where(c => c.classId == id).First(); Type_0D type0d = new Type_0D() { classId = type.classId, typeFieldsExCount = (uint)type.fields.Count, scriptIndex = 0xFFFF, unknown16_1 = 0, unknown1 = 0, unknown2 = 0, unknown3 = 0, unknown4 = 0, unknown5 = 0, unknown6 = 0, unknown7 = 0, unknown8 = 0 }; string stringTable = ""; List <TypeField_0D> field0ds = new List <TypeField_0D>(); for (int i = 0; i < type.fields.Count; i++) { ClassDatabaseTypeField field = type.fields[i]; string fieldName = field.fieldName.GetString(classes) + '\0'; string typeName = field.typeName.GetString(classes) + '\0'; uint fieldNamePos = 0xFFFFFFFF; uint typeNamePos = 0xFFFFFFFF; if (stringTable.Contains(fieldName)) { fieldNamePos = (uint)stringTable.IndexOf(fieldName); } else if (Type_0D.strTable.Contains(fieldName)) { fieldNamePos = (uint)Type_0D.strTable.IndexOf(fieldName) + 0x80000000; } else { fieldNamePos = (uint)stringTable.Length; stringTable += fieldName; } if (stringTable.Contains(typeName)) { typeNamePos = (uint)stringTable.IndexOf(typeName); } else if (Type_0D.strTable.Contains(typeName)) { typeNamePos = (uint)Type_0D.strTable.IndexOf(typeName) + 0x80000000; } else { typeNamePos = (uint)stringTable.Length; stringTable += typeName; } field0ds.Add(new TypeField_0D() { depth = field.depth, flags = field.flags2, index = (uint)i, isArray = field.isArray == 1 ? true : false, nameStringOffset = fieldNamePos, size = field.size, typeStringOffset = typeNamePos, version = field.version }); } type0d.pStringTable = stringTable; type0d.stringTableLen = (uint)stringTable.Length; type0d.pTypeFieldsEx = field0ds.ToArray(); return(type0d); }
//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); }
public static void GenerateLevelFiles(AssetsManager am, AssetsFileInstance inst) { EditorUtility.DisplayProgressBar("HKEdit", "Reading dependencies...", 0.5f); am.UpdateDependencies(); //quicker asset id lookup for (int i = 0; i < am.files.Count; i++) { AssetsFileInstance afi = am.files[i]; if (i % 100 == 0) { EditorUtility.DisplayProgressBar("HKEdit", "Generating QLTs...", (float)i / am.files.Count); } afi.table.GenerateQuickLookupTree(); } ClassDatabaseFile cldb = am.classFile; AssetsFileTable table = inst.table; ReferenceCrawler crawler = new ReferenceCrawler(am); List <AssetFileInfoEx> initialGameObjects = table.GetAssetsOfType(0x01); for (int i = 0; i < initialGameObjects.Count; i++) { if (i % 100 == 0) { EditorUtility.DisplayProgressBar("HKEdit", "Recursing GameObject dependencies... (step 1/3)", (float)i / initialGameObjects.Count); } AssetFileInfoEx inf = initialGameObjects[i]; crawler.AddReference(new AssetID(inst.path, (long)inf.index), false); crawler.FindReferences(inst, inf); } Dictionary <AssetID, AssetID> glblToLcl = crawler.references; List <Type_0D> types = new List <Type_0D>(); List <string> typeNames = new List <string>(); Dictionary <string, AssetsFileInstance> fileToInst = am.files.ToDictionary(d => d.path); int j = 0; foreach (KeyValuePair <AssetID, AssetID> id in glblToLcl) { if (j % 100 == 0) { EditorUtility.DisplayProgressBar("HKEdit", "Rewiring asset pointers... (step 2/3)", (float)j / glblToLcl.Count); } AssetsFileInstance depInst = fileToInst[id.Key.fileName]; AssetFileInfoEx depInf = depInst.table.getAssetInfo((ulong)id.Key.pathId); ClassDatabaseType clType = AssetHelper.FindAssetClassByID(cldb, depInf.curFileType); string clName = clType.name.GetString(cldb); if (!typeNames.Contains(clName)) { Type_0D type0d = C2T5.Cldb2TypeTree(cldb, clName); type0d.classId = (int)depInf.curFileType; types.Add(type0d); typeNames.Add(clName); } crawler.ReplaceReferences(depInst, depInf, id.Value.pathId); j++; } EditorUtility.DisplayProgressBar("HKEdit", "Saving scene... (step 3/3)", 1f); types.Add(CreateEditDifferTypeTree(cldb)); List <Type_0D> assetTypes = new List <Type_0D>() { C2T5.Cldb2TypeTree(cldb, 0x1c), C2T5.Cldb2TypeTree(cldb, 0x30), C2T5.Cldb2TypeTree(cldb, 0x53) }; string origFileName = Path.GetFileNameWithoutExtension(inst.path); string sceneGuid = CreateMD5(origFileName); string ExportedScenes = Path.Combine("Assets", "ExportedScenes"); //circumvents "!BeginsWithCaseInsensitive(file.pathName, AssetDatabase::kAssetsPathWithSlash)' assertion string ExportedScenesData = "ExportedScenesData"; CreateMetaFile(sceneGuid, Path.Combine(ExportedScenes, origFileName + ".unity.meta")); AssetsFile sceneFile = new AssetsFile(new AssetsFileReader(new MemoryStream(BundleCreator.CreateBlankAssets(ver, types)))); AssetsFile assetFile = new AssetsFile(new AssetsFileReader(new MemoryStream(BundleCreator.CreateBlankAssets(ver, assetTypes)))); byte[] sceneFileData; using (MemoryStream ms = new MemoryStream()) using (AssetsFileWriter w = new AssetsFileWriter(ms)) { w.bigEndian = false; //unity editor won't load whole assets files by guid, so we have to use hardcoded paths sceneFile.dependencies.pDependencies = new AssetsFileDependency[] { CreateDependency(ExportedScenesData + "/" + origFileName + "-data.assets"), CreateScriptDependency(Constants.editDifferMsEditorScriptHash, Constants.editDifferLsEditorScriptHash) }; sceneFile.dependencies.dependencyCount = 2; sceneFile.preloadTable.items = new AssetPPtr[] { new AssetPPtr(2, 11500000) }; sceneFile.preloadTable.len = 1; sceneFile.Write(w, 0, crawler.sceneReplacers.Concat(crawler.sceneMonoReplacers).ToArray(), 0); sceneFileData = ms.ToArray(); } byte[] assetFileData; using (MemoryStream ms = new MemoryStream()) using (AssetsFileWriter w = new AssetsFileWriter(ms)) { w.bigEndian = false; assetFile.Write(w, 0, crawler.assetReplacers.ToArray(), 0); assetFileData = ms.ToArray(); } File.WriteAllBytes(Path.Combine(ExportedScenes, origFileName + ".unity"), sceneFileData); File.WriteAllBytes(Path.Combine(ExportedScenesData, origFileName + "-data.assets"), assetFileData); File.WriteAllText(Path.Combine(ExportedScenesData, origFileName + ".metadata"), CreateHKWEMetaFile(am, inst)); EditorUtility.ClearProgressBar(); }
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); }