コード例 #1
0
ファイル: Loader.cs プロジェクト: crmaxx/HKWorldEdit2
        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++;
        }
コード例 #2
0
        /////////////////////////////////////////////////////////

        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);
        }
コード例 #3
0
        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);
        }
コード例 #4
0
ファイル: Loader.cs プロジェクト: crmaxx/HKWorldEdit2
        /////////////////////////////////////////////////////////

        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++;
        }
コード例 #5
0
        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();
        }
コード例 #6
0
ファイル: AddAssetWindow.axaml.cs プロジェクト: nesrak1/UABEA
        private async void ReturnAssetToAdd()
        {
            int    fileId           = ddFileId.SelectedIndex; //hopefully in order
            string pathIdText       = boxPathId.Text;
            string typeIdText       = boxTypeId.Text;
            string monoIdText       = boxMonoId.Text;
            bool   createBlankAsset = chkCreateZerodAsset.IsChecked ?? false;

            AssetsFileInstance file = workspace.LoadedFiles[fileId];

            AssetTypeTemplateField tempField;

            byte[] assetBytes;
            long   pathId;
            int    typeId;
            ushort monoId;

            if (!long.TryParse(pathIdText, out pathId))
            {
                await MessageBoxUtil.ShowDialog(this, "Bad input", "Path ID was invalid.");

                return;
            }

            if (file.file.typeTree.hasTypeTree)
            {
                if (!TryParseTypeTree(file, typeIdText, createBlankAsset, out tempField, out typeId))
                {
                    if (!TryParseClassDatabase(typeIdText, createBlankAsset, out tempField, out typeId))
                    {
                        await MessageBoxUtil.ShowDialog(this, "Bad input", "Class type was invalid.");

                        return;
                    }
                    else
                    {
                        //has typetree but had to lookup to cldb
                        //we need to add a new typetree entry because this is
                        //probably not a type that existed in this bundle
                        file.file.typeTree.unity5Types.Add(C2T5.Cldb2TypeTree(workspace.am.classFile, typeId));
                    }
                }
            }
            else
            {
                if (!TryParseClassDatabase(typeIdText, createBlankAsset, out tempField, out typeId))
                {
                    await MessageBoxUtil.ShowDialog(this, "Bad input", "Class type was invalid.");

                    return;
                }
            }

            if (monoIdText == "-1")
            {
                monoId = 0xffff;
            }
            else if (!ushort.TryParse(monoIdText, out monoId))
            {
                await MessageBoxUtil.ShowDialog(this, "Bad input", "Mono ID was invalid.");

                return;
            }

            if (createBlankAsset)
            {
                AssetTypeValueField baseField = ValueBuilder.DefaultValueFieldFromTemplate(tempField);
                assetBytes = baseField.WriteToByteArray();
            }
            else
            {
                assetBytes = new byte[0];
            }

            workspace.AddReplacer(file, new AssetsReplacerFromMemory(0, pathId, typeId, monoId, assetBytes), new MemoryStream(assetBytes));

            Close(true);
        }
