Skip to content

Fix score processor no longer applying results when failing in multiplayer match #26751

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

Merged
merged 5 commits into from
Jan 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 31 additions & 9 deletions osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlayer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,18 @@

#nullable disable

using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Rooms;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.OnlinePlay.Multiplayer;
using osu.Game.Screens.Play;

Expand All @@ -19,14 +24,37 @@ public partial class TestSceneMultiplayerPlayer : MultiplayerTestScene
{
private MultiplayerPlayer player;

[SetUpSteps]
public override void SetUpSteps()
[Test]
public void TestGameplay()
{
setup();

AddUntilStep("wait for gameplay start", () => player.LocalUserPlaying.Value);
}

[Test]
public void TestFail()
{
base.SetUpSteps();
setup(() => new[] { new OsuModAutopilot() });

AddUntilStep("wait for gameplay start", () => player.LocalUserPlaying.Value);
AddStep("set health zero", () => player.ChildrenOfType<HealthProcessor>().Single().Health.Value = 0);
AddUntilStep("wait for fail", () => player.ChildrenOfType<HealthProcessor>().Single().HasFailed);
AddAssert("fail animation not shown", () => !player.GameplayState.HasFailed);

// ensure that even after reaching a failed state, score processor keeps accounting for new hit results.
// the testing method used here (autopilot + hold key) is sort-of dodgy, but works enough.
AddAssert("score is zero", () => player.GameplayState.ScoreProcessor.TotalScore.Value == 0);
AddStep("hold key", () => player.ChildrenOfType<OsuInputManager.RulesetKeyBindingContainer>().First().TriggerPressed(OsuAction.LeftButton));
AddUntilStep("score changed", () => player.GameplayState.ScoreProcessor.TotalScore.Value > 0);
}

private void setup(Func<IReadOnlyList<Mod>> mods = null)
{
AddStep("set beatmap", () =>
{
Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
SelectedMods.Value = mods?.Invoke() ?? Array.Empty<Mod>();
});

AddStep("Start track playing", () =>
Expand All @@ -52,11 +80,5 @@ public override void SetUpSteps()
AddUntilStep("gameplay clock is not paused", () => !player.ChildrenOfType<GameplayClockContainer>().Single().IsPaused.Value);
AddAssert("gameplay clock is running", () => player.ChildrenOfType<GameplayClockContainer>().Single().IsRunning);
}

[Test]
public void TestGameplay()
{
AddUntilStep("wait for gameplay start", () => player.LocalUserPlaying.Value);
}
}
}
6 changes: 4 additions & 2 deletions osu.Game/Rulesets/Scoring/ScoreProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,8 @@ public Dictionary<HitResult, int> MaximumStatistics
private readonly List<HitEvent> hitEvents = new List<HitEvent>();
private HitObject? lastHitObject;

public bool ApplyNewJudgementsWhenFailed { get; set; }

public ScoreProcessor(Ruleset ruleset)
{
Ruleset = ruleset;
Expand Down Expand Up @@ -211,7 +213,7 @@ protected sealed override void ApplyResultInternal(JudgementResult result)
result.ComboAtJudgement = Combo.Value;
result.HighestComboAtJudgement = HighestCombo.Value;

if (result.FailedAtJudgement)
if (result.FailedAtJudgement && !ApplyNewJudgementsWhenFailed)
return;

ScoreResultCounts[result.Type] = ScoreResultCounts.GetValueOrDefault(result.Type) + 1;
Expand Down Expand Up @@ -267,7 +269,7 @@ protected sealed override void RevertResultInternal(JudgementResult result)
Combo.Value = result.ComboAtJudgement;
HighestCombo.Value = result.HighestComboAtJudgement;

if (result.FailedAtJudgement)
if (result.FailedAtJudgement && !ApplyNewJudgementsWhenFailed)
return;

ScoreResultCounts[result.Type] = ScoreResultCounts.GetValueOrDefault(result.Type) - 1;
Expand Down
2 changes: 2 additions & 0 deletions osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ private void load()
if (!LoadedBeatmapSuccessfully)
return;

ScoreProcessor.ApplyNewJudgementsWhenFailed = true;

LoadComponentAsync(new GameplayChatDisplay(Room)
{
Expanded = { BindTarget = LeaderboardExpandedState },
Expand Down