public static AssetsReplacer CreatePreloadData(ulong pathId) { byte[] metaAsset = null; using (MemoryStream ms = new MemoryStream()) using (AssetsFileWriter writer = new AssetsFileWriter(ms)) { writer.bigEndian = false; writer.Write(0); writer.Align(); //writer.Write(gameObjects.Count); // //foreach (AssetID gameObject in gameObjects) //{ // writer.Write(gameObject.fileId); // writer.Write(gameObject.pathId); //} writer.Write(1); writer.Write(1); writer.Write((long)10001); writer.Align(); writer.Write(0); writer.Align(); //writer.Write(0); metaAsset = ms.ToArray(); } return(new AssetsReplacerFromMemory(0, pathId, 0x96, 0xFFFF, metaAsset)); }
private static AssetsReplacer CreateSceneMetadataMonoBehaviour(long goPid, long id, string sceneName, List <long> usedIds) { byte[] data; using (MemoryStream ms = new MemoryStream()) using (AssetsFileWriter w = new AssetsFileWriter(ms)) { w.bigEndian = false; w.Write(0); w.Write(goPid); w.Write(1); w.Write(2); w.Write((long)11500000); w.WriteCountStringInt32(""); w.Align(); w.WriteCountStringInt32(sceneName); w.Align(); w.Write(usedIds.Count); foreach (long usedId in usedIds) { w.Write(usedId); } w.Align(); w.Write(hkweVersion); data = ms.ToArray(); } return(new AssetsReplacerFromMemory(0, (ulong)id, 0x72, 0x0001, data)); }
private static AssetsReplacer CreatePrefabAsset(long rootId) { //the 2017 cldb doesn't have prefab in it so //we're on our own with binary writer again MemoryStream ms = new MemoryStream(); AssetsFileWriter writer = new AssetsFileWriter(ms); writer.bigEndian = false; writer.Write((uint)1); writer.Write(0); writer.Write((long)0); writer.Write(0); writer.Write(0); writer.Write(0); writer.Write((long)0); writer.Write(0); writer.Write(rootId); writer.Write((byte)0); writer.Align(); return(new AssetsReplacerFromMemory(0, 1, 0x3e9, 0xffff, ms.ToArray())); }
private byte[] CreateTk2DEmulatorMonoBehaviour(long goPid, Tk2dInfo tk2dInfo) { byte[] data; using (MemoryStream ms = new MemoryStream()) using (AssetsFileWriter w = new AssetsFileWriter(ms)) { w.bigEndian = false; w.Write(0); w.Write(goPid); w.Write(1); w.Write(3); w.Write((long)11500000); w.WriteCountStringInt32(""); w.Align(); w.Write(tk2dInfo.positions.Length); for (int i = 0; i < tk2dInfo.positions.Length; i++) { Vector3 position = tk2dInfo.positions[i]; w.Write(position.x); w.Write(position.y); w.Write(position.z); } w.Align(); w.Write(tk2dInfo.uvs.Length); for (int i = 0; i < tk2dInfo.uvs.Length; i++) { Vector3 uv = tk2dInfo.uvs[i]; w.Write(uv.x); w.Write(uv.y); } w.Align(); w.Write(tk2dInfo.indices.Length); for (int i = 0; i < tk2dInfo.indices.Length; i++) { w.Write(tk2dInfo.indices[i]); } w.Align(); data = ms.ToArray(); } return(data); }
private static AssetsReplacer CreateSceneMetadataGameObject(long tfPid, long mbPid, long id) { byte[] data; using (MemoryStream ms = new MemoryStream()) using (AssetsFileWriter w = new AssetsFileWriter(ms)) { w.bigEndian = false; w.Write(2); w.Write(0); w.Write(tfPid); w.Write(0); w.Write(mbPid); w.Write(0); w.Align(); w.WriteCountStringInt32("<//Hkwe Scene Metadata//>"); w.Align(); w.Write((ushort)0); w.Write((byte)1); data = ms.ToArray(); } return(new AssetsReplacerFromMemory(0, (ulong)id, 0x01, 0xFFFF, data)); }
public static AssetsReplacer CreateHeaderInformation(Dictionary <AssetID, ulong> files, ulong pathId) { byte[] textAsset = null; using (MemoryStream ms = new MemoryStream()) using (AssetsFileWriter writer = new AssetsFileWriter(ms)) { writer.bigEndian = false; writer.WriteCountStringInt32("AssetMap"); writer.Align(); StringBuilder builder = new StringBuilder(); foreach (KeyValuePair <AssetID, ulong> file in files) { AssetID key = file.Key; ulong value = file.Value; builder.Append(key.fileName + "," + key.pathId + "=" + value + ";"); } builder.Remove(builder.Length - 1, 1); writer.WriteCountStringInt32(builder.ToString()); writer.Align(); textAsset = ms.ToArray(); } return(new AssetsReplacerFromMemory(0, pathId, 0x31, 0xFFFF, textAsset)); }
private byte[] CreateEditDifferMonoBehaviour(long goPid, AssetTypeValueField componentArray, AssetID origGoPptr) { byte[] data; using (MemoryStream ms = new MemoryStream()) using (AssetsFileWriter w = new AssetsFileWriter(ms)) { w.bigEndian = false; w.Write(0); w.Write(goPid); w.Write(1); w.Write(2); w.Write((long)11500000); w.WriteCountStringInt32(""); w.Align(); w.Write(0); w.Write(origGoPptr.pathId); w.Write(origGoPptr.pathId); w.Write(0); int componentArrayLength = componentArray.GetValue().AsArray().size; w.Write(componentArrayLength); for (int i = 0; i < componentArrayLength; i++) { AssetTypeValueField component = componentArray[i].Get("component"); int m_FileID = component.Get("m_FileID").GetValue().AsInt(); long m_PathID = component.Get("m_PathID").GetValue().AsInt64(); if (m_PathID == 0) //removed (monobehaviour) { w.Write((long)-1); } else if (m_FileID == 0) //correct file { w.Write(m_PathID); } else //another file (shouldn't happen?) { w.Write((long)0); } } w.Write(0 /*rand.Next()*/); data = ms.ToArray(); } return(data); }
public static byte[] CreateBlankAssets(string engineVersion, List <Type_0D> types) { using (MemoryStream ms = new MemoryStream()) using (AssetsFileWriter writer = new AssetsFileWriter(ms)) { AssetsFileHeader header = new AssetsFileHeader() { metadataSize = 0, fileSize = 0x1000, format = 0x11, offs_firstFile = 0x1000, endianness = 0, unknown = new byte[] { 0, 0, 0 } }; TypeTree typeTree = new TypeTree() { unityVersion = engineVersion, version = 0x5, hasTypeTree = true, fieldCount = (uint)types.Count(), pTypes_Unity5 = types.ToArray() }; header.Write(writer.Position, writer); writer.bigEndian = false; typeTree.Write(writer.Position, writer, 0x11); writer.Write((uint)0); writer.Align(); //preload table and dependencies writer.Write((uint)0); writer.Write((uint)0); //due to a write bug in at.net we have to pad to 0x1000 while (ms.Position < 0x1000) { writer.Write((byte)0); } return(ms.ToArray()); } }
///////////////////////////////////////////////////////// // nope nothing to see here ///////////////////////////////////////////////////////// private static AssetsReplacer CreateEditDifferMonoBehaviour(long goPid, AssetID origGoPptr, long id, Random rand) { byte[] data; using (MemoryStream ms = new MemoryStream()) using (AssetsFileWriter w = new AssetsFileWriter(ms)) { w.bigEndian = false; w.Write(0); w.Write(goPid); w.Write(1); w.Write(1); w.Write((long)11500000); w.WriteCountStringInt32(""); w.Align(); w.Write(0); w.Write(origGoPptr.pathId); w.Write(origGoPptr.pathId); w.Write(0); w.Write(rand.Next()); data = ms.ToArray(); } return(new AssetsReplacerFromMemory(0, (ulong)id, 0x72, 0x0000, data)); }
//AssetTypeValueField public static void Write(this AssetTypeValueField valueField, AssetsFileWriter writer, int depth = 0) { if (valueField.templateField.isArray) { if (valueField.templateField.valueType == EnumValueTypes.ValueType_ByteArray) { AssetTypeByteArray byteArray = valueField.value.value.asByteArray; writer.Write(byteArray.size); writer.Write(byteArray.data); if (valueField.templateField.align) { writer.Align(); } } else { int size = valueField.value.value.asArray.size; writer.Write(size); for (int i = 0; i < size; i++) { valueField[i].Write(writer, depth + 1); } if (valueField.templateField.align) { writer.Align(); } } } else { if (valueField.childrenCount == 0) { switch (valueField.templateField.valueType) { case EnumValueTypes.ValueType_Int8: writer.Write(valueField.value.value.asInt8); if (valueField.templateField.align) { writer.Align(); } break; case EnumValueTypes.ValueType_UInt8: writer.Write(valueField.value.value.asUInt8); if (valueField.templateField.align) { writer.Align(); } break; case EnumValueTypes.ValueType_Bool: writer.Write(valueField.value.value.asBool); if (valueField.templateField.align) { writer.Align(); } break; case EnumValueTypes.ValueType_Int16: writer.Write(valueField.value.value.asInt16); if (valueField.templateField.align) { writer.Align(); } break; case EnumValueTypes.ValueType_UInt16: writer.Write(valueField.value.value.asUInt16); if (valueField.templateField.align) { writer.Align(); } break; case EnumValueTypes.ValueType_Int32: writer.Write(valueField.value.value.asInt32); break; case EnumValueTypes.ValueType_UInt32: writer.Write(valueField.value.value.asUInt32); break; case EnumValueTypes.ValueType_Int64: writer.Write(valueField.value.value.asInt64); break; case EnumValueTypes.ValueType_UInt64: writer.Write(valueField.value.value.asUInt64); break; case EnumValueTypes.ValueType_Float: writer.Write(valueField.value.value.asFloat); break; case EnumValueTypes.ValueType_Double: writer.Write(valueField.value.value.asDouble); break; case EnumValueTypes.ValueType_String: writer.WriteCountStringInt32(valueField.value.value.asString); writer.Align(); break; } } else { for (int i = 0; i < valueField.childrenCount; i++) { valueField[i].Write(writer, depth + 1); } if (valueField.templateField.align) { writer.Align(); } } } }
private void ImportTextAssetLoop() { Stack <bool> alignStack = new Stack <bool>(); while (true) { string?line = sr.ReadLine(); if (line == null) { return; } int thisDepth = 0; while (line[thisDepth] == ' ') { thisDepth++; } if (line[thisDepth] == '[') //array index, ignore { continue; } if (thisDepth < alignStack.Count) { while (thisDepth < alignStack.Count) { if (alignStack.Pop()) { aw.Align(); } } } bool align = line.Substring(thisDepth, 1) == "1"; int typeName = thisDepth + 2; int eqSign = line.IndexOf('='); string valueStr = line.Substring(eqSign + 1).Trim(); if (eqSign != -1) { string check = line.Substring(typeName); //this list may be incomplete if (StartsWithSpace(check, "bool")) { aw.Write(bool.Parse(valueStr)); } else if (StartsWithSpace(check, "UInt8")) { aw.Write(byte.Parse(valueStr)); } else if (StartsWithSpace(check, "SInt8")) { aw.Write(sbyte.Parse(valueStr)); } else if (StartsWithSpace(check, "UInt16")) { aw.Write(ushort.Parse(valueStr)); } else if (StartsWithSpace(check, "SInt16")) { aw.Write(short.Parse(valueStr)); } else if (StartsWithSpace(check, "unsigned int")) { aw.Write(uint.Parse(valueStr)); } else if (StartsWithSpace(check, "int")) { aw.Write(int.Parse(valueStr)); } else if (StartsWithSpace(check, "UInt64")) { aw.Write(ulong.Parse(valueStr)); } else if (StartsWithSpace(check, "SInt64")) { aw.Write(long.Parse(valueStr)); } else if (StartsWithSpace(check, "float")) { aw.Write(float.Parse(valueStr)); } else if (StartsWithSpace(check, "double")) { aw.Write(double.Parse(valueStr)); } else if (StartsWithSpace(check, "string")) { int firstQuote = valueStr.IndexOf('"'); int lastQuote = valueStr.LastIndexOf('"'); string valueStrFix = valueStr.Substring(firstQuote + 1, lastQuote - firstQuote - 1); valueStrFix = valueStrFix .Replace("\\r", "\r") .Replace("\\n", "\n"); aw.WriteCountStringInt32(valueStrFix); } if (align) { aw.Align(); } } else { alignStack.Push(align); } } }
public static void CreateBlankAssets(MemoryStream ms, string engineVersion, uint formatVersion, uint typeTreeVersion, bool hasTypeTree = false) { AssetsFileWriter writer = new AssetsFileWriter(ms); AssetsFileHeader header = new AssetsFileHeader() { metadataSize = 0, fileSize = -1, format = formatVersion, firstFileOffset = -1, endianness = 0, unknown = new byte[] { 0, 0, 0 } }; TypeTree typeTree = new TypeTree() { unityVersion = engineVersion, version = typeTreeVersion, hasTypeTree = hasTypeTree, fieldCount = 0, unity5Types = new List <Type_0D>() }; header.Write(writer); typeTree.Write(writer, formatVersion); writer.Write((uint)0); //AssetCount writer.Align(); //preload table and dependencies writer.Write((uint)0); writer.Write((uint)0); //secondaryTypeCount if (header.format >= 0x14) { writer.Write(0); } uint metadataSize = (uint)(writer.Position - 0x13); if (header.format >= 0x16) { metadataSize -= 0x1c; } if (writer.Position < 0x1000) { while (writer.Position < 0x1000) { writer.Write((byte)0x00); } } else { if (writer.Position % 16 == 0) { writer.Position += 16; } else { writer.Align16(); } } long endPosition = writer.Position; header.fileSize = endPosition; header.firstFileOffset = endPosition; header.metadataSize = metadataSize; writer.Position = 0; header.Write(writer); writer.Position = endPosition; }
//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 AssetsReplacer CreateBundleInformation(Dictionary <AssetID, ulong> files, List <ulong> spriteIds, ulong pathId) { byte[] metaAsset = null; using (MemoryStream ms = new MemoryStream()) using (AssetsFileWriter writer = new AssetsFileWriter(ms)) { writer.bigEndian = false; writer.Write(0); writer.Write((uint)(1 + files.Count + spriteIds.Count)); //spriteIds is risky, we don't know if all are going to be written writer.Write(0); writer.Write((ulong)2); foreach (KeyValuePair <AssetID, ulong> file in files) { writer.Write(0); writer.Write(file.Value); } writer.Align(); foreach (KeyValuePair <AssetID, ulong> file in files) { if (spriteIds.Contains(file.Value)) { writer.Write(0); writer.Write(file.Value); } } writer.Align(); int index = 1; writer.Write((uint)files.Count); foreach (KeyValuePair <AssetID, ulong> file in files) { writer.WriteCountStringInt32(file.Key.fileName + "/" + file.Key.pathId + ".dat"); writer.Align(); writer.Write(index++); writer.Write(1); writer.Write(0); writer.Write(file.Value); } writer.Align(); writer.Write(0); writer.Write(1); writer.Write(0); writer.Write((ulong)2); writer.Write((uint)1); writer.Write(0); writer.Write(0); writer.Write((uint)0); writer.Write((uint)0); writer.Write(7); writer.Write(0); metaAsset = ms.ToArray(); } return(new AssetsReplacerFromMemory(0, pathId, 0x8E, 0xFFFF, metaAsset)); }
public static AssetsReplacer CreateBundleInformation(string sceneName, ulong pathId) { byte[] metaAsset = null; using (MemoryStream ms = new MemoryStream()) using (AssetsFileWriter writer = new AssetsFileWriter(ms)) { writer.bigEndian = false; writer.WriteCountStringInt32(sceneName + ".unity3d"); writer.Align(); writer.Write(0); writer.Align(); writer.Write(1); writer.WriteCountStringInt32(sceneName + ".unity"); writer.Align(); writer.Write(0); writer.Write(0); writer.Write(0); writer.Write((long)0); writer.Align(); writer.Write(0); writer.Write(0); writer.Write(0); writer.Write((long)0); writer.Write((uint)1); writer.Write(0); writer.Align(); writer.Write(0); writer.Align(); writer.Write((uint)1); writer.Write(0); writer.Write(3); writer.Write(0); metaAsset = ms.ToArray(); } return(new AssetsReplacerFromMemory(0, pathId, 0x8E, 0xFFFF, metaAsset)); //byte[] metaAsset = null; //using (MemoryStream ms = new MemoryStream()) //using (AssetsFileWriter writer = new AssetsFileWriter(ms)) //{ // writer.bigEndian = false; // writer.Write(0); // writer.Write((uint)(files.Count + 1)); // // writer.Write(0); // writer.Write((ulong)1); // foreach (KeyValuePair<AssetID, ulong> file in files) // { // writer.Write(0); // writer.Write(file.Value); // } // writer.Align(); // // int index = 1; // writer.Write((uint)files.Count); // foreach (KeyValuePair<AssetID, ulong> file in files) // { // //writer.WriteCountStringInt32(""); // writer.WriteCountStringInt32(file.Key.fileId + "/" + file.Key.pathId + ".dat"); // writer.Align(); // writer.Write(index++); // writer.Write(1); // writer.Write(0); // writer.Write(file.Value); // } // writer.Align(); // // writer.Write(0); // writer.Write(1); // writer.Write(0); // writer.Write((ulong)2); // // writer.Write((uint)1); // // writer.Write(0); // // writer.Write(0); // // writer.Write((uint)0); // // writer.Write((uint)0); // // writer.Write(7); // // writer.Write(0); // // metaAsset = ms.ToArray(); //} //return new AssetsReplacerFromMemory(0, pathId, 0x8E, 0xFFFF, metaAsset); }