コード例 #7
0
        public void Write(AssetsFileWriter writer, long filePos, List <AssetsReplacer> replacers, uint fileID = 0, ClassDatabaseFile typeMeta = null)
        {
            if (filePos == -1)
            {
                filePos = writer.Position;
            }
            else
            {
                writer.Position = filePos;
            }

            header.Write(writer);

            foreach (AssetsReplacer replacer in replacers)
            {
                int    replacerClassId     = replacer.GetClassID();
                ushort replacerScriptIndex = replacer.GetMonoScriptID();
                if (!typeTree.unity5Types.Any(t => t.classId == replacerClassId && t.scriptIndex == replacerScriptIndex))
                {
                    Type_0D type = null;

                    if (typeMeta != null)
                    {
                        ClassDatabaseType cldbType = AssetHelper.FindAssetClassByID(typeMeta, (uint)replacerClassId);
                        if (cldbType != null)
                        {
                            type = C2T5.Cldb2TypeTree(typeMeta, cldbType);

                            //in original AssetsTools, if you tried to use a new monoId it would just try to use
                            //the highest existing scriptIndex that existed without making a new one (unless there
                            //were no monobehavours ofc) this isn't any better as we just assign a plain monobehaviour
                            //typetree to a type that probably has more fields. I don't really know of a better way to
                            //handle this at the moment as cldbs cannot differentiate monoids.
                            type.scriptIndex = replacerScriptIndex;
                        }
                    }

                    if (type == null)
                    {
                        type = new Type_0D
                        {
                            classId           = replacerClassId,
                            unknown16_1       = 0,
                            scriptIndex       = replacerScriptIndex,
                            typeHash1         = 0,
                            typeHash2         = 0,
                            typeHash3         = 0,
                            typeHash4         = 0,
                            typeFieldsExCount = 0,
                            stringTableLen    = 0,
                            stringTable       = ""
                        };
                    }

                    typeTree.unity5Types.Add(type);
                }
            }
            typeTree.Write(writer, header.format);

            Dictionary <long, AssetFileInfo>  oldAssetInfosByPathId = new Dictionary <long, AssetFileInfo>();
            Dictionary <long, AssetsReplacer> replacersByPathId     = replacers.ToDictionary(r => r.GetPathID());
            List <AssetFileInfo> newAssetInfos = new List <AssetFileInfo>();

            // Collect unchanged assets (that aren't getting removed)
            reader.Position = assetTablePos;
            for (int i = 0; i < assetCount; i++)
            {
                AssetFileInfo oldAssetInfo = new AssetFileInfo();
                oldAssetInfo.Read(header.format, reader);
                oldAssetInfosByPathId.Add(oldAssetInfo.index, oldAssetInfo);

                if (replacersByPathId.ContainsKey(oldAssetInfo.index))
                {
                    continue;
                }

                AssetFileInfo newAssetInfo = new AssetFileInfo
                {
                    index = oldAssetInfo.index,
                    curFileTypeOrIndex  = oldAssetInfo.curFileTypeOrIndex,
                    inheritedUnityClass = oldAssetInfo.inheritedUnityClass,
                    scriptIndex         = oldAssetInfo.scriptIndex,
                    unknown1            = oldAssetInfo.unknown1
                };
                newAssetInfos.Add(newAssetInfo);
            }

            // Collect modified and new assets
            foreach (AssetsReplacer replacer in replacers.Where(r => r.GetReplacementType() == AssetsReplacementType.AddOrModify))
            {
                AssetFileInfo newAssetInfo = new AssetFileInfo
                {
                    index = replacer.GetPathID(),
                    inheritedUnityClass = (ushort)replacer.GetClassID(),                              //for older unity versions
                    scriptIndex         = replacer.GetMonoScriptID(),
                    unknown1            = 0
                };

                if (header.format < 0x10)
                {
                    newAssetInfo.curFileTypeOrIndex = replacer.GetClassID();
                }
                else
                {
                    if (replacer.GetMonoScriptID() == 0xFFFF)
                    {
                        newAssetInfo.curFileTypeOrIndex = typeTree.unity5Types.FindIndex(t => t.classId == replacer.GetClassID());
                    }
                    else
                    {
                        newAssetInfo.curFileTypeOrIndex = typeTree.unity5Types.FindIndex(t => t.classId == replacer.GetClassID() && t.scriptIndex == replacer.GetMonoScriptID());
                    }
                }

                newAssetInfos.Add(newAssetInfo);
            }

            newAssetInfos.Sort((i1, i2) => i1.index.CompareTo(i2.index));

            // Write asset infos (will write again later on to update the offsets and sizes)
            writer.Write(newAssetInfos.Count);
            writer.Align();
            long newAssetTablePos = writer.Position;

            foreach (AssetFileInfo newAssetInfo in newAssetInfos)
            {
                newAssetInfo.Write(header.format, writer);
            }

            preloadTable.Write(writer);
            dependencies.Write(writer);

            // Temporary fix for secondaryTypeCount and friends
            if (header.format >= 0x14)
            {
                writer.Write(0); //secondaryTypeCount
            }

            uint newMetadataSize = (uint)(writer.Position - filePos - 0x13); //0x13 is header - "endianness byte"? (if that's what it even is)

            if (header.format >= 0x16)
            {
                // Remove larger variation fields as well
                newMetadataSize -= 0x1c;
            }

            // For padding only. if all initial data before assetData is more than 0x1000, this is skipped
            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 newFirstFileOffset = writer.Position;

            // Write all asset data
            for (int i = 0; i < newAssetInfos.Count; i++)
            {
                AssetFileInfo newAssetInfo = newAssetInfos[i];
                newAssetInfo.curFileOffset = writer.Position - newFirstFileOffset;

                if (replacersByPathId.TryGetValue(newAssetInfo.index, out AssetsReplacer replacer))
                {
                    replacer.Write(writer);
                }
                else
                {
                    AssetFileInfo oldAssetInfo = oldAssetInfosByPathId[newAssetInfo.index];
                    reader.Position = header.firstFileOffset + oldAssetInfo.curFileOffset;
                    reader.BaseStream.CopyToCompat(writer.BaseStream, oldAssetInfo.curFileSize);
                }

                newAssetInfo.curFileSize = (uint)(writer.Position - (newFirstFileOffset + newAssetInfo.curFileOffset));
                if (i != newAssetInfos.Count - 1)
                {
                    writer.Align8();
                }
            }

            long newFileSize = writer.Position - filePos;

            // Write new header
            AssetsFileHeader newHeader = new AssetsFileHeader
            {
                metadataSize    = newMetadataSize,
                fileSize        = newFileSize,
                format          = header.format,
                firstFileOffset = newFirstFileOffset,
                endianness      = header.endianness,
                unknown         = header.unknown,
                unknown1        = header.unknown1,
                unknown2        = header.unknown2
            };

            writer.Position = filePos;
            newHeader.Write(writer);

            // Write new asset infos again (this time with offsets and sizes filled in)
            writer.Position = newAssetTablePos;
            foreach (AssetFileInfo newAssetInfo in newAssetInfos)
            {
                newAssetInfo.Write(header.format, writer);
            }

            // Set writer position back to end of file
            writer.Position = filePos + newFileSize;
        }
