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(); }