public void StartCaching() { if (!IsCaching) { _manualResetEvent = new ManualResetEvent(true); _thread = new Thread(CachingThread); _isOperationCancelled = false; _thread.Start(); CachingStarted?.Invoke(); } }
private IEnumerator CacheAllBeatmapDetailsCoroutine() { CachingStarted?.Invoke(); var sw = Stopwatch.StartNew(); // load beatmap details from cache if it exists var loadCache = PopulateCacheFromFileCoroutine(); while (loadCache.MoveNext()) { yield return(loadCache.Current); } // we don't have to cache OST levels, since they can be immediately cast into IBeatmapLevel objects List <IPreviewBeatmapLevel> allCustomLevels = BeatmapDetailsLoader.GetAllCustomLevels(); // record errors from SongDataCore for logging List <SongDataCoreDataStatus> sdcErrorStatusList = new List <SongDataCoreDataStatus>(allCustomLevels.Count); List <IEnumerator <BeatmapDetails> > taskList = new List <IEnumerator <BeatmapDetails> >(WorkChunkSize); int index = 0; int errorCount = 0; long elapsed = 0; while (index < allCustomLevels.Count) { if (sw.ElapsedMilliseconds > 30000 + elapsed) { elapsed = sw.ElapsedMilliseconds; Logger.log.Debug($"Caching coroutine has finished caching {index} beatmaps out of {allCustomLevels.Count} ({elapsed} ms elapsed)"); } while (_cachingPaused) { yield return(null); } int startingIndex = index; for (int i = 0; i < WorkChunkSize && index < allCustomLevels.Count && index - startingIndex < WorkQueryChunkSize; ++index) { string levelID = GetSimplifiedLevelID(allCustomLevels[index]); if (BeatmapDetailsLoader._cache.ContainsKey(levelID) && BeatmapDetailsLoader._cache[levelID].SongDuration > 0.01f) { continue; } SongDataCoreDataStatus status = SongDataCoreTweaks.GetBeatmapDetails(allCustomLevels[index] as CustomPreviewBeatmapLevel, out var beatmapDetails); if (status == SongDataCoreDataStatus.Success) { // load the beatmap details manually if some data from BeatSaver is incomplete if (beatmapDetails.DifficultyBeatmapSets.Any(set => set.DifficultyBeatmaps.Any(diff => diff.NoteJumpMovementSpeed == 0))) { Logger.log.Debug($"BeatmapDetails object generated for '{beatmapDetails.SongName}' from BeatSaver data has some incomplete fields. " + "Discarding and generating BeatmapDetails object from locally stored information instead"); taskList.Add(BeatmapDetails.CreateBeatmapDetailsFromFilesCoroutine(allCustomLevels[index] as CustomPreviewBeatmapLevel)); ++i; } else { BeatmapDetailsLoader._cache[levelID] = beatmapDetails; } } else { if (SongDataCoreTweaks.IsModAvailable) { sdcErrorStatusList.Add(status); } taskList.Add(BeatmapDetails.CreateBeatmapDetailsFromFilesCoroutine(allCustomLevels[index] as CustomPreviewBeatmapLevel)); ++i; } } if (taskList.Any()) { yield return(null); } while (taskList.Any()) { while (_cachingPaused) { yield return(null); } for (int i = 0; i < taskList.Count; ++i) { IEnumerator <BeatmapDetails> loadCoroutine = taskList[i]; if (loadCoroutine.MoveNext()) { BeatmapDetails beatmapDetails = loadCoroutine.Current; if (beatmapDetails != null) { BeatmapDetailsLoader._cache[beatmapDetails.LevelID] = beatmapDetails; taskList.Remove(loadCoroutine); --i; } } else { ++errorCount; taskList.Remove(loadCoroutine); --i; } } if (taskList.Any()) { yield return(null); } } if (index < allCustomLevels.Count) { yield return(null); } } // check for pause before writing to disk while (_cachingPaused) { yield return(null); } sw.Stop(); Logger.log.Info($"Finished caching the details of {allCustomLevels.Count} beatmaps (took {sw.ElapsedMilliseconds / 1000f} seconds)"); if (errorCount > 0) { Logger.log.Warn($"Unable to cache the beatmap details for {errorCount} songs"); } if (sdcErrorStatusList.Count > 0) { // NOTE: this will need to be updated if i ever add more error status markers Logger.log.Debug($"Unable to retrieve some data from SongDataCore: (" + $"NoData = {sdcErrorStatusList.Count(x => x == SongDataCoreDataStatus.NoData)}, " + $"InvalidBPM = {sdcErrorStatusList.Count(x => x == SongDataCoreDataStatus.InvalidBPM)}, " + $"InvalidDuration = {sdcErrorStatusList.Count(x => x == SongDataCoreDataStatus.InvalidDuration)}, " + $"InvalidCharacteristicString = {sdcErrorStatusList.Count(x => x == SongDataCoreDataStatus.InvalidCharacteristicString)}, " + $"InvalidDifficultyString = {sdcErrorStatusList.Count(x => x == SongDataCoreDataStatus.InvalidDifficultyString)}, " + $"ExceptionThrown = {sdcErrorStatusList.Count(x => x == SongDataCoreDataStatus.ExceptionThrown)})"); } BeatmapDetailsLoader.instance.SaveCacheToFile(); _cachingCoroutine = null; CachingFinished?.Invoke(); }