コード例 #8
0
ファイル: HKEdit.cs プロジェクト: raphydaphy/HKEdit
    private static void LoadScene()
    {
        am = new AssetsManager();
        am.LoadClassPackage("cldb.dat");
        am.useTemplateFieldCache = true;
        am.updateAfterLoad       = false;

        hkDir = Util.SteamHelper.GetHollowKnightDataPath();

        var globalgamemanagers = am.LoadAssetsFile(Path.Combine(hkDir, "globalgamemanagers"), false);
        var buildSettings      = globalgamemanagers.table.getAssetInfo(11);

        var baseField = am.GetATI(globalgamemanagers.file, buildSettings).GetBaseField();

        var scenesArray = baseField.Get("scenes").Get("Array");

        // TODO: Allow level to be selected
        const int level = 0;

        var levelName = scenesArray[level].GetValue().AsString().Substring(14);

        levelName = levelName.Substring(0, levelName.Length - 6);

        progressBarTitle = "Loading Scene #" + level + ": " + levelName;

        if (ShouldCancel("Checking workspace", 0.2f))
        {
            return;
        }

        if (!baseField.Get("m_Version").GetValue().AsString().Equals(Application.unityVersion))
        {
            EditorUtility.ClearProgressBar();
            EditorUtility.DisplayDialog("Incorrect Unity version!", " You are using " +
                                        Application.unityVersion + " but the assets are compiled for version " +
                                        baseField.Get("m_Version").GetValue().AsString(), "Ok");
            return;
        }

        unityVersion = Application.unityVersion;

        if (!Directory.Exists(scenesDir))
        {
            Directory.CreateDirectory(scenesDir);
        }

        if (!Directory.Exists(dataDir))
        {
            Directory.CreateDirectory(dataDir);
        }

        var metaFilePath   = Path.Combine(scenesDir, "level" + level + ".unity.meta");
        var sceneFilePath  = Path.Combine(scenesDir, "level" + level + ".unity");
        var assetsFilePath = Path.Combine(dataDir, "level" + level + ".assets");

        if (File.Exists(sceneFilePath))
        {
            if (EditorUtility.DisplayDialog("Overwrite scene?", "" +
                                            " You have already exported this scene. Would you like to overwrite it or open the existing scene? ",
                                            "Open Existing", "Overwrite"))
            {
                if (ShouldCancel("Opening Scene", 0.5f))
                {
                    return;
                }
                EditorSceneManager.OpenScene(sceneFilePath);
                EditorUtility.ClearProgressBar();
                return;
            }
            else
            {
                File.Delete(sceneFilePath);
            }
        }

        if (File.Exists(metaFilePath))
        {
            File.Delete(metaFilePath);
        }
        if (File.Exists(assetsFilePath))
        {
            File.Delete(assetsFilePath);
        }

        curSceneId = 1;
        curAssetId = 1;

        pointers       = new Dictionary <AssetID, AssetID>();
        sceneReplacers = new List <AssetsReplacer>();
        assetReplacers = new List <AssetsReplacer>();
        monoReplacers  = new List <AssetsReplacer>();

        if (ShouldCancel("Reading level file", 0.5f))
        {
            return;
        }
        var scenePath = Path.Combine(Util.SteamHelper.GetHollowKnightDataPath(), "level" + level);
        var scene     = am.LoadAssetsFile(scenePath, true);

        if (ShouldCancel("Updating Dependencies", 0.8f))
        {
            return;
        }
        am.UpdateDependencies();

        for (var i = 0; i < am.files.Count; i++)
        {
            if (i % 100 == 0 && ShouldCancel("Generating QLTs", (float)i / am.files.Count))
            {
                return;
            }
            am.files[i].table.GenerateQuickLookupTree();
        }

        var table                = scene.table;
        var gameObjects          = table.GetAssetsOfType(0x01);
        var gameObjectBaseFields = new Dictionary <AssetFileInfoEx, AssetTypeValueField>();

        var c = 0;

        for (c = 0; c < gameObjects.Count; c++)
        {
            if (c % 100 == 0 && ShouldCancel("Finding initial GameObjects", (float)c / gameObjects.Count))
            {
                return;
            }

            var gameObjectInfo      = gameObjects[c];
            var gameObjectBaseField = am.GetATI(scene.file, gameObjectInfo).GetBaseField();

            AddPointer(new AssetID(scene.path, (long)gameObjectInfo.index), false);
            gameObjectBaseFields.Add(gameObjectInfo, gameObjectBaseField);
        }
        c = 0;

        foreach (var pair in gameObjectBaseFields)
        {
            if (c % 100 == 0 && ShouldCancel("Recursing GameObject dependencies", (float)c / gameObjectBaseFields.Count))
            {
                return;
            }
            FindNestedPointers(scene, pair.Value, pair.Key, false);
            c++;
        }

        var types     = new List <Type_0D>();
        var typeNames = new List <string>();

        var fileToInst = am.files.ToDictionary(d => d.path);
        var j          = 0;

        foreach (var pair in pointers)
        {
            if (j % 100 == 0 && ShouldCancel("Rewiring asset pointers", (float)j / pointers.Count))
            {
                return;
            }

            var file = fileToInst[pair.Key.fileName];
            var info = file.table.getAssetInfo((ulong)pair.Key.pathId);

            var assetClass = AssetHelper.FindAssetClassByID(am.classFile, info.curFileType);
            var assetName  = assetClass.name.GetString(am.classFile);

            if (!typeNames.Contains(assetName))
            {
                var type0d = C2T5.Cldb2TypeTree(am.classFile, assetName);
                type0d.classId = (int)info.curFileType;
                types.Add(type0d);
                typeNames.Add(assetName);
            }

            ReplacePointers(file, info, pair.Value.pathId);
            j++;
        }

        if (ShouldCancel("Saving scene", 1))
        {
            return;
        }

        List <Type_0D> assetTypes = new List <Type_0D>()
        {
            C2T5.Cldb2TypeTree(am.classFile, 0x1c), // audioclip
            C2T5.Cldb2TypeTree(am.classFile, 0x30), // shader
            C2T5.Cldb2TypeTree(am.classFile, 0x53)  // texture2d
        };

        var sceneGuid = Util.UnityHelper.CreateMD5(levelName);

        UnityHelper.CreateMetaFile(sceneGuid, metaFilePath);

        var sceneFile = new AssetsFile(new AssetsFileReader(new MemoryStream(BundleCreator.CreateBlankAssets(unityVersion, types))));
        var assetFile = new AssetsFile(new AssetsFileReader(new MemoryStream(BundleCreator.CreateBlankAssets(unityVersion, assetTypes))));

        byte[] sceneFileData;
        using (MemoryStream ms = new MemoryStream())
            using (AssetsFileWriter w = new AssetsFileWriter(ms))
            {
                w.bigEndian = false;
                sceneFile.dependencies.pDependencies = new AssetsFileDependency[]
                {
                    UnityHelper.CreateDependency(assetsFilePath),
                };
                sceneFile.dependencies.dependencyCount = 1;

                sceneFile.preloadTable.items = new AssetPPtr[] {};
                sceneFile.preloadTable.len   = 0;

                sceneFile.Write(w, 0, sceneReplacers.Concat(monoReplacers).ToArray(), 0);
                sceneFileData = ms.ToArray();
            }
        byte[] assetFileData;
        using (var ms = new MemoryStream())
            using (var w = new AssetsFileWriter(ms))
            {
                w.bigEndian = false;
                assetFile.Write(w, 0, assetReplacers.ToArray(), 0);
                assetFileData = ms.ToArray();
            }

        File.WriteAllBytes(sceneFilePath, sceneFileData);
        File.WriteAllBytes(assetsFilePath, assetFileData);

        if (ShouldCancel("Refreshing Assets", 0.95f))
        {
            return;
        }
        AssetDatabase.Refresh();
        EditorUtility.ClearProgressBar();
    }
