/// <summary> /// Update all files within a directory to correct variable names /// </summary> /// <param name="folderPath">In folder path</param> /// <param name="keyVars">dictionary of words to replace within files</param> /// <param name="checkSubDirectories">Recursive update files and folders</param> /// <param name="excludeExtensions">Blacklist of file extensions not to update</param> public static void UpdateAllCopiedFiles(string folderPath, Dictionary <string, string> keyVars, bool checkSubDirectories = false, string[] excludeExtensions = null) { if (checkSubDirectories) { string[] dirs = SafeFileManagement.GetDirectoryPaths(folderPath, Globals.NUMBER_OF_IO_RETRY_ATTEMPTS); foreach (string dir in dirs) { UpdateAllCopiedFiles(dir, keyVars, checkSubDirectories, excludeExtensions); } } if (Directory.Exists(folderPath)) { string[] files = SafeFileManagement.GetFilesPaths(folderPath, Globals.NUMBER_OF_IO_RETRY_ATTEMPTS); foreach (string file in files) { if (excludeExtensions != null) { string extension = Path.GetExtension(file); if (Array.Exists(excludeExtensions, element => element.ToLower() == extension.ToLower())) { continue; } } UpdateFileWithKeys(file, keyVars); } } }
/// <summary> /// Convert Beat Saber data to a minecraft ResourcePack /// </summary> /// <param name="unzippedFolderPath">Path to unzipped beat saber pack</param> /// <param name="datapackOutputPath">Folder path that Resourcepack will be generated in</param> /// <param name="packInfo">Beat Saber Infomation</param> /// <returns>-1 if successful</returns> public static async Task <ConversionError> FromBeatSaberData(string datapackOutputPath, BeatSaberMap beatSaberMap) { return(await Task.Run(() => { var packInfo = beatSaberMap.InfoData; var unzippedFolderPath = beatSaberMap.ExtractedFilePath; if (!Directory.Exists(unzippedFolderPath) || packInfo == null) { return ConversionError.MissingInfo; } Dictionary <string, string> keyVars = new Dictionary <string, string>(); string folder_uuid = SafeFileManagement.GetFileName(Path.GetFileName(unzippedFolderPath)).MakeMinecraftSafe(); string packName = Globals.RESOURCEPACK + folder_uuid; // Paths string fullOutputPath = Path.Combine(datapackOutputPath, packName + Globals.ZIP); string rootFolderPath = Path.Combine(unzippedFolderPath, packName); string minecraftNamespace = Path.Combine(rootFolderPath, Globals.ASSETS, Globals.MINECRAFT); string mapSong = Path.Combine(unzippedFolderPath, packInfo.SongFilename); string packSong = Path.Combine(minecraftNamespace, Globals.SOUNDS, Globals.CUSTOM, folder_uuid + Globals.OGG); string mapIcon = Path.Combine(unzippedFolderPath, packInfo.CoverImageFilename); string packIcon = Path.Combine(rootFolderPath, Globals.PACK_ICON); // Replaced vars keyVars["SONGUUID"] = folder_uuid; keyVars["SONGNAME"] = packInfo.SongName + packInfo.SongSubName; keyVars["AUTHORNAME"] = packInfo.SongAuthorName; // Copying Template string copiedTemplatePath = Path.Combine(unzippedFolderPath, Globals.TEMPLATE_RESOURCES_PACK_NAME); if (SafeFileManagement.DirectoryCopy(Globals.pathOfResourcepackTemplate, unzippedFolderPath, true, Globals.excludeExtensions, Globals.NUMBER_OF_IO_RETRY_ATTEMPTS)) { if (SafeFileManagement.MoveDirectory(copiedTemplatePath, rootFolderPath, Globals.NUMBER_OF_IO_RETRY_ATTEMPTS)) { Filemanagement.UpdateAllCopiedFiles(rootFolderPath, keyVars); // Copying Image Icon SafeFileManagement.CopyFileTo(mapIcon, packIcon, true, Globals.NUMBER_OF_IO_RETRY_ATTEMPTS); // Copying Song if (SafeFileManagement.CopyFileTo(mapSong, packSong, true, Globals.NUMBER_OF_IO_RETRY_ATTEMPTS)) { if (!Filemanagement.UpdateFileWithKeys(Path.Combine(minecraftNamespace, Globals.SOUNDS_JSON), keyVars)) { return ConversionError.OtherFail; } } // Creating Zip Archive.Compress(rootFolderPath, fullOutputPath, true); return ConversionError.None; } } return ConversionError.FailedToCopyFile; })); }
/// <summary> /// Convert a Beat Saber Zip file into a Minecraft Resourcepack and Datapack /// </summary> /// <param name="zipPath">file path to beat saber zip file</param> /// <param name="datapackOutputPath">folder path that minecraft zips will be generated</param> /// <param name="uuid">Unique number that determines song value</param> /// <param name="cancellationToken">Token that allows async function to be canceled</param> /// <returns>-1 on Success</returns> public static async Task <ConversionError> ConvertAsync(string zipPath, string datapackOutputPath, int uuid, IProgress <ConversionProgress> progress, CancellationToken cancellationToken) { if (!File.Exists(zipPath) || !Directory.Exists(datapackOutputPath)) { return(ConversionError.MissingInfo); } progress.Report(new ConversionProgress(0.1f, "Loading beat map file")); var beatSaberMap = await MapLoader.GetDataFromMapZip(zipPath, ProcessManager.temporaryPath, cancellationToken); if (beatSaberMap == null) { return(ConversionError.InvalidBeatMap); } cancellationToken.ThrowIfCancellationRequested(); var tempFolder = beatSaberMap.ExtractedFilePath; try { beatSaberMap = ConvertFilesEggToOgg(beatSaberMap); beatSaberMap = ConvertFilesJpgToPng(beatSaberMap); if (beatSaberMap.InfoData.DifficultyBeatmapSets.Length == 0) { return(ConversionError.NoMapData); } cancellationToken.ThrowIfCancellationRequested(); // Generating Resource pack progress.Report(new ConversionProgress(0.2f, "Generating resource pack")); var resourcepackError = await ResourcePack.FromBeatSaberData(datapackOutputPath, beatSaberMap); if (resourcepackError != ConversionError.None) { return(resourcepackError); } cancellationToken.ThrowIfCancellationRequested(); // Generating Data pack progress.Report(new ConversionProgress(0.3f, "Generating datapack")); var datapackError = await DataPack.FromBeatSaberData(datapackOutputPath, beatSaberMap, progress, cancellationToken); if (datapackError != ConversionError.None) { return(datapackError); } } catch (OperationCanceledException e) { SafeFileManagement.DeleteDirectory(tempFolder); throw (e); } catch (ObjectDisposedException) { SafeFileManagement.DeleteDirectory(tempFolder); } // Successfully converted map SafeFileManagement.DeleteDirectory(tempFolder); return(ConversionError.None); }
public static BeatSaberMap ConvertFilesJpgToPng(BeatSaberMap beatSaberMap) { string[] files = Directory.GetFiles(beatSaberMap.ExtractedFilePath, "*.jpg*", SearchOption.AllDirectories); beatSaberMap.InfoData.CoverImageFilename = beatSaberMap.InfoData.CoverImageFilename.Replace(".jpg", ".png"); foreach (string path in files) { string newName = path.Replace(".jpg", ".png"); SafeFileManagement.MoveFile(path, newName); } return(beatSaberMap); }
/// <summary> /// Replace any keys within a file from a dictionary /// </summary> /// <param name="filePath">path of file to replace keys in</param> /// <param name="keyVars">dictionary of words to replace within files</param> public static bool UpdateFileWithKeys(string filePath, Dictionary <string, string> keyVars) { string textInfo = SafeFileManagement.GetFileContents(filePath); if (textInfo == null) { return(false); } foreach (string key in keyVars.Keys) { textInfo = textInfo.Replace(key, keyVars[key]); } return(SafeFileManagement.SetFileContents(filePath, textInfo)); }
public DataPackData(string unzippedFolderPath, string datapackOutputPath, BeatSaberMap beatSaberMap) { var packInfo = beatSaberMap.InfoData; keyVars = new Dictionary <string, string>(); folder_uuid = SafeFileManagement.GetFileName(Path.GetFileName(unzippedFolderPath)).MakeMinecraftSafe(); packName = Globals.DATAPACK + folder_uuid; songGuid = beatSaberMap.GuidId.ToString(); // Paths datapackRootPath = Path.Combine(unzippedFolderPath, packName); fullOutputPath = Path.Combine(datapackOutputPath, packName + Globals.ZIP); blockSaberBaseFunctionsPath = Path.Combine(datapackRootPath, Globals.DATA, Globals.BLOCK_SABER_BASE, Globals.FUNCTIONS); folder_uuidFunctionsPath = Path.Combine(datapackRootPath, Globals.DATA, folder_uuid, Globals.FUNCTIONS); spawnNotesBasePath = Path.Combine(folder_uuidFunctionsPath, Globals.SPAWN_NOTES_BASE_FUNCTION); // Values metersPerTick = packInfo.BeatsPerMinute / 60.0d * 24 * 0.21 / 20; ticksStartOffset = (int)(Mathf.Clamp((float)(packInfo.BeatsPerMinute / 60d * 10), 7, 20) / metersPerTick); // Set up Keys keyVars["MAPPER_NAME"] = packInfo.LevelAuthorName; keyVars["BEATS_PER_MINUTE"] = packInfo.BeatsPerMinute.ToString(); keyVars["SONGID"] = beatSaberMap.GuidId.GetHashCode().ToString(); keyVars["MOVESPEED"] = metersPerTick.ToString(); keyVars["SONGTITLE"] = packInfo.SongName + " " + packInfo.SongSubName; keyVars["SONGSHORTNAME"] = packInfo.SongName; keyVars["SONGARTIST"] = packInfo.SongAuthorName; keyVars["folder_uuid"] = folder_uuid; keyVars["SONGDIFFICULTYID"] = songGuid + "1"; StringBuilder listOfDifficulties = new StringBuilder(); var beatMapSets = beatSaberMap.InfoData.DifficultyBeatmapSets; for (int beatMapCounts = 0; beatMapCounts < beatMapSets.Length; beatMapCounts++) { var beatMapInfos = beatMapSets[beatMapCounts].DifficultyBeatmaps; int beatMapCount = beatMapInfos.Length; for (int difficulty = 0; difficulty < beatMapCount; difficulty++) { listOfDifficulties.Append(beatMapInfos[difficulty].Difficulty); if (difficulty < beatMapCount - 1) { listOfDifficulties.Append(" | "); } } } keyVars["DIFFICULTYLIST"] = listOfDifficulties.ToString(); }
/// <summary> /// Convert images file to png /// </summary> /// <param name="rootFilePath">Folder that contains .jpg files</param> /// <param name="packInfo">info object that contains data about beatsaber songs</param> /// <returns>updated pack info object</returns> public static Info ConvertImageFiles(string rootFilePath, Info packInfo) { string[] files = Directory.GetFiles(rootFilePath, "*.jpg*", SearchOption.AllDirectories); if (string.IsNullOrEmpty(packInfo.CoverImageFilename)) { return(null); } packInfo.CoverImageFilename = packInfo.CoverImageFilename.Replace(".jpg", ".png"); foreach (string path in files) { string newName = path.Replace(".jpg", ".png"); SafeFileManagement.MoveFile(path, newName); } return(packInfo); }
public static BeatSaberMap ConvertFilesEggToOgg(BeatSaberMap beatSaberMap) { string[] files = Directory.GetFiles(beatSaberMap.ExtractedFilePath, "*.egg*", SearchOption.AllDirectories); string[] alreadyConvertedfiles = Directory.GetFiles(beatSaberMap.ExtractedFilePath, "*.ogg*", SearchOption.AllDirectories); if (files.Length == 0 && alreadyConvertedfiles.Length == 0) { return(beatSaberMap); } beatSaberMap.InfoData.SongFilename = beatSaberMap.InfoData.SongFilename.Replace(".egg", ".ogg"); foreach (string path in files) { string newName = path.Replace(".egg", ".ogg"); SafeFileManagement.MoveFile(path, newName); } return(beatSaberMap); }
/// <summary> /// Get all data from beatsaber map zip file /// </summary> /// <param name="fileToUnzip">path to beat saber map zip</param> /// <param name="pathToUnzip">path to unzip map data</param> /// <param name="cancellationToken">token to cancel action</param> /// <returns></returns> public static async Task <BeatSaberMap> GetDataFromMapZip(string fileToUnzip, string pathToUnzip, CancellationToken cancellationToken) { string tempUnZipPath = Path.Combine(pathToUnzip, "MapLoader", SafeFileManagement.GetFolderName(fileToUnzip)); if (Directory.Exists(tempUnZipPath)) { SafeFileManagement.DeleteDirectory(tempUnZipPath); } Directory.CreateDirectory(tempUnZipPath); await Archive.DecompressAsync(fileToUnzip, tempUnZipPath, cancellationToken); cancellationToken.ThrowIfCancellationRequested(); return(await Task.Run(() => { string infoPath = Path.Combine(tempUnZipPath, "info.dat"); Info info = JsonUtility.FromJson <Info>(SafeFileManagement.GetFileContents(infoPath)); if (info == null) { return null; } info = ConvertSoundFile(tempUnZipPath, info); if (info == null) { return null; } info = ConvertImageFiles(tempUnZipPath, info); if (info == null) { return null; } cancellationToken.ThrowIfCancellationRequested(); Dictionary <string, MapDataInfo> mapDataInfos = new Dictionary <string, MapDataInfo>(); foreach (var beatMapSets in info.DifficultyBeatmapSets) { foreach (var beatMap in beatMapSets.DifficultyBeatmaps) { string mapPath = Path.Combine(tempUnZipPath, beatMap.BeatmapFilename); MapData mapData = JsonUtility.FromJson <MapData>(SafeFileManagement.GetFileContents(mapPath)); mapDataInfos.Add(beatMap.BeatmapFilename, new MapDataInfo(beatMap, mapData)); } } return new BeatSaberMap(info, mapDataInfos, tempUnZipPath); })); }
/// <summary> /// Convert egg file to ogg /// </summary> /// <param name="rootFilePath">Folder that contains .egg files</param> /// <param name="info">Info object that contains data about beatsaber songs</param> /// <returns>Updated pack info object</returns> public static Info ConvertSoundFile(string rootFilePath, Info info) { string[] files = Directory.GetFiles(rootFilePath, "*.egg*", SearchOption.AllDirectories); string[] alreadyConvertedfiles = Directory.GetFiles(rootFilePath, "*.ogg*", SearchOption.AllDirectories); if (string.IsNullOrEmpty(info.SongFilename)) { return(null); } info.SongFilename = info.SongFilename.Replace(".egg", ".ogg"); if (files.Length == 0 && alreadyConvertedfiles.Length == 0) { return(null); } foreach (string path in files) { string newName = path.Replace(".egg", ".ogg"); SafeFileManagement.MoveFile(path, newName); } return(info); }
public void OpenOutputPath() { SafeFileManagement.OpenFolder(OutputPath); }
/// <summary> /// Generate obstacles commands given a song and difficulty /// </summary> /// <param name="song">Beatmap data for a song and difficulty</param> /// <param name="difficultyName">Minecraft safe difficulty name</param> /// <param name="commandBasePath">Base folder path to generate new mcfunctions</param> /// <param name="packInfo">Beat Saber Parsed info</param> /// <param name="dpd">Data used for datapack generation</param> public static void GenerateObstacles(MapData song, string difficultyName, string commandBasePath, Info packInfo, DataPackData dpd) { Obstacle[] obstacles = song.Obstacles; int obstacleIndex = 0; int currentLevel = 1; int currentTick = 0; int maxTick = 0; int minTick = -1; int currentNumberOfCommands = 0; int currentCommandLimit = Globals.COMMAND_LIMIT; // Main note generation while (obstacleIndex < obstacles.Length) { string commandLevelName = difficultyName + Globals.LEVEL_OBSTACLE_NAME + currentLevel; string commandLevelFileName = commandLevelName + Globals.MCFUNCTION; string commandLevelFilePath = Path.Combine(dpd.folder_uuidFunctionsPath, commandLevelFileName); StringBuilder currentCommands = new StringBuilder(); int maxNewTick = 0; int minNewTick = 0; minTick = -1; // Continue to generate commands until all nodes and obstacles have been iterated though while (obstacleIndex < obstacles.Length && currentNumberOfCommands < currentCommandLimit) { ObstacleDataToCommands(obstacles[obstacleIndex], packInfo.BeatsPerMinute, dpd.metersPerTick, ref currentCommands, ref currentNumberOfCommands, ref minNewTick, ref maxNewTick); if (minTick == -1) { minTick = minNewTick; } maxTick = Mathf.Max(maxTick, maxNewTick); obstacleIndex++; } if (obstacleIndex >= obstacles.Length) { maxTick += (int)(dpd.ticksStartOffset + 1); currentCommands.AppendFormat(Globals.templateStrings._finishedObstacles, maxTick); if (minTick == -1) { minTick = maxTick - 1; } } SafeFileManagement.SetFileContents(commandLevelFilePath, currentCommands.ToString()); string baseCommand = string.Format(Globals.templateStrings._baseCommand, minTick, maxTick, dpd.folder_uuid, commandLevelName); SafeFileManagement.AppendFile(commandBasePath, baseCommand); currentCommandLimit = currentNumberOfCommands + Globals.COMMAND_LIMIT; minTick = 0; maxTick = 0; currentLevel++; } if (obstacles.Length == 0) { string commandLevelName = difficultyName + Globals.LEVEL_OBSTACLE_NAME + currentLevel; string commandLevelFileName = commandLevelName + Globals.MCFUNCTION; string commandLevelFilePath = Path.Combine(dpd.folder_uuidFunctionsPath, commandLevelFileName); StringBuilder currentCommands = new StringBuilder(); currentTick++; currentCommands.AppendFormat(Globals.templateStrings._finishedObstacles, currentTick); SafeFileManagement.SetFileContents(commandLevelFilePath, currentCommands.ToString()); string baseCommand = string.Format(Globals.templateStrings._baseCommand, minTick, maxTick + (int)(dpd.ticksStartOffset + 1), dpd.folder_uuid, commandLevelName); SafeFileManagement.AppendFile(commandBasePath, baseCommand); } }
/// <summary> /// Generate a minecraft datapack from Beat Saber data /// </summary> /// <param name="unzippedFolderPath">Path of unzipped Beat Saber data</param> /// <param name="datapackOutputPath">Path to output datapack</param> /// <param name="packInfo">Beat Saber Parsed info</param> /// <param name="beatMapSongList">List of Beat Saber song data</param> /// <param name="cancellationToken">Token that allows async function to be canceled</param> /// <returns></returns> public static async Task <ConversionError> FromBeatSaberData(string datapackOutputPath, BeatSaberMap beatSaberMap, IProgress <ConversionProgress> progress, CancellationToken cancellationToken) { return(await Task.Run(() => { var unzippedFolderPath = beatSaberMap.ExtractedFilePath; if (!Directory.Exists(unzippedFolderPath)) { return Task.FromResult(ConversionError.UnzipError); } DataPackData dataPackData = new DataPackData(unzippedFolderPath, datapackOutputPath, beatSaberMap); if (beatSaberMap.InfoData.DifficultyBeatmapSets.Length == 0) { return Task.FromResult(ConversionError.NoMapData); } // Copying Template string copiedTemplatePath = Path.Combine(unzippedFolderPath, Globals.TEMPLATE_DATA_PACK_NAME); if (!SafeFileManagement.DirectoryCopy(Globals.pathOfDatapackTemplate, unzippedFolderPath, true, Globals.excludeExtensions, Globals.NUMBER_OF_IO_RETRY_ATTEMPTS)) { return Task.FromResult(ConversionError.FailedToCopyFile); } try { if (SafeFileManagement.MoveDirectory(copiedTemplatePath, dataPackData.datapackRootPath, Globals.NUMBER_OF_IO_RETRY_ATTEMPTS)) { cancellationToken.ThrowIfCancellationRequested(); // Must change the folder names before searching for keys string songname_uuidFolder = Path.Combine(dataPackData.datapackRootPath, Globals.DATA, Globals.FOLDER_UUID); string newPath = Path.Combine(dataPackData.datapackRootPath, Globals.DATA, dataPackData.folder_uuid); SafeFileManagement.MoveDirectory(songname_uuidFolder, newPath, Globals.NUMBER_OF_IO_RETRY_ATTEMPTS); // Updating Copied files Filemanagement.UpdateAllCopiedFiles(dataPackData.datapackRootPath, dataPackData.keyVars, true, Globals.excludeKeyVarExtensions); // Copying Image Icon string mapIcon = Path.Combine(unzippedFolderPath, beatSaberMap.InfoData.CoverImageFilename); string packIcon = Path.Combine(dataPackData.datapackRootPath, Globals.PACK_ICON); SafeFileManagement.CopyFileTo(mapIcon, packIcon, true, Globals.NUMBER_OF_IO_RETRY_ATTEMPTS); cancellationToken.ThrowIfCancellationRequested(); progress.Report(new ConversionProgress(0.4f, "Generating main datapack files")); var mcBeatDataError = GenerateMCBeatData(beatSaberMap, dataPackData, progress, cancellationToken); if (mcBeatDataError != ConversionError.None) { return Task.FromResult(mcBeatDataError); } cancellationToken.ThrowIfCancellationRequested(); progress.Report(new ConversionProgress(0.9f, "Zipping files")); Archive.Compress(dataPackData.datapackRootPath, dataPackData.fullOutputPath, true); return Task.FromResult(ConversionError.None); } } catch (OperationCanceledException wasCanceled) { throw wasCanceled; } catch (ObjectDisposedException wasAreadyCanceled) { throw wasAreadyCanceled; } return Task.FromResult(ConversionError.OtherFail); })); }
/// <summary> /// Generate note commands given a song and difficulty /// </summary> /// <param name="song">Beatmap data for a song and difficulty</param> /// <param name="difficultyName">Minecraft safe difficulty name</param> /// <param name="commandBasePath">Base folder path to generate new mcfunctions</param> /// <param name="packInfo">Beat Saber Parsed info</param> /// <param name="dpd">Data used for datapack generation</param> public static void GenerateNotes(MapData song, string difficultyName, string commandBasePath, Info packInfo, DataPackData dpd) { double prevNodeTime = 0; int nodeRowID = 1; int currentLevel = 1; int currentTick = 0; int prevCurrentTick = 0; int currentNumberOfCommands = 0; int noteIndex = 0; int currentCommandLimit = Globals.COMMAND_LIMIT; var notes = song.Notes; // Main note generation while (noteIndex < notes.Length) { string commandLevelName = difficultyName + Globals.LEVEL_NOTE_NAME + currentLevel; string commandLevelFileName = commandLevelName + Globals.MCFUNCTION; string commandLevelFilePath = Path.Combine(dpd.folder_uuidFunctionsPath, commandLevelFileName); StringBuilder currentCommands = new StringBuilder(); // Continue to generate commands until all nodes and obstacles have been iterated though while (noteIndex < notes.Length && currentNumberOfCommands < currentCommandLimit) { if (prevNodeTime != notes[noteIndex].Time) { nodeRowID++; } NodeDataToCommands(notes[noteIndex], packInfo.BeatsPerMinute, dpd.metersPerTick, nodeRowID, ref currentCommands, ref currentTick); prevNodeTime = notes[noteIndex].Time; currentNumberOfCommands += 3; noteIndex++; } if (noteIndex >= notes.Length) { currentTick += (int)(dpd.ticksStartOffset + 1);; currentCommands.AppendFormat(Globals.templateStrings._finishedNotes, currentTick); } SafeFileManagement.SetFileContents(commandLevelFilePath, currentCommands.ToString()); string baseCommand = string.Format(Globals.templateStrings._baseCommand, prevCurrentTick, currentTick, dpd.folder_uuid, commandLevelName); SafeFileManagement.AppendFile(commandBasePath, baseCommand); prevCurrentTick = currentTick + 1; currentCommandLimit = currentNumberOfCommands + Globals.COMMAND_LIMIT; currentLevel++; } // Note pretty buy create a command if no obstacles are present in a map if (notes.Length == 0) { currentTick += (int)(dpd.ticksStartOffset + 1);; string commandLevelName = difficultyName + Globals.LEVEL_NOTE_NAME + currentLevel; string commandLevelFileName = commandLevelName + Globals.MCFUNCTION; string commandLevelFilePath = Path.Combine(dpd.folder_uuidFunctionsPath, commandLevelFileName); StringBuilder currentCommands = new StringBuilder(); SafeFileManagement.SetFileContents(commandLevelFilePath, currentCommands.ToString()); string baseCommand = string.Format(Globals.templateStrings._baseCommand, prevCurrentTick, currentTick, dpd.folder_uuid, commandLevelName); SafeFileManagement.AppendFile(commandBasePath, baseCommand); currentCommands.AppendFormat(Globals.templateStrings._finishedNotes, currentTick); } }
public static void GenerateEvents(MapData song, string difficultyName, string commandBasePath, Info packInfo, DataPackData dpd) { int currentLevel = 1; int currentTick = 0; int prevCurrentTick = 0; int currentNumberOfCommands = 0; int noteIndex = 0; int currentCommandLimit = Globals.COMMAND_LIMIT; var bEvents = song.Events.Where(x => x.Value >= 0 && x.Value <= 11).ToArray(); List <EventFadeSave> autoOffTick = new List <EventFadeSave>(); for (int i = 0; i < 10; i++) { autoOffTick.Add(new EventFadeSave()); } // Main note generation while (noteIndex < bEvents.Length) { string commandLevelName = difficultyName + Globals.LEVEL_EVENT_NAME + currentLevel; string commandLevelFileName = commandLevelName + Globals.MCFUNCTION; string commandLevelFilePath = Path.Combine(dpd.folder_uuidFunctionsPath, commandLevelFileName); StringBuilder currentCommands = new StringBuilder(); // Continue to generate commands until all events while (noteIndex < bEvents.Length && currentNumberOfCommands < currentCommandLimit) { currentNumberOfCommands += EventDataToCommands(bEvents[noteIndex], packInfo.BeatsPerMinute, dpd, ref currentCommands, ref currentTick, ref autoOffTick); noteIndex++; } if (noteIndex >= bEvents.Length) { currentTick += (int)(dpd.ticksStartOffset + 1);; currentCommands.AppendFormat(Globals.templateStrings._finishedEvents, currentTick); } SafeFileManagement.SetFileContents(commandLevelFilePath, currentCommands.ToString()); string baseCommand = string.Format(Globals.templateStrings._baseCommand, prevCurrentTick, currentTick, dpd.folder_uuid, commandLevelName); SafeFileManagement.AppendFile(commandBasePath, baseCommand); prevCurrentTick = currentTick + 1; currentCommandLimit = currentNumberOfCommands + Globals.COMMAND_LIMIT; currentLevel++; } // Note pretty buy create a command if no obstacles are present in a map if (bEvents.Length == 0) { currentTick += (int)(dpd.ticksStartOffset + 1);; string commandLevelName = difficultyName + Globals.LEVEL_EVENT_NAME + currentLevel; string commandLevelFileName = commandLevelName + Globals.MCFUNCTION; string commandLevelFilePath = Path.Combine(dpd.folder_uuidFunctionsPath, commandLevelFileName); StringBuilder currentCommands = new StringBuilder(); SafeFileManagement.SetFileContents(commandLevelFilePath, currentCommands.ToString()); string baseCommand = string.Format(Globals.templateStrings._baseCommand, prevCurrentTick, currentTick, dpd.folder_uuid, commandLevelName); SafeFileManagement.AppendFile(commandBasePath, baseCommand); currentCommands.AppendFormat(Globals.templateStrings._finishedNotes, currentTick); } }
/// <summary> /// Main generation of minecraft commands for beat saber data /// </summary> /// <param name="beatMapSongList">List of Beat Saber song data</param> /// <param name="packInfo">Beat Saber Parsed info</param> /// <param name="dpd">Data used for datapack generation</param> /// <returns></returns> public static ConversionError GenerateMCBeatData(BeatSaberMap beatSaberMap, DataPackData dpd, IProgress <ConversionProgress> progress, CancellationToken cancellationToken) { StringBuilder difficultyDisplayCommands = new StringBuilder(); StringBuilder scoreboardCommands = new StringBuilder(); StringBuilder spawnOriginCommands = new StringBuilder(); StringBuilder spawnNotesBaseCommands = new StringBuilder(); int difficultyNumber = 1; // Iterate though each song difficulty var mapDataInfos = beatSaberMap.MapDataInfos; var progressPercent = 0.4f; var mapDataInfosKeys = mapDataInfos.Keys.ToArray(); var progressIncrament = mapDataInfosKeys.Length * 0.5f; for (int i = 0; i < mapDataInfosKeys.Length; i++) { var mapDataInfo = mapDataInfos[mapDataInfosKeys[i]]; if (mapDataInfo.MapData == null || mapDataInfo.MapData.Notes == null || mapDataInfo.MapData.Obstacles == null) { return(ConversionError.NoMapData); } progress.Report(new ConversionProgress(progressPercent + progressIncrament, "Generating minecraft commands")); if (mapDataInfo.MapData.Notes.Length > 0 || mapDataInfo.MapData.Obstacles.Length > 0) { string difficultyName = mapDataInfo.DifficultyBeatmapInfo.Difficulty.MakeMinecraftSafe(); // Append running command lists string songDifficultyID = dpd.songGuid + difficultyNumber.ToString(); scoreboardCommands.AppendFormat(Globals.templateStrings._scoreboardCommand, songDifficultyID); spawnOriginCommands.AppendFormat(Globals.templateStrings._spawnOriginCommands, -dpd.metersPerTick * dpd.ticksStartOffset, difficultyNumber); spawnNotesBaseCommands.AppendFormat(Globals.templateStrings._spawnNotesBaseCommand, difficultyNumber, dpd.folder_uuid, difficultyName); CreateDifficultyDisplay(songDifficultyID, difficultyName, dpd.folder_uuid, ref difficultyDisplayCommands); // Write difficulty-specific-file commands string playCommands = string.Format(Globals.templateStrings._playCommands, difficultyNumber, dpd.folder_uuid); string playPath = Path.Combine(dpd.folder_uuidFunctionsPath, difficultyName + "_play" + Globals.MCFUNCTION); SafeFileManagement.SetFileContents(playPath, playCommands); string playSongCommand = string.Format(Globals.templateStrings._playSongCommand, dpd.ticksStartOffset - 1, dpd.folder_uuid); string commandBasePath = Path.Combine(dpd.folder_uuidFunctionsPath, difficultyName + Globals.MCFUNCTION); SafeFileManagement.AppendFile(commandBasePath, playSongCommand); string completedSongCommand = string.Format(Globals.templateStrings._completedSong, difficultyNumber, songDifficultyID); string completedSongPath = Path.Combine(dpd.folder_uuidFunctionsPath, Globals.MAP_DIFFICULTY_COMPLETED); SafeFileManagement.AppendFile(completedSongPath, completedSongCommand); // Generate main note/obstacle data/light data GenerateNotes(mapDataInfo.MapData, difficultyName, commandBasePath, beatSaberMap.InfoData, dpd); GenerateObstacles(mapDataInfo.MapData, difficultyName, commandBasePath, beatSaberMap.InfoData, dpd); GenerateEvents(mapDataInfo.MapData, difficultyName, commandBasePath, beatSaberMap.InfoData, dpd); difficultyNumber++; } } // Write collected commands to files string difficultiesFunctionPath = Path.Combine(dpd.folder_uuidFunctionsPath, Globals.DIFFICULTIES); string initFunctionPath = Path.Combine(dpd.folder_uuidFunctionsPath, Globals.INIT_FUNCTION); string setSpawnOrginFunctionPath = Path.Combine(dpd.folder_uuidFunctionsPath, Globals.SET_SPAWN_ORIGIN); SafeFileManagement.AppendFile(dpd.spawnNotesBasePath, spawnNotesBaseCommands.ToString()); SafeFileManagement.AppendFile(setSpawnOrginFunctionPath, spawnOriginCommands.ToString()); SafeFileManagement.AppendFile(initFunctionPath, scoreboardCommands.ToString()); // Add back button in tellraw difficultyDisplayCommands.Append(Globals.templateStrings._mainMenuBack); SafeFileManagement.AppendFile(difficultiesFunctionPath, difficultyDisplayCommands.ToString()); return(ConversionError.None); }