private async void ToggleSearch(object sender, EventArgs e) { if (_searchCancelToken != null) { _searchCancelToken.Cancel(); _searchCancelToken = null; return; } var levelPattern = LevPatternBox.Text; var errorFiles = new List <string>(); bool searchForFastestReplays; bool searchForAllReplays; var clickedButton = (Button)sender; if (clickedButton.Equals(SearchButton)) { searchForAllReplays = fastestSlowestSelect.SelectedOption == 2; searchForFastestReplays = fastestSlowestSelect.SelectedOption == 0; } else { searchForAllReplays = true; searchForFastestReplays = false; } var searchOnlyMissingLev = clickedButton.Equals(ReplaysWithoutLevFileButton); var searchOnlyWrongLev = clickedButton.Equals(ReplaysIncorrectLevButton); if (!Utils.RecDirectoryExists()) { Utils.ShowError(Constants.RecDirNotFound); return; } var p1Apples = Range <int> .FromNumericBoxes(TextBox1, TextBox14); var p2Apples = Range <int> .FromNumericBoxes(TextBox3, TextBox16); var p1Turns = Range <int> .FromNumericBoxes(TextBox2, TextBox23); var p2Turns = Range <int> .FromNumericBoxes(TextBox10, TextBox15); var p1Gt = Range <int> .FromNumericBoxes(TextBox11, TextBox24); var p2Gt = Range <int> .FromNumericBoxes(TextBox12, TextBox13); var p1Sv = Range <int> .FromNumericBoxes(TextBox4, TextBox21); var p2Sv = Range <int> .FromNumericBoxes(TextBox9, TextBox22); var p1Rv = Range <int> .FromNumericBoxes(TextBox6, TextBox19); var p2Rv = Range <int> .FromNumericBoxes(TextBox7, TextBox20); var p1Lv = Range <int> .FromNumericBoxes(TextBox8, TextBox17); var p2Lv = Range <int> .FromNumericBoxes(TextBox5, TextBox18); Range <double> time; try { time = Utils.GetTimeRange(TimeMinBox.Text, TimeMaxBox.Text); } catch (Exception) { Utils.ShowError("Time bound is in wrong format. Make sure it is 9 characters long."); return; } var size = new Range <int>((int)minFileSizeBox.Value * 1024, (int)maxFileSizeBox.Value * 1024); Regex levFilenameMatcher; try { levFilenameMatcher = new Regex(levelPattern, RegexOptions.IgnoreCase); } catch (Exception) { levFilenameMatcher = new Regex(string.Empty); } var searchParams = new ReplaySearchParameters { InternalRec = SearchParameters.GetBoolOptionFromTriSelect(intExtSelect), AcrossLev = SearchParameters.GetBoolOptionFromTriSelect(elmaAcrossSelect), Date = new Range <DateTime>(minDateTime.Value, maxDateTime.Value), Finished = SearchParameters.GetBoolOptionFromTriSelect(finishedSelect), LevExists = BoolOption.Dontcare, WrongLev = BoolOption.Dontcare, LevFilenameMatcher = levFilenameMatcher, MultiPlayer = SearchParameters.GetBoolOptionFromTriSelect(singleMultiSelect), Size = size, Time = time, P1Bounds = new ReplaySearchParameters.PlayerBounds { Apples = p1Apples, GroundTouches = p1Gt, LeftVolts = p1Lv, RightVolts = p1Rv, SuperVolts = p1Sv, Turns = p1Turns }, P2Bounds = new ReplaySearchParameters.PlayerBounds { Apples = p2Apples, GroundTouches = p2Gt, LeftVolts = p2Lv, RightVolts = p2Rv, SuperVolts = p2Sv, Turns = p2Turns } }; if (searchOnlyMissingLev) { searchParams.ResetOptions(); searchParams.LevExists = BoolOption.False; } if (searchOnlyWrongLev) { searchParams.ResetOptions(); searchParams.WrongLev = BoolOption.True; } var allFiles = Directory.GetFiles(Global.AppSettings.General.ReplayDirectory, "*.rec", Global.AppSettings.ReplayManager.RecDirSearchOption); var replayFiles = searchOnlyMissingLev || searchOnlyWrongLev ? allFiles.ToList() : Utils.FilterByRegex(allFiles, SearchPattern).ToList(); ObjectList.ClearObjects(); var oldButtonText = clickedButton.Text; _searchCancelToken = new CancellationTokenSource(); DuplicateButton.Enabled = false; DuplicateFilenameButton.Enabled = false; ConfigButton.Enabled = false; clickedButton.Text = "Stop"; var foundReplays = new List <Replay>(); ToolStripProgressBar1.Maximum = replayFiles.Count; var recsByLevel = new Dictionary <string, List <Replay> >(); var token = _searchCancelToken.Token; var progressHandler = new Progress <(int progress, int levels, int recs, int phase)>(value => { var(progressValue, levels, recs, phase) = value; ToolStripProgressBar1.Value = progressValue; if (searchForAllReplays) { statusLabel.Text = $"Found {recs} replays so far"; } else { statusLabel.Text = phase == 1 ? $"Phase 1: {levels} levels" : $"Phase 2: {recs} replays"; } }); var progress = (IProgress <(int progress, int levels, int recs, int phase)>)progressHandler; var iter = 0; try { await Task.Run(() => { foreach (var replayFile in replayFiles) { iter++; Replay srp; try { srp = new Replay(replayFile); } catch (ArgumentException) { errorFiles.Add(replayFile); continue; } if (searchParams.Matches(srp)) { if (!searchForAllReplays) { var key = srp.LevelFilename.ToLower() + srp.IsMulti; recsByLevel.TryGetValue(key, out var recs); if (recs == null) { recs = new List <Replay>(); recsByLevel[key] = recs; } recs.Add(srp); } else { foundReplays.Add(srp); } } if (iter % 10 == 0) { progress.Report((iter, recsByLevel.Count, foundReplays.Count, 1)); } token.ThrowIfCancellationRequested(); } }, token); } catch (OperationCanceledException) { Finalize(); return; } if (!searchForAllReplays) { ToolStripProgressBar1.Maximum = recsByLevel.Count; iter = 0; try { await Task.Run(() => { foreach (var rbl in recsByLevel) { iter++; var matchedReplay = rbl.Value[0]; foreach (var z in rbl.Value.Where(z => !z.WrongLevelVersion)) { if (searchForFastestReplays) { if (!matchedReplay.Finished && z.Finished) { matchedReplay = z; } else if (matchedReplay.Finished && z.Finished && z.Time < matchedReplay.Time) { matchedReplay = z; } else if (!matchedReplay.Finished && !z.Finished && z.Player1.Apples > matchedReplay.Player1.Apples) { matchedReplay = z; } } else { if (matchedReplay.Finished && !z.Finished) { matchedReplay = z; } else if (matchedReplay.Finished && z.Finished && z.Time > matchedReplay.Time) { matchedReplay = z; } else if (!matchedReplay.Finished && !z.Finished && (z.Player1.Apples < matchedReplay.Player1.Apples || matchedReplay.Time > z.Time)) { matchedReplay = z; } } } if (searchForFastestReplays || rbl.Value.Count > 1) { foundReplays.Add(matchedReplay); } if (iter % 10 == 0) { progress.Report((iter, recsByLevel.Count, foundReplays.Count, 2)); } token.ThrowIfCancellationRequested(); } }, token); } catch (OperationCanceledException) { } } Finalize(); void Finalize() { ObjectList.SetObjects(foundReplays); statusLabel.Text = "Ready"; ToolStripProgressBar1.Value = 0; _searchCancelToken = null; DuplicateButton.Enabled = true; DuplicateFilenameButton.Enabled = true; ConfigButton.Enabled = true; clickedButton.Text = oldButtonText; DisplaySelectionInfo(); if (errorFiles.Count > 0) { using (var ef = new ErrorForm(errorFiles)) { ef.ShowDialog(); } } } }
private async void searchButton_Click(object sender, EventArgs e) { if (_searchCancelToken != null) { _searchCancelToken.Cancel(); _searchCancelToken = null; return; } if (!Utils.LevDirectoryExists()) { Utils.ShowError(Constants.LevDirNotFound); return; } var res = GetRegexes(); if (!res.HasValue) { Utils.ShowError("Some of the search parameters have invalid syntax (regex)."); return; } var allFiles = Directory.GetFiles(Global.AppSettings.General.LevelDirectory, "*.lev", Global.AppSettings.LevelManager.LevDirSearchOption); var recFiles = Directory.GetFiles(Global.AppSettings.General.ReplayDirectory, "*.rec", Global.AppSettings.LevelManager.RecDirSearchOption); var levFiles = Utils.FilterByRegex(allFiles, SearchPattern).ToList(); searchProgressBar.Maximum = recFiles.Length; var progressHandler = new Progress <(int progress, string statusText)>(value => { var(progressValue, status) = value; searchProgressBar.Value = progressValue; statusLabel.Text = status; }); var progress = (IProgress <(int progress, string statusText)>)progressHandler; var errorFiles = new List <string>(); _recsByLevel = new Dictionary <string, List <Replay> >(); _searchCancelToken = new CancellationTokenSource(); var token = _searchCancelToken.Token; var foundLevs = new List <Level>(); var clickedButton = (Button)sender; var oldButtonText = clickedButton.Text; clickedButton.Text = "Stop"; try { await Task.Run(() => { var iter = 0; foreach (var f in recFiles) { iter++; var r = new Replay(f); var key = r.LevelFilename.ToLower() + r.LevId; _recsByLevel.TryGetValue(key, out var list); if (list == null) { list = new List <Replay>(); _recsByLevel[key] = list; } list.Add(r); if (iter % 10 == 0) { progress.Report((iter, $"Processing replay files first: {iter} of {recFiles.Length}")); } token.ThrowIfCancellationRequested(); } }, token); } catch (OperationCanceledException) { Finalize(); return; } searchProgressBar.Maximum = levFiles.Count; var(titleRe, lgrRe, gtRe, stRe, spnRe, mpnRe) = res.Value; var searchParams = new LevelSearchParameters { AcrossLev = SearchParameters.GetBoolOptionFromTriSelect(elmaAcrossSelect), Date = new Range <DateTime>(minDateTime.Value, maxDateTime.Value), Size = new Range <int>((int)minFileSizeBox.Value * 1024, (int)maxFileSizeBox.Value * 1024), Title = titleRe, Lgr = lgrRe, GroundTexture = gtRe, SkyTexture = stRe, SinglePlayerNick = spnRe, MultiPlayerNick = mpnRe, SinglePlayerBestTime = Utils.GetTimeRange(minSingleBestTimeBox.Text, maxSingleBestTimeBox.Text), MultiPlayerBestTime = Utils.GetTimeRange(minMultiBestTimeBox.Text, maxMultiBestTimeBox.Text), GroundPolygons = Range <int> .FromNumericBoxes(minGroundPolygonsBox, maxGroundPolygonsBox), GroundVertices = Range <int> .FromNumericBoxes(minGroundVerticesBox, maxGroundVerticesBox), GrassPolygons = Range <int> .FromNumericBoxes(minGrassPolygonsBox, maxGrassPolygonsBox), GrassVertices = Range <int> .FromNumericBoxes(minGrassVerticesBox, maxGrassVerticesBox), SingleTop10Times = Range <int> .FromNumericBoxes(minSingleplayerTimesBox, maxSingleplayerTimesBox), MultiTop10Times = Range <int> .FromNumericBoxes(minMultiplayerTimesBox, maxMultiplayerTimesBox), Killers = Range <int> .FromNumericBoxes(minKillersBox, maxKillersBox), Flowers = Range <int> .FromNumericBoxes(minFlowersBox, maxFlowersBox), Pictures = Range <int> .FromNumericBoxes(minPicturesBox, maxPicturesBox), Textures = Range <int> .FromNumericBoxes(minTexturesBox, maxTexturesBox), Apples = Range <int> .FromNumericBoxes(minApplesBox, maxApplesBox), GravApples = new Dictionary <AppleType, Range <int> > { { AppleType.Normal, Range <int> .FromNumericBoxes(minNormApplesBox, maxNormApplesBox) }, { AppleType.GravityUp, Range <int> .FromNumericBoxes(minGravUpApplesBox, maxGravUpApplesBox) }, { AppleType.GravityDown, Range <int> .FromNumericBoxes(minGravDownApplesBox, maxGravDownApplesBox) }, { AppleType.GravityLeft, Range <int> .FromNumericBoxes(minGravLeftApplesBox, maxGravLeftApplesBox) }, { AppleType.GravityRight, Range <int> .FromNumericBoxes(minGravRightApplesBox, maxGravRightApplesBox) } } }; try { await Task.Run(() => { var iter = 0; foreach (var levFile in levFiles) { iter++; Level srp; try { srp = Level.FromPath(levFile); } catch (ArgumentException) { errorFiles.Add(levFile); continue; } if (searchParams.Matches(srp)) { foundLevs.Add(srp); } if (iter % 10 == 0) { progress.Report((iter, $"Found {foundLevs.Count} levels so far")); } token.ThrowIfCancellationRequested(); } }, token); } catch (OperationCanceledException) { } Finalize(); void Finalize() { foreach (var lev in foundLevs) { var key = lev.FileName.ToLower() + lev.Identifier; _recsByLevel.TryGetValue(key, out var recs); if (recs != null) { lev.Replays = recs.Count; } } ObjectList.SetObjects(foundLevs); statusLabel.Text = "Ready"; searchProgressBar.Value = 0; _searchCancelToken = null; configButton.Enabled = true; clickedButton.Text = oldButtonText; DisplaySelectionInfo(); if (errorFiles.Count > 0) { using (var ef = new ErrorForm(errorFiles)) { ef.ShowDialog(); } } } }