コード例 #9
0
ファイル: Loader.cs プロジェクト: xueliuxing28/HKWorldEdit
        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());
                }
        }
コード例 #10
0
ファイル: Loader.cs プロジェクト: crmaxx/HKWorldLoad
        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());
                }
        }
コード例 #11
0
ファイル: Saver.cs プロジェクト: nesrak1/HKWorldEdit2
        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();
                }
        }
コード例 #12
0
        private void btnOK_Click(object sender, EventArgs e)
        {
            var cldb     = Workspace.Am.classFile;
            var fileInst = Workspace.LoadedFiles[cboxFileID.SelectedIndex];
            AssetTypeTemplateField templateField;

            var fileId = cboxFileID.SelectedIndex;

            if (!long.TryParse(boxPathID.Text, out var pathId))
            {
                MsgBoxUtils.ShowErrorDialog("Path ID is invalid!");
                return;
            }
            var type = boxTypeNameOrID.Text;
            int typeId;
            var createBlankAsset = chboxCreateBlankAssets.Checked;

            if (fileInst.file.typeTree.hasTypeTree)
            {
                if (!TryParseTypeTree(fileInst, ref type, createBlankAsset, out templateField, out typeId))
                {
                    if (!TryParseClassDatabase(ref type, createBlankAsset, out templateField, out typeId))
                    {
                        MsgBoxUtils.ShowErrorDialog("Class type is invalid!");
                        return;
                    }

                    //has typetree but had to lookup to cldb
                    //we need to add a new typetree entry because this is
                    //probably not a type that existed in this bundle
                    fileInst.file.typeTree.unity5Types.Add(C2T5.Cldb2TypeTree(cldb, typeId));
                }
            }
            else
            {
                if (!TryParseClassDatabase(ref type, createBlankAsset, out templateField, out typeId))
                {
                    MsgBoxUtils.ShowErrorDialog("Class type is invalid!");
                    return;
                }
            }

            var monoSelected = cboxTypePreset.SelectedIndex == 1;

            ushort monoId;

            if (typeId != 0x72 || !monoSelected)
            {
                monoId = ushort.MaxValue;
            }
            else
            {
                if (!ushort.TryParse(boxMonoID.Text, out monoId))
                {
                    MsgBoxUtils.ShowErrorDialog("Mono ID is invalid!");
                    return;
                }
            }

            if (!int.TryParse(boxCount.Text, out var count))
            {
                MsgBoxUtils.ShowErrorDialog("The count of assets being created is invalid!");
                return;
            }

            byte[] assetBytes;
            if (createBlankAsset)
            {
                var baseField = ValueBuilder.DefaultValueFieldFromTemplate(templateField);
                assetBytes = baseField.WriteToByteArray();
            }
            else
            {
                assetBytes = Array.Empty <byte>();
            }
            for (var i = 0; i < count; i++)
            {
                var item = new AssetItem
                {
                    Type     = type,
                    TypeID   = (uint)typeId,
                    FileID   = fileId,
                    PathID   = pathId + i,
                    Size     = assetBytes.Length,
                    Modified = "*",
                    MonoID   = monoId
                };
                Items.Add(item);
                Workspace.AddReplacer(AssetModifier.CreateAssetReplacer(item, assetBytes), new MemoryStream(assetBytes));
            }
            DialogResult = DialogResult.OK;
        }
