public BeatmapLevelDataObject DeserializeFromJson(string songPath, string overrideLevelID) { try { var jsonSettings = new JsonSerializerSettings() { ContractResolver = new MetadataResolver(_assetsFile) }; string infoFile = Path.Combine(songPath, "Info.dat"); BeatmapLevelDataObject bml = null; using (var sr = new StreamReader(_config.SongFileProvider.GetReadStream(infoFile))) { bml = JsonConvert.DeserializeObject <BeatmapLevelDataObject>(sr.ReadToEnd(), jsonSettings); } if (!string.IsNullOrWhiteSpace(overrideLevelID)) { bml.LevelID = overrideLevelID; } return(bml); } catch (Exception ex) { Log.LogErr("Exception deserializing level", ex); return(null); } }
//todo: not sure if this is always safe to assume the folder where the ogg is has the info.dat, but I hope it is public string GetCoverImageFilename(BeatmapLevelDataObject levelData) { var path = levelData?.AudioClip?.Object?.Resource?.Source; if (path == null) { Log.LogErr("Trying to get the cover image file, audio clip resource object was null!"); return(null); } if (!path.StartsWith(_config.SongsPath)) { Log.LogErr($"The audio clip path for level ID {levelData.LevelID} of '{path}' doesn't match with the configured songs path of '{_config.SongsPath}'. Can't get cover art image location!"); return(null); } //path = path.Substring(_config.SongsPath.Length).TrimStart('/'); int idx = path.LastIndexOf("/"); path = path.Substring(0, idx); var infodatfile = path.CombineFwdSlash("info.dat"); if (!_config.SongFileProvider.FileExists(infodatfile)) { Log.LogErr($"Could not find {infodatfile} for level ID {levelData.LevelID}"); return(null); } //I hope this is a faster way than deserializing the entire object and worth the double code paths for parsing the same serialized type string imageFilename = null; try { using (var jr = new JsonTextReader(new StreamReader(_config.SongFileProvider.GetReadStream(infodatfile)))) { while (jr.Read()) { if (jr.TokenType == JsonToken.PropertyName && jr.Value?.ToString() == "_coverImageFilename") { if (jr.Read() && jr.TokenType == JsonToken.String) { imageFilename = jr.Value?.ToString(); break; } } } } } catch (Exception ex) { Log.LogErr($"Exception trying to read info.dat to get _coverImageFilename for level ID {levelData.LevelID} from '{infodatfile}'.", ex); return(null); } return(imageFilename); }
public AudioClipObject LoadSongAudioAsset(string songPath, BeatmapLevelDataObject levelData) { string audioClipFile = songPath.CombineFwdSlash(levelData.SongFilename); //string outputFileName = levelData.LevelID + ".ogg"; int channels; int frequency; Single length; byte[] oggBytes = _config.SongFileProvider.Read(audioClipFile); unsafe { GCHandle pinnedArray = GCHandle.Alloc(oggBytes, GCHandleType.Pinned); try { IntPtr pointer = pinnedArray.AddrOfPinnedObject(); int error; StbSharp.StbVorbis.stb_vorbis_alloc alloc; StbSharp.StbVorbis.stb_vorbis v = StbSharp.StbVorbis.stb_vorbis_open_memory((byte *)pointer.ToPointer(), oggBytes.Length, &error, &alloc); channels = v.channels; frequency = (int)v.sample_rate; length = StbSharp.StbVorbis.stb_vorbis_stream_length_in_seconds(v); StbSharp.StbVorbis.stb_vorbis_close(v); } catch (Exception ex) { Log.LogErr($"Exception parsing ogg file {audioClipFile}", ex); return(null); } finally { pinnedArray.Free(); } } var audioClip = new AudioClipObject(_assetsFile) { Name = levelData.LevelID, LoadType = 1, IsTrackerFormat = false, Ambisonic = false, SubsoundIndex = 0, PreloadAudioData = false, LoadInBackground = true, Legacy3D = true, CompressionFormat = 1, BitsPerSample = 16, Channels = channels, Frequency = frequency, Length = (Single)length, Resource = new StreamedResource(audioClipFile, 0, Convert.ToUInt64(_config.SongFileProvider.GetFileSize(audioClipFile))) }; return(audioClip); }
public Texture2DObject LoadSongCover(string songPath, BeatmapLevelDataObject levelData) { if (!string.IsNullOrWhiteSpace(levelData.CoverImageFilename) && _config.SongFileProvider.FileExists(songPath.CombineFwdSlash(levelData.CoverImageFilename))) { try { string coverFile = songPath.CombineFwdSlash(levelData.CoverImageFilename); var coverAsset = new Texture2DObject(_assetsFile) { Name = levelData.LevelID + "Cover" }; byte[] imageBytes = _config.SongFileProvider.Read(coverFile); ImageUtils.Instance.AssignImageToTexture(imageBytes, coverAsset, 256, 256); return(coverAsset); } catch (Exception ex) { Log.LogErr("Error loading cover art asset", ex); } } return(null); }
public Texture2DObject LoadSongCover(string songPath, BeatmapLevelDataObject levelData) { if (!string.IsNullOrWhiteSpace(levelData.CoverImageFilename) && File.Exists(Path.Combine(songPath, levelData.CoverImageFilename))) { try { string coverFile = Path.Combine(songPath, levelData.CoverImageFilename); Bitmap coverImage = (Bitmap)Bitmap.FromFile(coverFile); var coverAsset = new Texture2DObject(_assetsFile) { Name = levelData.LevelID + "Cover" }; ImageUtils.AssignImageToTexture(coverImage, coverAsset, 256, 256); return(coverAsset); } catch (Exception ex) { Log.LogErr("Error loading cover art asset", ex); } } return(null); }
public BeatmapLevelDataObject LoadSongToAsset(BeatmapLevelDataObject beatmapLevel, string songPath, bool includeCovers = true) { try { beatmapLevel.Name = $"{beatmapLevel.LevelID}Level"; //cover art Texture2DObject coverImage = null; if (includeCovers) { coverImage = LoadSongCover(songPath, beatmapLevel); } //audio var audioAsset = LoadSongAudioAsset(songPath, beatmapLevel); if (audioAsset == null) { Log.LogErr($"failed to get audio for song at path {songPath}"); return(null); } var toRemoveSet = new List <DifficultyBeatmapSet>(); foreach (var difficultySet in beatmapLevel.DifficultyBeatmapSets) { var characteristic = GetCharacteristicAsset(difficultySet.BeatmapCharacteristicName)?.PtrFrom(beatmapLevel); if (characteristic == null) { Log.LogErr($"Characteristic {difficultySet.BeatmapCharacteristicName} couldn't be found. Set will be removed."); toRemoveSet.Add(difficultySet); continue; } difficultySet.BeatmapCharacteristic = characteristic; List <DifficultyBeatmap> toRemove = new List <DifficultyBeatmap>(); foreach (var difficultyBeatmap in difficultySet.DifficultyBeatmaps) { string dataFile = null; if (!string.IsNullOrWhiteSpace(difficultyBeatmap.BeatmapFilename)) { dataFile = songPath.CombineFwdSlash(difficultyBeatmap.BeatmapFilename); if (!_config.SongFileProvider.FileExists(dataFile)) { Log.LogErr($"BeatmapFilename was set to {dataFile} but the file didn't exist, will try to fall back to difficulty name."); dataFile = null; } } if (dataFile == null) { dataFile = songPath.CombineFwdSlash($"{difficultyBeatmap.Difficulty.ToString()}.dat"); } if (!_config.SongFileProvider.FileExists(dataFile)) { Log.LogErr(dataFile + " is missing, skipping this difficulty"); toRemove.Add(difficultyBeatmap); continue; } string jsonData = _config.SongFileProvider.ReadToString(dataFile); if (_assetsFile != null) { difficultyBeatmap.BeatmapData = new BeatmapDataObject(_assetsFile); } difficultyBeatmap.BeatmapData.Name = beatmapLevel.LevelID + ((difficultySet.BeatmapCharacteristicName == Characteristic.Standard) ? "" : difficultySet.BeatmapCharacteristicName.ToString()) + difficultyBeatmap.Difficulty.ToString() + "BeatmapData"; difficultyBeatmap.BeatmapData.BeatsPerMinute = beatmapLevel.BeatsPerMinute; difficultyBeatmap.BeatmapData.Shuffle = beatmapLevel.Shuffle; difficultyBeatmap.BeatmapData.ShufflePeriod = beatmapLevel.ShufflePeriod; difficultyBeatmap.BeatmapData.JsonData = jsonData; _assetsFile.AddObject(difficultyBeatmap.BeatmapData, true); difficultyBeatmap.BeatmapDataPtr = difficultyBeatmap.BeatmapData.PtrFrom(beatmapLevel); } toRemove.ForEach(x => difficultySet.DifficultyBeatmaps.Remove(x)); if (difficultySet.DifficultyBeatmaps.Count < 1) { Log.LogErr($"Song at path {songPath} has no valid beatmaps for any difficulty on set {difficultySet.BeatmapCharacteristicName}, removing it"); toRemoveSet.Add(difficultySet); continue; } } toRemoveSet.ForEach(x => beatmapLevel.DifficultyBeatmapSets.Remove(x)); if (beatmapLevel.DifficultyBeatmapSets.Count < 1) { Log.LogErr($"Song at path {songPath} has no valid characterstics, it will not be imported"); return(null); } _assetsFile.AddObject(audioAsset, true); if (coverImage != null) { _assetsFile.AddObject(coverImage); } beatmapLevel.AudioClip = audioAsset.PtrFrom(beatmapLevel); if (coverImage == null) { var bsCover = _assetsFile.FindAsset <Texture2DObject>(x => x.Object.Name == "BeatSaberCover"); if (bsCover == null) { Log.LogErr("Unable to find BeatSaberCover in assets! How is that gone?"); throw new Exception("Could not find beat saber cover in assets! That should never be missing."); } var cover = bsCover.Clone(); _assetsFile.AddObject(cover, true); beatmapLevel.CoverImageTexture2D = cover.PtrFrom(beatmapLevel); } else { beatmapLevel.CoverImageTexture2D = coverImage.PtrFrom(beatmapLevel); } var environment = GetEnvironment(beatmapLevel.EnvironmentName); if (environment == null) { Log.LogMsg($"Unknown environment name '{beatmapLevel.EnvironmentName}' on '{beatmapLevel.SongName}', falling back to default."); environment = GetEnvironment("DefaultEnvironment"); if (environment == null) { throw new Exception("Unable to find the default environment!"); } } beatmapLevel.EnvironmentInfo = environment.PtrFrom(beatmapLevel); _assetsFile.AddObject(beatmapLevel, true); return(beatmapLevel); } catch (Exception ex) { Log.LogErr($"Error loading song from path {songPath}", ex); return(null); } }
public BeatmapLevelDataObject LoadSongToAsset(BeatmapLevelDataObject beatmapLevel, string songPath, out string oggFileName, bool includeCovers = true) { oggFileName = null; try { beatmapLevel.Name = $"{beatmapLevel.LevelID}Level"; //cover art Texture2DObject coverImage = null; if (includeCovers) { coverImage = LoadSongCover(songPath, beatmapLevel); } //audio var audioAsset = LoadSongAudioAsset(songPath, beatmapLevel); if (audioAsset == null) { Log.LogErr($"failed to get audio for song at path {songPath}"); return(null); } oggFileName = Path.Combine(songPath, beatmapLevel.SongFilename);; foreach (var difficultySet in beatmapLevel.DifficultyBeatmapSets) { difficultySet.BeatmapCharacteristic = GetCharacteristicAsset(difficultySet.BeatmapCharacteristicName).PtrFrom(beatmapLevel); List <DifficultyBeatmap> toRemove = new List <DifficultyBeatmap>(); foreach (var difficultyBeatmap in difficultySet.DifficultyBeatmaps) { var dataFile = Path.Combine(songPath, $"{difficultyBeatmap.Difficulty.ToString()}.dat"); if (!File.Exists(dataFile)) { Log.LogErr(dataFile + " is missing, skipping this difficulty"); toRemove.Add(difficultyBeatmap); continue; } string jsonData; using (var sr = new StreamReader(dataFile)) { jsonData = sr.ReadToEnd(); } if (_assetsFile != null) { difficultyBeatmap.BeatmapData = new BeatmapDataObject(_assetsFile); } difficultyBeatmap.BeatmapData.Name = beatmapLevel.LevelID + ((difficultySet.BeatmapCharacteristicName == Characteristic.Standard) ? "" : difficultySet.BeatmapCharacteristicName.ToString()) + difficultyBeatmap.Difficulty.ToString() + "BeatmapData"; difficultyBeatmap.BeatmapData.BeatsPerMinute = beatmapLevel.BeatsPerMinute; difficultyBeatmap.BeatmapData.Shuffle = beatmapLevel.Shuffle; difficultyBeatmap.BeatmapData.ShufflePeriod = beatmapLevel.ShufflePeriod; difficultyBeatmap.BeatmapData.JsonData = jsonData; difficultyBeatmap.BeatmapData.TransformToProjectedData(); difficultyBeatmap.BeatmapData.JsonData = null; _assetsFile.AddObject(difficultyBeatmap.BeatmapData, true); difficultyBeatmap.BeatmapDataPtr = difficultyBeatmap.BeatmapData.PtrFrom(beatmapLevel); } toRemove.ForEach(x => difficultySet.DifficultyBeatmaps.Remove(x)); if (difficultySet.DifficultyBeatmaps.Count < 1) { Log.LogErr($"Song at path {songPath} has no valid beatmaps for any difficulty, skipping song"); return(null); } } _assetsFile.AddObject(audioAsset, true); if (coverImage != null) { _assetsFile.AddObject(coverImage); } beatmapLevel.AudioClip = audioAsset.PtrFrom(beatmapLevel); if (coverImage == null) { beatmapLevel.CoverImageTexture2D = _assetsFile.FindAsset <Texture2DObject>(x => x.Object.Name == "BeatSaberCover").PtrFrom(beatmapLevel); } else { beatmapLevel.CoverImageTexture2D = coverImage.PtrFrom(beatmapLevel); } var environment = _assetsFile.Manager.MassFirstOrDefaultAsset <MonoBehaviourObject>(x => x.Object.Name == $"{beatmapLevel.EnvironmentName}SceneInfo"); if (environment == null) { Log.LogMsg($"Unknown environment name '{beatmapLevel.EnvironmentName}' on '{beatmapLevel.SongName}', falling back to default."); environment = _assetsFile.Manager.MassFirstAsset <MonoBehaviourObject>(x => x.Object.Name == "DefaultEnvironmentSceneInfo"); } beatmapLevel.EnvironmentSceneInfo = environment.PtrFrom(beatmapLevel); _assetsFile.AddObject(beatmapLevel, true); return(beatmapLevel); } catch (Exception ex) { Log.LogErr($"Error loading song from path {songPath}", ex); return(null); } }