public static void Init() { AddSample(SoundType.EndSign, Path.Combine(SoundsFolder, "endsign.wav")); AddSample(SoundType.Boss, Path.Combine(SoundsFolder, "bossdefeat.wav")); LifeCounter.Init(); BossLoads.Init(); }
public static LoadResults Start(string file, bool partialRun, CropSettings?crop, TrimSettings?trim, LoadType loadTypes, bool resize, Action <ProgressPhase, float> updateProgress) { List <Load> loads = new List <Load>(); updateProgress.Invoke(ProgressPhase.Phase_1_PreprocessVideo, 0); VideoCapture capture = new VideoCapture(file); string processedFile = CropTrimAndResizeVideo(capture, file, crop, /*trim,*/ resize); capture = VideoCapture.FromFile(processedFile); updateProgress.Invoke(ProgressPhase.Phase_2_StartingTime, 0); int startingFrame = 0; int endingFrame = trim.HasValue ? (int)Math.Min((trim.Value.End * capture.Fps) - 1, capture.FrameCount - 1) : capture.FrameCount - 1; if (!partialRun && loadTypes.HasFlag(LoadType.Start)) { var startLoad = Util.CountDarknessFrames(LoadType.Start, capture, trim?.Start ?? 0, (int)(capture.Fps * StartScreenMaxDuration)); if (startLoad.FrameStart == -1) { throw new Exception( "Start screen not detected, make sure the video starts on the \"Start\"/\"Options\" screen"); } loads.Add(startLoad); startingFrame = startLoad.FrameStart; if (loadTypes.HasFlag(LoadType.Overworld)) { var startOverworldLoad = Util.CountFrozenFrames(LoadType.Overworld, capture, startLoad.FrameEnd / capture.Fps, (int)capture.Fps / 5, (int)capture.Fps * 20); if (startOverworldLoad.HasValue) { loads.Add(startOverworldLoad.Value); } } } updateProgress.Invoke(ProgressPhase.Phase_3_VideoScale, 0); float videoScale = LifeCounter.GetLifeCountScale(capture, startingFrame, updateProgress); if (float.IsNaN(videoScale)) { throw new Exception("Video Scale couldn't be determined: " + videoScale); } updateProgress.Invoke(ProgressPhase.Phase_4_EndingTime, 0); if (!partialRun) { var _endingFrame = BossLoads.GetLastFinalBossFrame(capture, videoScale, endingFrame, updateProgress); if (!_endingFrame.HasValue) { throw new Exception( "Final hit not detected, make sure the video doesn't end more than 3 minutes after the final hit."); } endingFrame = _endingFrame.Value; } updateProgress.Invoke(ProgressPhase.Phase_5_EndSignLoads, 0); if (loadTypes.HasFlag(LoadType.EndSign)) { loads.AddRange(EndSignLoads.GetEndSignLoads(capture, videoScale, startingFrame, endingFrame, updateProgress)); } updateProgress.Invoke(ProgressPhase.Phase_6_OverworldLoads, 0); if (loadTypes.HasFlag(LoadType.Overworld) || loadTypes.HasFlag(LoadType.BackSign)) { loads.AddRange(OverworldLoads.GetOverworldLoads(capture, videoScale, startingFrame / (float)capture.Fps, endingFrame / (float)capture.Fps, loadTypes, updateProgress)); } updateProgress.Invoke(ProgressPhase.Phase_7_DeathLoads, 0); if (loadTypes.HasFlag(LoadType.Death)) { loads.AddRange(DeathLoads.GetDeathLoads(capture, videoScale, startingFrame, endingFrame, updateProgress)); } updateProgress.Invoke(ProgressPhase.Phase_8_BossLoads, 0); if (loadTypes.HasFlag(LoadType.Boss)) { loads.AddRange(BossLoads.GetBossLoads(capture, videoScale, startingFrame, endingFrame, updateProgress)); } int phase8Progress = 0; // Remove backsign loads that aren't preceded by an overworld load (ignore death loads for this) var sortedLoads = loads.OrderBy(l => l.FrameStart).ToList(); List <Load> backsignLoadsToRemove = new List <Load>(); for (int i = 0; i < sortedLoads.Count; i++) { if (sortedLoads[i].Type == LoadType.BackSign) { var bsLoad = sortedLoads[i]; for (int j = i - 1; j >= 0; j--) { var checkLoad = sortedLoads[j]; // only consider loads more than 3 seconds before the backsign load if (checkLoad.FrameStart > bsLoad.FrameStart - capture.Fps * 3.0) { continue; } if (checkLoad.Type == LoadType.Death) { continue; } if (checkLoad.Type == LoadType.Overworld) { break; } else { backsignLoadsToRemove.Add(bsLoad); } } } } foreach (var l in backsignLoadsToRemove) { loads.Remove(l); } // Remove unnecessary endsign loads (when they overlap with other loads) foreach (var load in loads.Where(l => l.Type != LoadType.EndSign).ToList()) { loads.RemoveAll(l => l.Type == LoadType.EndSign && l.Overlaps(load, (int)(capture.Fps * 0.5f))); } // Remove unnecessary backsign loads (when they overlap with other loads) foreach (var load in loads.Where(l => l.Type != LoadType.BackSign).ToList()) { loads.RemoveAll(l => l.Type == LoadType.BackSign && l.Overlaps(load, (int)(capture.Fps * 0.5f))); } // Remove all loads that start after the last frame loads.RemoveAll(l => l.FrameStart > endingFrame); updateProgress.Invoke(ProgressPhase.Phase_9_GenerateReport, 0); LoadResults results = new LoadResults(loads, (float)capture.Fps, startingFrame, endingFrame); results.SaveDebugImages(capture, "debugExport", "file"); var report = new LoadRemoverReport(Path.GetFileName(file), results, capture); var reportPath = Path.ChangeExtension(file, null) + "_report.html"; report.GenerateHtml(TemplateFile).Save(reportPath); updateProgress.Invoke(ProgressPhase.Phase_9_GenerateReport, 1); var openReport = MessageBox.Show($"Done! The report file can be found at {Environment.NewLine}{reportPath}{Environment.NewLine}" + $"Do you wish to open the report now?", "Report", MessageBoxButton.YesNo, MessageBoxImage.Question); if (openReport == MessageBoxResult.Yes) { // Open report in default application (hopefully the browser) var psi = new ProcessStartInfo { FileName = reportPath, UseShellExecute = true }; Process.Start(psi); } return(results); }