From b74c3b1c5cbdd1d4bfc2b108bc9bd0a9b7b68e7f Mon Sep 17 00:00:00 2001
From: Nitrous <nathan.alo2000@gmail.com>
Date: Wed, 10 Jan 2024 15:19:38 +0800
Subject: [PATCH] Make all hit objects before the start time marked as hit.

---
 osu.Game/Screens/Edit/Editor.cs               |  2 +-
 .../Screens/Edit/GameplayTest/EditorPlayer.cs | 37 ++++++++++++++++++-
 .../Edit/GameplayTest/EditorPlayerLoader.cs   |  5 ++-
 3 files changed, 40 insertions(+), 4 deletions(-)

diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs
index c1f6c02301..224823de70 100644
--- a/osu.Game/Screens/Edit/Editor.cs
+++ b/osu.Game/Screens/Edit/Editor.cs
@@ -452,7 +452,7 @@ namespace osu.Game.Screens.Edit
                 pushEditorPlayer();
             }
 
-            void pushEditorPlayer() => this.Push(new EditorPlayerLoader(this));
+            void pushEditorPlayer() => this.Push(new EditorPlayerLoader(this, playableBeatmap));
         }
 
         /// <summary>
diff --git a/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs b/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs
index 7dff05667d..47abcff476 100644
--- a/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs
+++ b/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs
@@ -1,11 +1,17 @@
 // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
 // See the LICENCE file in the repository root for full licence text.
 
+using System.Collections.Generic;
 using System.Linq;
 using osu.Framework.Allocation;
 using osu.Framework.Screens;
 using osu.Game.Beatmaps;
+using osu.Game.Online.Spectator;
 using osu.Game.Overlays;
+using osu.Game.Rulesets.Objects;
+using osu.Game.Rulesets.Replays;
+using osu.Game.Rulesets.Scoring;
+using osu.Game.Scoring;
 using osu.Game.Screens.Play;
 using osu.Game.Users;
 
@@ -15,17 +21,19 @@ namespace osu.Game.Screens.Edit.GameplayTest
     {
         private readonly Editor editor;
         private readonly EditorState editorState;
+        private readonly IBeatmap playableBeatmap;
 
         protected override UserActivity InitialActivity => new UserActivity.TestingBeatmap(Beatmap.Value.BeatmapInfo, Ruleset.Value);
 
         [Resolved]
         private MusicController musicController { get; set; } = null!;
 
-        public EditorPlayer(Editor editor)
+        public EditorPlayer(Editor editor, IBeatmap playableBeatmap)
             : base(new PlayerConfiguration { ShowResults = false })
         {
             this.editor = editor;
             editorState = editor.GetState();
+            this.playableBeatmap = playableBeatmap;
         }
 
         protected override GameplayClockContainer CreateGameplayClockContainer(WorkingBeatmap beatmap, double gameplayStart)
@@ -43,6 +51,22 @@ namespace osu.Game.Screens.Edit.GameplayTest
         protected override void LoadComplete()
         {
             base.LoadComplete();
+
+            var frame = new ReplayFrame { Header = new FrameHeader(new ScoreInfo(), new ScoreProcessorStatistics()) };
+
+            foreach (var hitObject in enumerateHitObjects(playableBeatmap.HitObjects.Where(h => h.StartTime < editorState.Time)))
+            {
+                var judgement = hitObject.CreateJudgement();
+
+                if (!frame.Header.Statistics.ContainsKey(judgement.MaxResult))
+                    frame.Header.Statistics.Add(judgement.MaxResult, 0);
+
+                frame.Header.Statistics[judgement.MaxResult]++;
+            }
+
+            HealthProcessor.ResetFromReplayFrame(frame);
+            ScoreProcessor.ResetFromReplayFrame(frame);
+
             ScoreProcessor.HasCompleted.BindValueChanged(completed =>
             {
                 if (completed.NewValue)
@@ -54,6 +78,17 @@ namespace osu.Game.Screens.Edit.GameplayTest
                     }, RESULTS_DISPLAY_DELAY);
                 }
             });
+
+            static IEnumerable<HitObject> enumerateHitObjects(IEnumerable<HitObject> hitObjects)
+            {
+                foreach (var hitObject in hitObjects)
+                {
+                    foreach (var nested in hitObject.NestedHitObjects)
+                        yield return nested;
+
+                    yield return hitObject;
+                }
+            }
         }
 
         protected override void PrepareReplay()
diff --git a/osu.Game/Screens/Edit/GameplayTest/EditorPlayerLoader.cs b/osu.Game/Screens/Edit/GameplayTest/EditorPlayerLoader.cs
index bb151e4a45..c62b8cafb8 100644
--- a/osu.Game/Screens/Edit/GameplayTest/EditorPlayerLoader.cs
+++ b/osu.Game/Screens/Edit/GameplayTest/EditorPlayerLoader.cs
@@ -4,6 +4,7 @@
 using osu.Framework.Allocation;
 using osu.Framework.Graphics;
 using osu.Framework.Screens;
+using osu.Game.Beatmaps;
 using osu.Game.Screens.Menu;
 using osu.Game.Screens.Play;
 
@@ -14,8 +15,8 @@ namespace osu.Game.Screens.Edit.GameplayTest
         [Resolved]
         private OsuLogo osuLogo { get; set; } = null!;
 
-        public EditorPlayerLoader(Editor editor)
-            : base(() => new EditorPlayer(editor))
+        public EditorPlayerLoader(Editor editor, IBeatmap playableBeatmap)
+            : base(() => new EditorPlayer(editor, playableBeatmap))
         {
         }