mirror of
https://github.com/osukey/osukey.git
synced 2025-08-04 07:06:35 +09:00
Merge pull request #15130 from bdach/spectator-convert-failure
Fix score created in player not populating ruleset ID
This commit is contained in:
@ -3,6 +3,7 @@
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Game.Beatmaps;
|
||||
@ -10,10 +11,13 @@ using osu.Game.Online.API;
|
||||
using osu.Game.Online.Rooms;
|
||||
using osu.Game.Online.Solo;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mania;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.Taiko;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens.Ranking;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
|
||||
@ -32,7 +36,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
protected override bool HasCustomSteps => true;
|
||||
|
||||
protected override TestPlayer CreatePlayer(Ruleset ruleset) => new TestPlayer(false);
|
||||
protected override TestPlayer CreatePlayer(Ruleset ruleset) => new NonImportingPlayer(false);
|
||||
|
||||
protected override Ruleset CreatePlayerRuleset() => createCustomRuleset?.Invoke() ?? new OsuRuleset();
|
||||
|
||||
@ -86,6 +90,46 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddAssert("ensure passing submission", () => Player.SubmittedScore?.ScoreInfo.Passed == true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSubmissionForDifferentRuleset()
|
||||
{
|
||||
prepareTokenResponse(true);
|
||||
|
||||
createPlayerTest(createRuleset: () => new TaikoRuleset());
|
||||
|
||||
AddUntilStep("wait for token request", () => Player.TokenCreationRequested);
|
||||
|
||||
AddUntilStep("wait for track to start running", () => Beatmap.Value.Track.IsRunning);
|
||||
|
||||
addFakeHit();
|
||||
|
||||
AddStep("seek to completion", () => Player.GameplayClockContainer.Seek(Player.DrawableRuleset.Objects.Last().GetEndTime()));
|
||||
|
||||
AddUntilStep("results displayed", () => Player.GetChildScreen() is ResultsScreen);
|
||||
AddAssert("ensure passing submission", () => Player.SubmittedScore?.ScoreInfo.Passed == true);
|
||||
AddAssert("submitted score has correct ruleset ID", () => Player.SubmittedScore?.ScoreInfo.RulesetID == new TaikoRuleset().RulesetInfo.ID);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSubmissionForConvertedBeatmap()
|
||||
{
|
||||
prepareTokenResponse(true);
|
||||
|
||||
createPlayerTest(createRuleset: () => new ManiaRuleset(), createBeatmap: _ => createTestBeatmap(new OsuRuleset().RulesetInfo));
|
||||
|
||||
AddUntilStep("wait for token request", () => Player.TokenCreationRequested);
|
||||
|
||||
AddUntilStep("wait for track to start running", () => Beatmap.Value.Track.IsRunning);
|
||||
|
||||
addFakeHit();
|
||||
|
||||
AddStep("seek to completion", () => Player.GameplayClockContainer.Seek(Player.DrawableRuleset.Objects.Last().GetEndTime()));
|
||||
|
||||
AddUntilStep("results displayed", () => Player.GetChildScreen() is ResultsScreen);
|
||||
AddAssert("ensure passing submission", () => Player.SubmittedScore?.ScoreInfo.Passed == true);
|
||||
AddAssert("submitted score has correct ruleset ID", () => Player.SubmittedScore?.ScoreInfo.RulesetID == new ManiaRuleset().RulesetInfo.ID);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNoSubmissionOnExitWithNoToken()
|
||||
{
|
||||
@ -242,5 +286,33 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private class NonImportingPlayer : TestPlayer
|
||||
{
|
||||
public NonImportingPlayer(bool allowPause = true, bool showResults = true, bool pauseOnFocusLost = false)
|
||||
: base(allowPause, showResults, pauseOnFocusLost)
|
||||
{
|
||||
}
|
||||
|
||||
protected override Task ImportScore(Score score)
|
||||
{
|
||||
// It was discovered that Score members could sometimes be half-populated.
|
||||
// In particular, the RulesetID property could be set to 0 even on non-osu! maps.
|
||||
// We want to test that the state of that property is consistent in this test.
|
||||
// EF makes this impossible.
|
||||
//
|
||||
// First off, because of the EF navigational property-explicit foreign key field duality,
|
||||
// it can happen that - for example - the Ruleset navigational property is correctly initialised to mania,
|
||||
// but the RulesetID foreign key property is not initialised and remains 0.
|
||||
// EF silently bypasses this by prioritising the Ruleset navigational property over the RulesetID foreign key one.
|
||||
//
|
||||
// Additionally, adding an entity to an EF DbSet CAUSES SIDE EFFECTS with regard to the foreign key property.
|
||||
// In the above instance, if a ScoreInfo with Ruleset = {mania} and RulesetID = 0 is attached to an EF context,
|
||||
// RulesetID WILL BE SILENTLY SET TO THE CORRECT VALUE of 3.
|
||||
//
|
||||
// For the above reasons, importing is disabled in this test.
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
51
osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorHost.cs
Normal file
51
osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorHost.cs
Normal file
@ -0,0 +1,51 @@
|
||||
// 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 NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.Spectator;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mania;
|
||||
using osu.Game.Tests.Visual.Spectator;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
public class TestSceneSpectatorHost : PlayerTestScene
|
||||
{
|
||||
protected override Ruleset CreatePlayerRuleset() => new ManiaRuleset();
|
||||
|
||||
[Cached(typeof(SpectatorClient))]
|
||||
private TestSpectatorClient spectatorClient { get; } = new TestSpectatorClient();
|
||||
|
||||
private DummyAPIAccess dummyAPIAccess => (DummyAPIAccess)API;
|
||||
private const int dummy_user_id = 42;
|
||||
|
||||
public override void SetUpSteps()
|
||||
{
|
||||
AddStep("set dummy user", () => dummyAPIAccess.LocalUser.Value = new User
|
||||
{
|
||||
Id = dummy_user_id,
|
||||
Username = "DummyUser"
|
||||
});
|
||||
AddStep("add test spectator client", () => Add(spectatorClient));
|
||||
AddStep("add watching user", () => spectatorClient.WatchUser(dummy_user_id));
|
||||
base.SetUpSteps();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestClientSendsCorrectRuleset()
|
||||
{
|
||||
AddUntilStep("spectator client sending frames", () => spectatorClient.PlayingUserStates.ContainsKey(dummy_user_id));
|
||||
AddAssert("spectator client sent correct ruleset", () => spectatorClient.PlayingUserStates[dummy_user_id].RulesetID == Ruleset.Value.ID);
|
||||
}
|
||||
|
||||
public override void TearDownSteps()
|
||||
{
|
||||
base.TearDownSteps();
|
||||
AddStep("stop watching user", () => spectatorClient.StopWatchingUser(dummy_user_id));
|
||||
AddStep("remove test spectator client", () => Remove(spectatorClient));
|
||||
}
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
@ -217,9 +218,12 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
Score = CreateScore(playableBeatmap);
|
||||
|
||||
Debug.Assert(ruleset.RulesetInfo.ID != null);
|
||||
|
||||
// ensure the score is in a consistent state with the current player.
|
||||
Score.ScoreInfo.BeatmapInfo = Beatmap.Value.BeatmapInfo;
|
||||
Score.ScoreInfo.Ruleset = ruleset.RulesetInfo;
|
||||
Score.ScoreInfo.RulesetID = ruleset.RulesetInfo.ID.Value;
|
||||
Score.ScoreInfo.Mods = gameplayMods;
|
||||
|
||||
dependencies.CacheAs(GameplayState = new GameplayState(playableBeatmap, ruleset, gameplayMods, Score));
|
||||
|
Reference in New Issue
Block a user