Esempio n. 1
0
        public static List <Load> GetOverworldLoads(VideoCapture capture, float scale, float timeStart, float timeEnd,
                                                    LoadType loadTypes,
                                                    Action <LoadRemover.ProgressPhase, float> updateProgress)
        {
            List <Load> loads           = new List <Load>();
            var         binocularFrames = FindBinocularFrames(capture, timeStart, timeEnd);
            List <int>  startingFrames  = new List <int>();
            List <int>  endingFrames    = new List <int>();
            int         lastFrame       = -2;

            foreach (var frame in binocularFrames)
            {
                if (frame > lastFrame + 1)
                {
                    startingFrames.Add(frame);
                    endingFrames.Add(lastFrame);
                }

                lastFrame = frame;
            }

            float fps      = (float)capture.Fps;
            int   progress = 0;

            if (loadTypes.HasFlag(LoadType.Overworld))
            {
                foreach (var f in startingFrames)
                {
                    updateProgress.Invoke(LoadRemover.ProgressPhase.Phase_6_OverworldLoads,
                                          0.5f + ((progress++) / (float)startingFrames.Count) * 0.25f);

                    // 30 fps -> 10 frozen frames
                    // 60 fps -> 20 frozen frames
                    Rect cropRect   = new Rect(0, 0, (int)(capture.FrameWidth * 0.5f), capture.FrameHeight);
                    var  _loadStart = Util.CountFrozenFrames(LoadType.Overworld, capture, f / fps, (int)(fps / 3),
                                                             (int)fps * 25, cropRect);

                    if (!_loadStart.HasValue)
                    {
                        continue;
                    }

                    var loadStart = _loadStart.Value;

                    // Check when the life counter first appears, skip three seconds
                    for (int i = (int)fps * 3; i < fps * 20; i++)
                    {
                        var lifeCount = LifeCounter.GetLifeCount(capture, (f + i) / fps, scale);
                        if (lifeCount >= 0)
                        {
                            loads.Add(new Load(LoadType.Overworld, loadStart.FrameStart, f + i));
                            break;
                        }
                    }
                }
            }

            updateProgress.Invoke(LoadRemover.ProgressPhase.Phase_6_OverworldLoads, 0.66f);

            progress = 0;


            if (loadTypes.HasFlag(LoadType.BackSign))
            {
                foreach (var f in startingFrames)
                {
                    updateProgress.Invoke(LoadRemover.ProgressPhase.Phase_6_OverworldLoads,
                                          0.75f + ((progress++) / (float)startingFrames.Count) * 0.25f);

                    // Check back sign loads
                    var _backSignLoad = Util.CountFrozenFrames(LoadType.BackSign, capture,
                                                               (f / fps) - backSignLoadMaxDuration, (int)fps * 1, (int)fps * backSignLoadMaxDuration);

                    if (!_backSignLoad.HasValue)
                    {
                        continue;
                    }

                    loads.Add(_backSignLoad.Value);
                }
            }

            return(loads);
        }
Esempio n. 2
0
        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);
        }