예제 #1
0
            public void StartCaching()
            {
                if (!IsCaching)
                {
                    _manualResetEvent     = new ManualResetEvent(true);
                    _thread               = new Thread(CachingThread);
                    _isOperationCancelled = false;

                    _thread.Start();
                    CachingStarted?.Invoke();
                }
            }
예제 #2
0
            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();
            }