コード例 #13
0
        public void Write(AssetsFileWriter writer, long filePos, List <AssetsReplacer> replacers, uint fileID, ClassDatabaseFile typeMeta = null)
        {
            if (filePos == -1)
            {
                filePos = writer.Position;
            }
            else
            {
                writer.Position = filePos;
            }

            header.Write(writer);

            for (int i = 0; i < replacers.Count; i++)
            {
                AssetsReplacer replacer        = replacers[i];
                int            replacerClassId = replacer.GetClassID();
                if (!typeTree.unity5Types.Any(t => t.classId == replacerClassId))
                {
                    Type_0D type = new Type_0D()
                    {
                        classId           = replacer.GetClassID(),
                        unknown16_1       = 0,
                        scriptIndex       = 0xFFFF,
                        typeHash1         = 0,
                        typeHash2         = 0,
                        typeHash3         = 0,
                        typeHash4         = 0,
                        typeFieldsExCount = 0,
                        stringTableLen    = 0,
                        stringTable       = ""
                    };

                    if (typeMeta != null)
                    {
                        int cldbIndex = typeMeta.classes.FindIndex(c => c.classId == replacerClassId);
                        if (cldbIndex != -1)
                        {
                            int cldbId = typeMeta.classes[cldbIndex].classId;
                            type = C2T5.Cldb2TypeTree(typeMeta, cldbId);
                        }
                    }

                    typeTree.unity5Types.Add(type);
                }
            }
            typeTree.Write(writer, header.format);

            int initialSize  = (int)(AssetFileInfo.GetSize(header.format) * AssetCount);
            int newSize      = (int)(AssetFileInfo.GetSize(header.format) * (AssetCount + replacers.Count));
            int appendedSize = newSize - initialSize;

            reader.Position = AssetTablePos;

            List <AssetFileInfo>  originalAssetInfos = new List <AssetFileInfo>();
            List <AssetFileInfo>  assetInfos         = new List <AssetFileInfo>();
            List <AssetsReplacer> currentReplacers   = replacers.ToList();
            uint currentOffset = 0;

            //-write all original assets, modify sizes if needed and skip those to be removed
            for (int i = 0; i < AssetCount; i++)
            {
                AssetFileInfo info = new AssetFileInfo();
                info.Read(header.format, reader);
                originalAssetInfos.Add(info);
                AssetFileInfo newInfo = new AssetFileInfo()
                {
                    index               = info.index,
                    curFileOffset       = currentOffset,
                    curFileSize         = info.curFileSize,
                    curFileTypeOrIndex  = info.curFileTypeOrIndex,
                    inheritedUnityClass = info.inheritedUnityClass,
                    scriptIndex         = info.scriptIndex,
                    unknown1            = info.unknown1
                };
                AssetsReplacer replacer = currentReplacers.FirstOrDefault(n => n.GetPathID() == newInfo.index);
                if (replacer != null)
                {
                    currentReplacers.Remove(replacer);
                    if (replacer.GetReplacementType() == AssetsReplacementType.AddOrModify)
                    {
                        int classIndex;
                        if (replacer.GetMonoScriptID() == 0xFFFF)
                        {
                            classIndex = typeTree.unity5Types.FindIndex(t => t.classId == replacer.GetClassID());
                        }
                        else
                        {
                            classIndex = typeTree.unity5Types.FindIndex(t => t.classId == replacer.GetClassID() && t.scriptIndex == replacer.GetMonoScriptID());
                        }
                        newInfo = new AssetFileInfo()
                        {
                            index               = replacer.GetPathID(),
                            curFileOffset       = currentOffset,
                            curFileSize         = (uint)replacer.GetSize(),
                            curFileTypeOrIndex  = classIndex,
                            inheritedUnityClass = (ushort)replacer.GetClassID(), //for older unity versions
                            scriptIndex         = replacer.GetMonoScriptID(),
                            unknown1            = 0
                        };
                    }
                    else if (replacer.GetReplacementType() == AssetsReplacementType.Remove)
                    {
                        continue;
                    }
                }
                currentOffset += newInfo.curFileSize;
                uint pad = 8 - (currentOffset % 8);
                if (pad != 8)
                {
                    currentOffset += pad;
                }

                assetInfos.Add(newInfo);
            }

            //-write new assets
            while (currentReplacers.Count > 0)
            {
                AssetsReplacer replacer = currentReplacers[0];
                if (replacer.GetReplacementType() == AssetsReplacementType.AddOrModify)
                {
                    int classIndex;
                    if (replacer.GetMonoScriptID() == 0xFFFF)
                    {
                        classIndex = typeTree.unity5Types.FindIndex(t => t.classId == replacer.GetClassID());
                    }
                    else
                    {
                        classIndex = typeTree.unity5Types.FindIndex(t => t.classId == replacer.GetClassID() && t.scriptIndex == replacer.GetMonoScriptID());
                    }
                    AssetFileInfo info = new AssetFileInfo()
                    {
                        index               = replacer.GetPathID(),
                        curFileOffset       = currentOffset,
                        curFileSize         = (uint)replacer.GetSize(),
                        curFileTypeOrIndex  = 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(header.format, writer);
            }

            preloadTable.Write(writer);

            dependencies.Write(writer);

            //temporary fix for secondarytypecount and friends
            if (header.format >= 0x14)
            {
                writer.Write(0); //secondaryTypeCount
                //writer.Write((byte)0); //unknownString length
            }

            uint metadataSize = (uint)(writer.Position - filePos - 0x13); //0x13 is header - "endianness byte"? (if that's what it even is)

            if (header.format >= 0x16)
            {
                //remove larger variation fields as well
                metadataSize -= 0x1c;
            }

            //-for padding only. if all initial data before assetData is more than 0x1000, this is skipped
            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 offs_firstFile = writer.Position;

            for (int i = 0; i < assetInfos.Count; i++)
            {
                AssetFileInfo  info     = assetInfos[i];
                AssetsReplacer replacer = replacers.FirstOrDefault(n => n.GetPathID() == info.index);
                if (replacer != null)
                {
                    if (replacer.GetReplacementType() == AssetsReplacementType.AddOrModify)
                    {
                        replacer.Write(writer);
                        if (i != assetInfos.Count - 1)
                        {
                            writer.Align8();
                        }
                    }
                    else if (replacer.GetReplacementType() == AssetsReplacementType.Remove)
                    {
                        continue;
                    }
                }
                else
                {
                    AssetFileInfo originalInfo = originalAssetInfos.FirstOrDefault(n => n.index == info.index);
                    if (originalInfo != null)
                    {
                        reader.Position = header.firstFileOffset + originalInfo.curFileOffset;
                        byte[] assetData = reader.ReadBytes((int)originalInfo.curFileSize);
                        writer.Write(assetData);
                        if (i != assetInfos.Count - 1)
                        {
                            writer.Align8();
                        }
                    }
                }
            }

            header.firstFileOffset = offs_firstFile;

            long fileSizeMarker = writer.Position - filePos;

            reader.Position = header.firstFileOffset;

            writer.Position     = filePos;
            header.metadataSize = metadataSize;
            header.fileSize     = fileSizeMarker;
            header.Write(writer);

            writer.Position = fileSizeMarker + filePos;
        }
コード例 #14
0
ファイル: Loader.cs プロジェクト: crmaxx/HKWorldEdit2
        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);
        }