public void OnGUI() { serializedObject.Update(); EditorGUILayout.Space(); EditorGUILayout.LabelField("Karlson custom level exporter", EditorStyles.boldLabel); EditorGUILayout.Space(); levelMetadata.levelId = EditorGUILayout.TextField("Level ID", levelMetadata.levelId); EditorGUILayout.Space(); levelMetadata.levelName = EditorGUILayout.TextField("Level name", levelMetadata.levelName); levelMetadata.levelVersion = EditorGUILayout.TextField("Level version", levelMetadata.levelVersion); levelMetadata.authorName = EditorGUILayout.TextField("Author name", levelMetadata.authorName); EditorGUILayout.PropertyField(levelCoverProperty); EditorGUILayout.Space(); levelMetadata.isLevelPack = EditorGUILayout.Toggle("Is level pack", levelMetadata.isLevelPack); EditorGUILayout.Space(); if (!levelMetadata.isLevelPack) { EditorGUILayout.PropertyField(mainSceneProperty); } else { packStagesReorderableList.DoLayoutList(); } EditorGUILayout.Space(); EditorGUILayout.LabelField("Level description"); levelMetadata.levelDescription = EditorGUILayout.TextArea(levelMetadata.levelDescription); EditorGUILayout.Space(); requiredModsReorderableList.DoLayoutList(); EditorGUILayout.Space(); serializedObject.ApplyModifiedProperties(); bool canBuildLevel = ((!levelMetadata.isLevelPack && mainStage != null) || (levelMetadata.isLevelPack && packStages.Count(x => x != default) > 0)) && !string.IsNullOrEmpty(levelMetadata.levelId); if (!canBuildLevel) { if (string.IsNullOrEmpty(levelMetadata.levelId)) { status = "Level ID is empty!"; } else if (!((!levelMetadata.isLevelPack && mainStage != null) || (levelMetadata.isLevelPack && packStages.Count(x => x != default) > 0))) { status = "No stage(s)!"; } } else { if (!isBuildingLevel) { status = "Ready!"; } } GUI.enabled = canBuildLevel; if (GUILayout.Button("Build level", GUILayout.Height(30f))) { levelMetadata.requiredMods = requiredModsList; BuildLevel(levelMetadata, levelCover, levelMetadata.isLevelPack ? packStages : new List <SceneAsset>() { mainStage }); } GUI.enabled = true; GUILayout.BeginHorizontal(); if (GUILayout.Button("Save preset")) { levelMetadata.stages = levelMetadata.isLevelPack ? packStages.Select(x => AssetDatabase.GetAssetPath(x)).ToList() : new List <string>() { AssetDatabase.GetAssetPath(mainStage) }; levelMetadata.requiredMods = requiredModsList; string serializedMetadata = JsonUtility.ToJson(levelMetadata); string savePath = EditorUtility.SaveFilePanel("Save level preset", "", "", "json"); if (savePath.Length > 0) { File.WriteAllText(savePath, serializedMetadata); } } if (GUILayout.Button("Load preset")) { string loadPath = EditorUtility.OpenFilePanel("Load level preset", "", "json"); if (loadPath.Length > 0) { try { string serializedMetadata = File.ReadAllText(loadPath); levelMetadata = JsonUtility.FromJson <LevelMetadata>(serializedMetadata); if (levelMetadata.stages != null && levelMetadata.stages.Count > 0) { packStages = levelMetadata.stages.Select(x => AssetDatabase.LoadAssetAtPath <SceneAsset>(x)).ToList(); mainStage = packStages[0]; } else { packStages = new List <SceneAsset>(); } if (levelMetadata.requiredMods != null && levelMetadata.requiredMods.Count > 0) { requiredModsList = levelMetadata.requiredMods; } else { requiredModsList = new List <ModEntry>(); } } catch (Exception e) { Debug.LogException(e); } } } GUILayout.EndHorizontal(); EditorGUILayout.LabelField("Status: " + status); }
public LevelLoadResult LoadLevelInfo(string levelPath, bool leaveOpen, bool isAsync = false) { LevelLoadResult result = new LevelLoadResult(); FileStream stream = File.OpenRead(levelPath); result.fileStream = stream; try { bool headerOK = stream.ReadByte() == (byte)'K' && stream.ReadByte() == (byte)'R' && stream.ReadByte() == (byte)'L' && stream.ReadByte() == (byte)'S' && stream.ReadByte() == (byte)'N'; SemVer.Version fileVersion = new SemVer.Version(stream.ReadByte(), stream.ReadByte(), stream.ReadByte()); if (headerOK && compatibleFileVersions.IsSatisfied(fileVersion)) { byte[] metadataSizeBuffer = new byte[4]; stream.Read(metadataSizeBuffer, 0, 4); int metadataSize = BitConverter.ToInt32(metadataSizeBuffer, 0); byte[] coverSizeBuffer = new byte[4]; stream.Read(coverSizeBuffer, 0, 4); int coverSize = BitConverter.ToInt32(coverSizeBuffer, 0); byte[] metadataBuffer = new byte[metadataSize]; stream.Read(metadataBuffer, 0, metadataSize); LevelMetadata levelMetadata = JsonConvert.DeserializeObject <LevelMetadata>(Encoding.UTF8.GetString(metadataBuffer)); byte[] coverBuffer = new byte[coverSize]; stream.Read(coverBuffer, 0, coverSize); long assetsArchiveOffset = stream.Position; LevelInfo info = new LevelInfo() { path = levelPath, metadata = levelMetadata, cover = null, assetsArchiveOffset = assetsArchiveOffset }; if (isAsync) { MainThreadDispatcher.Enqueue(() => { if (coverBuffer != null && coverBuffer.Length > 0) { Texture2D levelCover = new Texture2D(1, 1); levelCover.LoadImage(coverBuffer); info.cover = levelCover; } }); } else { if (coverBuffer != null && coverBuffer.Length > 0) { Texture2D levelCover = new Texture2D(1, 1); levelCover.LoadImage(coverBuffer); info.cover = levelCover; } } result.info = info; result.success = true; if (!leaveOpen) { stream.Close(); result.fileStream = null; } return(result); } else { if (headerOK) { Console.WriteLine($"File at \"{levelPath}\" is not a Karlson level!"); } else { Console.WriteLine($"Level at \"{levelPath}\" is not compatible with this MapLoader version! Level file version: {fileVersion}, Compatible file versions: {compatibleFileVersions}"); } stream.Close(); result.fileStream = null; result.success = false; return(result); } } catch (Exception e) { Console.WriteLine($"Unable to load level info for level at \"{levelPath}\"! Exception: " + e); stream.Close(); result.fileStream = null; result.success = false; return(result); } }
private void BuildLevel(LevelMetadata levelMetadata, Texture2D levelCover, List <SceneAsset> sceneAsset) { isBuildingLevel = true; string assetBundleDirectory = "Assets/Output"; if (!Directory.Exists(assetBundleDirectory)) { Directory.CreateDirectory(assetBundleDirectory); } else if (Directory.GetFileSystemEntries(assetBundleDirectory).Length != 0) { DirectoryInfo deleteFilesInfo = new DirectoryInfo(assetBundleDirectory); foreach (FileInfo file in deleteFilesInfo.EnumerateFiles()) { file.Delete(); } foreach (DirectoryInfo dir in deleteFilesInfo.EnumerateDirectories()) { dir.Delete(true); } } status = "Collecting assets..."; AssetBundleBuild[] buildMap = new AssetBundleBuild[1]; buildMap[0].assetBundleName = "Stages_" + levelMetadata.levelId; buildMap[0].assetNames = sceneAsset.Distinct().Select(x => AssetDatabase.GetAssetPath(x)).ToArray(); //Debug.Log($"Scene assets: {sceneAsset.Count}"); //Debug.Log($"Path: {AssetDatabase.GetAssetPath(sceneAsset[0])}"); foreach (var bundle in buildMap) { Debug.Log($"Building AssetBundle with name \"{bundle.assetBundleName}\", assets count: {bundle.assetNames.Length}"); } status = "Building assets..."; BuildPipeline.BuildAssetBundles(assetBundleDirectory, buildMap, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows); Debug.Log($"Finished building AssetBundles! Packing level..."); status = "Packing level..."; File.Move(Path.Combine(assetBundleDirectory, "Output"), Path.Combine(assetBundleDirectory, levelMetadata.levelId)); var fileStream = File.Open(Path.Combine(assetBundleDirectory, levelMetadata.levelId + ".lvl"), FileMode.Create); levelMetadata.stages = sceneAsset.Select(x => x.name).ToList(); byte[] levelMetadataBytes = Encoding.UTF8.GetBytes(JsonUtility.ToJson(levelMetadata)); byte[] metadataSizeBuffer = BitConverter.GetBytes(levelMetadataBytes.Length); if (levelCover == null) { levelCover = new Texture2D(1, 1); } if (!levelCover.isReadable) { SetTextureImporterFormat(levelCover, true); } var decompressed = DeCompress(levelCover); byte[] coverBytes = decompressed.EncodeToPNG(); byte[] coverSizeBuffer = BitConverter.GetBytes(coverBytes.Length); byte[] buffer = new byte[5 + 3 + 4 + 4 + levelMetadataBytes.Length + coverBytes.Length]; buffer[0] = (byte)'K'; buffer[1] = (byte)'R'; buffer[2] = (byte)'L'; buffer[3] = (byte)'S'; buffer[4] = (byte)'N'; Array.Copy(fileFormatVersion, 0, buffer, 5, 3); Array.Copy(metadataSizeBuffer, 0, buffer, 8, 4); Array.Copy(coverSizeBuffer, 0, buffer, 12, 4); Array.Copy(levelMetadataBytes, 0, buffer, 16, levelMetadataBytes.Length); Array.Copy(coverBytes, 0, buffer, 16 + levelMetadataBytes.Length, coverBytes.Length); fileStream.Write(buffer, 0, buffer.Length); ZipArchive assetsArchive = new ZipArchive(fileStream, ZipArchiveMode.Create); assetsArchive.CreateEntryFromFile(Path.Combine(assetBundleDirectory, levelMetadata.levelId), levelMetadata.levelId); foreach (var bundle in buildMap) { assetsArchive.CreateEntryFromFile(Path.Combine(assetBundleDirectory, bundle.assetBundleName), bundle.assetBundleName); } assetsArchive.Dispose(); DirectoryInfo dirInfo = new DirectoryInfo(assetBundleDirectory); foreach (FileInfo file in dirInfo.EnumerateFiles()) { if (!file.Name.EndsWith(".lvl")) { file.Delete(); } } Debug.Log($"Done!"); isBuildingLevel = false; }