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