Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix editor test play not marking hit objects before its start time as judged #26465

Merged
merged 13 commits into from
Jun 28, 2024
Merged
18 changes: 18 additions & 0 deletions osu.Game.Tests/Visual/Editing/TestSceneEditorTestGameplay.cs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,24 @@ public void TestGameplayTestWhenTrackRunning()
AddAssert("sample playback re-enabled", () => !Editor.SamplePlaybackDisabled.Value);
}

[TestCase(2000)] // chosen to be after last object in the map
[TestCase(22000)] // chosen to be in the middle of the last spinner
public void TestGameplayTestAtEndOfBeatmap(int offsetFromEnd)
{
AddStep($"seek to end minus {offsetFromEnd}ms", () => EditorClock.Seek(importedBeatmapSet.MaxLength - offsetFromEnd));
AddStep("click test gameplay button", () =>
{
var button = Editor.ChildrenOfType<TestGameplayButton>().Single();

InputManager.MoveMouseTo(button);
InputManager.Click(MouseButton.Left);
});

AddUntilStep("player pushed", () => Stack.CurrentScreen is EditorPlayer);

AddUntilStep("current screen is editor", () => Stack.CurrentScreen is Editor);
}

[Test]
public void TestCancelGameplayTestWithUnsavedChanges()
{
Expand Down
70 changes: 70 additions & 0 deletions osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
// 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.Overlays;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects;
using osu.Game.Screens.Play;
using osu.Game.Users;

Expand Down Expand Up @@ -43,6 +46,10 @@ protected override GameplayClockContainer CreateGameplayClockContainer(WorkingBe
protected override void LoadComplete()
{
base.LoadComplete();

markPreviousObjectsHit();
markVisibleDrawableObjectsHit();

ScoreProcessor.HasCompleted.BindValueChanged(completed =>
{
if (completed.NewValue)
Expand All @@ -56,6 +63,69 @@ protected override void LoadComplete()
});
}

private void markPreviousObjectsHit()
{
foreach (var hitObject in enumerateHitObjects(DrawableRuleset.Objects, editorState.Time))
{
var judgement = hitObject.Judgement;
var result = new JudgementResult(hitObject, judgement) { Type = judgement.MaxResult };

HealthProcessor.ApplyResult(result);
ScoreProcessor.ApplyResult(result);
}

static IEnumerable<HitObject> enumerateHitObjects(IEnumerable<HitObject> hitObjects, double cutoffTime)
{
foreach (var hitObject in hitObjects)
{
foreach (var nested in enumerateHitObjects(hitObject.NestedHitObjects, cutoffTime))
{
if (nested.GetEndTime() < cutoffTime)
yield return nested;
}

if (hitObject.GetEndTime() < cutoffTime)
yield return hitObject;
}
}
}

private void markVisibleDrawableObjectsHit()
{
if (!DrawableRuleset.Playfield.IsLoaded)
{
Schedule(markVisibleDrawableObjectsHit);
return;
}

foreach (var drawableObjectEntry in enumerateDrawableEntries(
DrawableRuleset.Playfield.AllHitObjects
.Select(ho => ho.Entry)
.Where(e => e != null)
.Cast<HitObjectLifetimeEntry>(), editorState.Time))
{
drawableObjectEntry.Result = new JudgementResult(drawableObjectEntry.HitObject, drawableObjectEntry.HitObject.Judgement)
{
Type = drawableObjectEntry.HitObject.Judgement.MaxResult
};
}

static IEnumerable<HitObjectLifetimeEntry> enumerateDrawableEntries(IEnumerable<HitObjectLifetimeEntry> entries, double cutoffTime)
{
foreach (var entry in entries)
{
foreach (var nested in enumerateDrawableEntries(entry.NestedEntries, cutoffTime))
{
if (nested.HitObject.GetEndTime() < cutoffTime)
yield return nested;
}

if (entry.HitObject.GetEndTime() < cutoffTime)
yield return entry;
}
}
}

protected override void PrepareReplay()
{
// don't record replays.
Expand Down
Loading