1
0
mirror of https://github.com/ppy/osu.git synced 2025-02-13 15:53:51 +08:00

Merge branch 'master' into beatmap-cancellation-token

This commit is contained in:
Bartłomiej Dach 2021-11-17 21:52:30 +01:00
commit 8b134914cf
No known key found for this signature in database
GPG Key ID: BCECCD4FA41F6497
35 changed files with 388 additions and 86 deletions

View File

@ -183,6 +183,19 @@ namespace osu.Desktop.Updater
} }
}); });
} }
public override void Close()
{
// cancelling updates is not currently supported by the underlying updater.
// only allow dismissing for now.
switch (State)
{
case ProgressNotificationState.Cancelled:
base.Close();
break;
}
}
} }
private class SquirrelLogger : Splat.ILogger, IDisposable private class SquirrelLogger : Splat.ILogger, IDisposable

View File

@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Catch.Tests
var controlPointInfo = new ControlPointInfo(); var controlPointInfo = new ControlPointInfo();
controlPointInfo.Add(0, new TimingControlPoint()); controlPointInfo.Add(0, new TimingControlPoint());
WorkingBeatmap beatmap = CreateWorkingBeatmap(new Beatmap IWorkingBeatmap beatmap = CreateWorkingBeatmap(new Beatmap
{ {
HitObjects = new List<HitObject> { new Fruit() }, HitObjects = new List<HitObject> { new Fruit() },
BeatmapInfo = new BeatmapInfo BeatmapInfo = new BeatmapInfo

View File

@ -1,12 +1,35 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using Newtonsoft.Json;
using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Difficulty;
namespace osu.Game.Rulesets.Catch.Difficulty namespace osu.Game.Rulesets.Catch.Difficulty
{ {
public class CatchDifficultyAttributes : DifficultyAttributes public class CatchDifficultyAttributes : DifficultyAttributes
{ {
[JsonProperty("approach_rate")]
public double ApproachRate { get; set; } public double ApproachRate { get; set; }
public override IEnumerable<(int attributeId, object value)> ToDatabaseAttributes()
{
foreach (var v in base.ToDatabaseAttributes())
yield return v;
// Todo: osu!catch should not output star rating in the 'aim' attribute.
yield return (ATTRIB_ID_AIM, StarRating);
yield return (ATTRIB_ID_APPROACH_RATE, ApproachRate);
yield return (ATTRIB_ID_MAX_COMBO, MaxCombo);
}
public override void FromDatabaseAttributes(IReadOnlyDictionary<int, double> values)
{
base.FromDatabaseAttributes(values);
StarRating = values[ATTRIB_ID_AIM];
ApproachRate = values[ATTRIB_ID_APPROACH_RATE];
MaxCombo = (int)values[ATTRIB_ID_MAX_COMBO];
}
} }
} }

View File

@ -1,13 +1,38 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using Newtonsoft.Json;
using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Difficulty;
namespace osu.Game.Rulesets.Mania.Difficulty namespace osu.Game.Rulesets.Mania.Difficulty
{ {
public class ManiaDifficultyAttributes : DifficultyAttributes public class ManiaDifficultyAttributes : DifficultyAttributes
{ {
[JsonProperty("great_hit_window")]
public double GreatHitWindow { get; set; } public double GreatHitWindow { get; set; }
[JsonProperty("score_multiplier")]
public double ScoreMultiplier { get; set; } public double ScoreMultiplier { get; set; }
public override IEnumerable<(int attributeId, object value)> ToDatabaseAttributes()
{
foreach (var v in base.ToDatabaseAttributes())
yield return v;
// Todo: osu!mania doesn't output MaxCombo attribute for some reason.
yield return (ATTRIB_ID_STRAIN, StarRating);
yield return (ATTRIB_ID_GREAT_HIT_WINDOW, GreatHitWindow);
yield return (ATTRIB_ID_SCORE_MULTIPLIER, ScoreMultiplier);
}
public override void FromDatabaseAttributes(IReadOnlyDictionary<int, double> values)
{
base.FromDatabaseAttributes(values);
StarRating = values[ATTRIB_ID_STRAIN];
GreatHitWindow = values[ATTRIB_ID_GREAT_HIT_WINDOW];
ScoreMultiplier = values[ATTRIB_ID_SCORE_MULTIPLIER];
}
} }
} }

View File

@ -1,21 +1,77 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using Newtonsoft.Json;
using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Osu.Difficulty namespace osu.Game.Rulesets.Osu.Difficulty
{ {
public class OsuDifficultyAttributes : DifficultyAttributes public class OsuDifficultyAttributes : DifficultyAttributes
{ {
[JsonProperty("aim_strain")]
public double AimStrain { get; set; } public double AimStrain { get; set; }
[JsonProperty("speed_strain")]
public double SpeedStrain { get; set; } public double SpeedStrain { get; set; }
[JsonProperty("flashlight_rating")]
public double FlashlightRating { get; set; } public double FlashlightRating { get; set; }
[JsonProperty("slider_factor")]
public double SliderFactor { get; set; } public double SliderFactor { get; set; }
[JsonProperty("approach_rate")]
public double ApproachRate { get; set; } public double ApproachRate { get; set; }
[JsonProperty("overall_difficulty")]
public double OverallDifficulty { get; set; } public double OverallDifficulty { get; set; }
public double DrainRate { get; set; } public double DrainRate { get; set; }
public int HitCircleCount { get; set; } public int HitCircleCount { get; set; }
public int SliderCount { get; set; } public int SliderCount { get; set; }
public int SpinnerCount { get; set; } public int SpinnerCount { get; set; }
public override IEnumerable<(int attributeId, object value)> ToDatabaseAttributes()
{
foreach (var v in base.ToDatabaseAttributes())
yield return v;
yield return (ATTRIB_ID_AIM, AimStrain);
yield return (ATTRIB_ID_SPEED, SpeedStrain);
yield return (ATTRIB_ID_OVERALL_DIFFICULTY, OverallDifficulty);
yield return (ATTRIB_ID_APPROACH_RATE, ApproachRate);
yield return (ATTRIB_ID_MAX_COMBO, MaxCombo);
yield return (ATTRIB_ID_STRAIN, StarRating);
if (ShouldSerializeFlashlightRating())
yield return (ATTRIB_ID_FLASHLIGHT, FlashlightRating);
yield return (ATTRIB_ID_SLIDER_FACTOR, SliderFactor);
}
public override void FromDatabaseAttributes(IReadOnlyDictionary<int, double> values)
{
base.FromDatabaseAttributes(values);
AimStrain = values[ATTRIB_ID_AIM];
SpeedStrain = values[ATTRIB_ID_SPEED];
OverallDifficulty = values[ATTRIB_ID_OVERALL_DIFFICULTY];
ApproachRate = values[ATTRIB_ID_APPROACH_RATE];
MaxCombo = (int)values[ATTRIB_ID_MAX_COMBO];
StarRating = values[ATTRIB_ID_STRAIN];
FlashlightRating = values.GetValueOrDefault(ATTRIB_ID_FLASHLIGHT);
SliderFactor = values[ATTRIB_ID_SLIDER_FACTOR];
}
// Used implicitly by Newtonsoft.Json to not serialize flashlight property in some cases.
[UsedImplicitly]
public bool ShouldSerializeFlashlightRating() => Mods.Any(m => m is ModFlashlight);
} }
} }

View File

@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
var controlPointInfo = new ControlPointInfo(); var controlPointInfo = new ControlPointInfo();
controlPointInfo.Add(0, new TimingControlPoint()); controlPointInfo.Add(0, new TimingControlPoint());
WorkingBeatmap beatmap = CreateWorkingBeatmap(new Beatmap IWorkingBeatmap beatmap = CreateWorkingBeatmap(new Beatmap
{ {
HitObjects = new List<HitObject> { new Hit { Type = HitType.Centre } }, HitObjects = new List<HitObject> { new Hit { Type = HitType.Centre } },
BeatmapInfo = new BeatmapInfo BeatmapInfo = new BeatmapInfo

View File

@ -1,16 +1,46 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using Newtonsoft.Json;
using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Difficulty;
namespace osu.Game.Rulesets.Taiko.Difficulty namespace osu.Game.Rulesets.Taiko.Difficulty
{ {
public class TaikoDifficultyAttributes : DifficultyAttributes public class TaikoDifficultyAttributes : DifficultyAttributes
{ {
[JsonProperty("stamina_strain")]
public double StaminaStrain { get; set; } public double StaminaStrain { get; set; }
[JsonProperty("rhythm_strain")]
public double RhythmStrain { get; set; } public double RhythmStrain { get; set; }
[JsonProperty("colour_strain")]
public double ColourStrain { get; set; } public double ColourStrain { get; set; }
[JsonProperty("approach_rate")]
public double ApproachRate { get; set; } public double ApproachRate { get; set; }
[JsonProperty("great_hit_window")]
public double GreatHitWindow { get; set; } public double GreatHitWindow { get; set; }
public override IEnumerable<(int attributeId, object value)> ToDatabaseAttributes()
{
foreach (var v in base.ToDatabaseAttributes())
yield return v;
yield return (ATTRIB_ID_MAX_COMBO, MaxCombo);
yield return (ATTRIB_ID_STRAIN, StarRating);
yield return (ATTRIB_ID_GREAT_HIT_WINDOW, GreatHitWindow);
}
public override void FromDatabaseAttributes(IReadOnlyDictionary<int, double> values)
{
base.FromDatabaseAttributes(values);
MaxCombo = (int)values[ATTRIB_ID_MAX_COMBO];
StarRating = values[ATTRIB_ID_STRAIN];
GreatHitWindow = values[ATTRIB_ID_GREAT_HIT_WINDOW];
}
} }
} }

View File

@ -19,7 +19,7 @@ namespace osu.Game.Tests.Skins
[Resolved] [Resolved]
private BeatmapManager beatmaps { get; set; } private BeatmapManager beatmaps { get; set; }
private WorkingBeatmap beatmap; private IWorkingBeatmap beatmap;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()

View File

@ -81,11 +81,11 @@ namespace osu.Game.Tests.Visual.Editing
public class EditorBeatmapContainer : Container public class EditorBeatmapContainer : Container
{ {
private readonly WorkingBeatmap working; private readonly IWorkingBeatmap working;
public EditorBeatmap EditorBeatmap { get; private set; } public EditorBeatmap EditorBeatmap { get; private set; }
public EditorBeatmapContainer(WorkingBeatmap working) public EditorBeatmapContainer(IWorkingBeatmap working)
{ {
this.working = working; this.working = working;

View File

@ -20,7 +20,7 @@ namespace osu.Game.Tests.Visual.Editing
[TestFixture] [TestFixture]
public class TestSceneWaveform : OsuTestScene public class TestSceneWaveform : OsuTestScene
{ {
private WorkingBeatmap waveformBeatmap; private IWorkingBeatmap waveformBeatmap;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(AudioManager audio) private void load(AudioManager audio)

View File

@ -95,8 +95,9 @@ namespace osu.Game.Tests.Visual.Gameplay
private void prepareBeatmap() private void prepareBeatmap()
{ {
Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo); var workingBeatmap = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
Beatmap.Value.BeatmapInfo.EpilepsyWarning = epilepsyWarning; workingBeatmap.BeatmapInfo.EpilepsyWarning = epilepsyWarning;
Beatmap.Value = workingBeatmap;
foreach (var mod in SelectedMods.Value.OfType<IApplicableToTrack>()) foreach (var mod in SelectedMods.Value.OfType<IApplicableToTrack>())
mod.ApplyToTrack(Beatmap.Value.Track); mod.ApplyToTrack(Beatmap.Value.Track);

View File

@ -12,7 +12,7 @@ namespace osu.Game.Tests.Visual.Gameplay
{ {
public class TestScenePlayerReferenceLeaking : TestSceneAllRulesetPlayers public class TestScenePlayerReferenceLeaking : TestSceneAllRulesetPlayers
{ {
private readonly WeakList<WorkingBeatmap> workingWeakReferences = new WeakList<WorkingBeatmap>(); private readonly WeakList<IWorkingBeatmap> workingWeakReferences = new WeakList<IWorkingBeatmap>();
private readonly WeakList<Player> playerWeakReferences = new WeakList<Player>(); private readonly WeakList<Player> playerWeakReferences = new WeakList<Player>();

View File

@ -86,7 +86,7 @@ namespace osu.Game.Tests.Visual.Gameplay
track.Start(); track.Start();
} }
private void loadStoryboard(WorkingBeatmap working) private void loadStoryboard(IWorkingBeatmap working)
{ {
if (storyboard != null) if (storyboard != null)
storyboardContainer.Remove(storyboard); storyboardContainer.Remove(storyboard);

View File

@ -31,7 +31,7 @@ namespace osu.Game.Tests.Visual.Menus
public void TestMusicNavigationActions() public void TestMusicNavigationActions()
{ {
int importId = 0; int importId = 0;
Queue<(WorkingBeatmap working, TrackChangeDirection changeDirection)> trackChangeQueue = null; Queue<(IWorkingBeatmap working, TrackChangeDirection changeDirection)> trackChangeQueue = null;
// ensure we have at least two beatmaps available to identify the direction the music controller navigated to. // ensure we have at least two beatmaps available to identify the direction the music controller navigated to.
AddRepeatStep("import beatmap", () => Game.BeatmapManager.Import(new BeatmapSetInfo AddRepeatStep("import beatmap", () => Game.BeatmapManager.Import(new BeatmapSetInfo
@ -58,7 +58,7 @@ namespace osu.Game.Tests.Visual.Menus
AddStep("bind to track change", () => AddStep("bind to track change", () =>
{ {
trackChangeQueue = new Queue<(WorkingBeatmap, TrackChangeDirection)>(); trackChangeQueue = new Queue<(IWorkingBeatmap, TrackChangeDirection)>();
Game.MusicController.TrackChanged += (working, changeDirection) => trackChangeQueue.Enqueue((working, changeDirection)); Game.MusicController.TrackChanged += (working, changeDirection) => trackChangeQueue.Enqueue((working, changeDirection));
}); });

View File

@ -67,6 +67,19 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddAssert("no item selected", () => playlist.SelectedItem.Value == null); AddAssert("no item selected", () => playlist.SelectedItem.Value == null);
} }
[Test]
public void TestMarkInvalid()
{
createPlaylist(true, true);
AddStep("mark item 0 as invalid", () => playlist.Items[0].MarkInvalid());
moveToItem(0);
AddStep("click", () => InputManager.Click(MouseButton.Left));
AddAssert("no item selected", () => playlist.SelectedItem.Value == null);
}
[Test] [Test]
public void TestSelectable() public void TestSelectable()
{ {

View File

@ -7,6 +7,7 @@ using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Screens; using osu.Framework.Screens;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Extensions;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Mania; using osu.Game.Rulesets.Mania;
using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu;
@ -139,7 +140,7 @@ namespace osu.Game.Tests.Visual.Navigation
AddStep("present beatmap", () => Game.PresentBeatmap(getImport())); AddStep("present beatmap", () => Game.PresentBeatmap(getImport()));
AddUntilStep("wait for song select", () => Game.ScreenStack.CurrentScreen is Screens.Select.SongSelect); AddUntilStep("wait for song select", () => Game.ScreenStack.CurrentScreen is Screens.Select.SongSelect);
AddUntilStep("correct beatmap displayed", () => Game.Beatmap.Value.BeatmapSetInfo.ID == getImport().ID); AddUntilStep("correct beatmap displayed", () => Game.Beatmap.Value.BeatmapSetInfo.MatchesOnlineID(getImport()));
AddAssert("correct ruleset selected", () => Game.Ruleset.Value.ID == getImport().Beatmaps.First().Ruleset.ID); AddAssert("correct ruleset selected", () => Game.Ruleset.Value.ID == getImport().Beatmaps.First().Ruleset.ID);
} }

View File

@ -96,7 +96,7 @@ namespace osu.Game.Tests.Visual.Navigation
Player player = null; Player player = null;
ResultsScreen results = null; ResultsScreen results = null;
WorkingBeatmap beatmap() => Game.Beatmap.Value; IWorkingBeatmap beatmap() => Game.Beatmap.Value;
PushAndConfirm(() => new TestPlaySongSelect()); PushAndConfirm(() => new TestPlaySongSelect());
@ -128,7 +128,7 @@ namespace osu.Game.Tests.Visual.Navigation
{ {
Player player = null; Player player = null;
WorkingBeatmap beatmap() => Game.Beatmap.Value; IWorkingBeatmap beatmap() => Game.Beatmap.Value;
PushAndConfirm(() => new TestPlaySongSelect()); PushAndConfirm(() => new TestPlaySongSelect());

View File

@ -73,7 +73,7 @@ namespace osu.Game.Tests.Visual.Playlists
RoomManager.CreateRequested = r => RoomManager.CreateRequested = r =>
{ {
createdRoom = r; createdRoom = r;
return true; return string.Empty;
}; };
}); });
@ -82,28 +82,58 @@ namespace osu.Game.Tests.Visual.Playlists
AddAssert("has correct duration", () => createdRoom.Duration.Value == expectedDuration); AddAssert("has correct duration", () => createdRoom.Duration.Value == expectedDuration);
} }
[Test]
public void TestInvalidBeatmapError()
{
const string not_found_prefix = "beatmaps not found:";
string errorMesage = null;
AddStep("setup", () =>
{
var beatmap = CreateBeatmap(Ruleset.Value).BeatmapInfo;
SelectedRoom.Value.Name.Value = "Test Room";
SelectedRoom.Value.Playlist.Add(new PlaylistItem { Beatmap = { Value = beatmap } });
errorMesage = $"{not_found_prefix} {beatmap.OnlineID}";
RoomManager.CreateRequested = _ => errorMesage;
});
AddAssert("error not displayed", () => !settings.ErrorText.IsPresent);
AddAssert("playlist item valid", () => SelectedRoom.Value.Playlist[0].Valid.Value);
AddStep("create room", () => settings.ApplyButton.Action.Invoke());
AddAssert("error displayed", () => settings.ErrorText.IsPresent);
AddAssert("error has custom text", () => settings.ErrorText.Text != errorMesage);
AddAssert("playlist item marked invalid", () => !SelectedRoom.Value.Playlist[0].Valid.Value);
}
[Test] [Test]
public void TestCreationFailureDisplaysError() public void TestCreationFailureDisplaysError()
{ {
bool fail; const string error_message = "failed";
string failText = error_message;
AddStep("setup", () => AddStep("setup", () =>
{ {
SelectedRoom.Value.Name.Value = "Test Room"; SelectedRoom.Value.Name.Value = "Test Room";
SelectedRoom.Value.Playlist.Add(new PlaylistItem { Beatmap = { Value = CreateBeatmap(Ruleset.Value).BeatmapInfo } }); SelectedRoom.Value.Playlist.Add(new PlaylistItem { Beatmap = { Value = CreateBeatmap(Ruleset.Value).BeatmapInfo } });
fail = true; RoomManager.CreateRequested = _ => failText;
RoomManager.CreateRequested = _ => !fail;
}); });
AddAssert("error not displayed", () => !settings.ErrorText.IsPresent); AddAssert("error not displayed", () => !settings.ErrorText.IsPresent);
AddStep("create room", () => settings.ApplyButton.Action.Invoke()); AddStep("create room", () => settings.ApplyButton.Action.Invoke());
AddAssert("error displayed", () => settings.ErrorText.IsPresent); AddAssert("error displayed", () => settings.ErrorText.IsPresent);
AddAssert("error has correct text", () => settings.ErrorText.Text == TestRoomManager.FAILED_TEXT); AddAssert("error has correct text", () => settings.ErrorText.Text == error_message);
AddStep("create room no fail", () => AddStep("create room no fail", () =>
{ {
fail = false; failText = string.Empty;
settings.ApplyButton.Action.Invoke(); settings.ApplyButton.Action.Invoke();
}); });
@ -132,9 +162,7 @@ namespace osu.Game.Tests.Visual.Playlists
protected class TestRoomManager : IRoomManager protected class TestRoomManager : IRoomManager
{ {
public const string FAILED_TEXT = "failed"; public Func<Room, string> CreateRequested;
public Func<Room, bool> CreateRequested;
public event Action RoomsUpdated public event Action RoomsUpdated
{ {
@ -157,8 +185,10 @@ namespace osu.Game.Tests.Visual.Playlists
if (CreateRequested == null) if (CreateRequested == null)
return; return;
if (!CreateRequested.Invoke(room)) string error = CreateRequested.Invoke(room);
onError?.Invoke(FAILED_TEXT);
if (!string.IsNullOrEmpty(error))
onError?.Invoke(error);
else else
onSuccess?.Invoke(room); onSuccess?.Invoke(room);
} }

View File

@ -88,7 +88,7 @@ namespace osu.Game.Tests.Visual.SongSelect
}); });
} }
private void showMetadataForBeatmap(Func<WorkingBeatmap> getBeatmap) private void showMetadataForBeatmap(Func<IWorkingBeatmap> getBeatmap)
{ {
AddStep("setup display", () => AddStep("setup display", () =>
{ {

View File

@ -17,6 +17,7 @@ using osu.Framework.Screens;
using osu.Framework.Testing; using osu.Framework.Testing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Extensions;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays; using osu.Game.Overlays;
@ -360,7 +361,7 @@ namespace osu.Game.Tests.Visual.SongSelect
AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmapInfo.Equals(target)); AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmapInfo.Equals(target));
// this is an important check, to make sure updateComponentFromBeatmap() was actually run // this is an important check, to make sure updateComponentFromBeatmap() was actually run
AddUntilStep("selection shown on wedge", () => songSelect.CurrentBeatmapDetailsBeatmap.BeatmapInfo.Equals(target)); AddUntilStep("selection shown on wedge", () => songSelect.CurrentBeatmapDetailsBeatmap.BeatmapInfo.MatchesOnlineID(target));
} }
[Test] [Test]
@ -392,7 +393,7 @@ namespace osu.Game.Tests.Visual.SongSelect
AddUntilStep("has correct ruleset", () => Ruleset.Value.ID == 0); AddUntilStep("has correct ruleset", () => Ruleset.Value.ID == 0);
// this is an important check, to make sure updateComponentFromBeatmap() was actually run // this is an important check, to make sure updateComponentFromBeatmap() was actually run
AddUntilStep("selection shown on wedge", () => songSelect.CurrentBeatmapDetailsBeatmap.BeatmapInfo.Equals(target)); AddUntilStep("selection shown on wedge", () => songSelect.CurrentBeatmapDetailsBeatmap.BeatmapInfo.MatchesOnlineID(target));
} }
[Test] [Test]
@ -507,13 +508,13 @@ namespace osu.Game.Tests.Visual.SongSelect
i.IsFiltered || i.Item.BeatmapInfo.Ruleset.ID == targetRuleset || i.Item.BeatmapInfo.Ruleset.ID == 0); i.IsFiltered || i.Item.BeatmapInfo.Ruleset.ID == targetRuleset || i.Item.BeatmapInfo.Ruleset.ID == 0);
}); });
AddUntilStep("carousel has correct", () => songSelect.Carousel.SelectedBeatmapInfo?.OnlineID == target.OnlineID); AddUntilStep("carousel has correct", () => songSelect.Carousel.SelectedBeatmapInfo?.MatchesOnlineID(target) == true);
AddUntilStep("game has correct", () => Beatmap.Value.BeatmapInfo.OnlineID == target.OnlineID); AddUntilStep("game has correct", () => Beatmap.Value.BeatmapInfo.MatchesOnlineID(target));
AddStep("reset filter text", () => songSelect.FilterControl.ChildrenOfType<SearchTextBox>().First().Text = string.Empty); AddStep("reset filter text", () => songSelect.FilterControl.ChildrenOfType<SearchTextBox>().First().Text = string.Empty);
AddAssert("game still correct", () => Beatmap.Value?.BeatmapInfo.OnlineID == target.OnlineID); AddAssert("game still correct", () => Beatmap.Value?.BeatmapInfo.MatchesOnlineID(target) == true);
AddAssert("carousel still correct", () => songSelect.Carousel.SelectedBeatmapInfo.OnlineID == target.OnlineID); AddAssert("carousel still correct", () => songSelect.Carousel.SelectedBeatmapInfo.MatchesOnlineID(target));
} }
[Test] [Test]
@ -544,8 +545,8 @@ namespace osu.Game.Tests.Visual.SongSelect
AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmapInfo != null); AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmapInfo != null);
AddUntilStep("carousel has correct", () => songSelect.Carousel.SelectedBeatmapInfo?.OnlineID == target.OnlineID); AddUntilStep("carousel has correct", () => songSelect.Carousel.SelectedBeatmapInfo?.MatchesOnlineID(target) == true);
AddUntilStep("game has correct", () => Beatmap.Value.BeatmapInfo.OnlineID == target.OnlineID); AddUntilStep("game has correct", () => Beatmap.Value.BeatmapInfo.MatchesOnlineID(target));
AddStep("set filter text", () => songSelect.FilterControl.ChildrenOfType<SearchTextBox>().First().Text = "nononoo"); AddStep("set filter text", () => songSelect.FilterControl.ChildrenOfType<SearchTextBox>().First().Text = "nononoo");
@ -672,7 +673,7 @@ namespace osu.Game.Tests.Visual.SongSelect
AddUntilStep("wait for selection", () => !Beatmap.IsDefault); AddUntilStep("wait for selection", () => !Beatmap.IsDefault);
AddStep("record set ID", () => previousSetID = Beatmap.Value.BeatmapSetInfo.ID); AddStep("record set ID", () => previousSetID = ((IBeatmapSetInfo)Beatmap.Value.BeatmapSetInfo).OnlineID);
AddAssert("selection changed once", () => changeCount == 1); AddAssert("selection changed once", () => changeCount == 1);
AddAssert("Check ruleset is osu!", () => Ruleset.Value.ID == 0); AddAssert("Check ruleset is osu!", () => Ruleset.Value.ID == 0);
@ -683,8 +684,8 @@ namespace osu.Game.Tests.Visual.SongSelect
AddUntilStep("selection changed", () => changeCount > 1); AddUntilStep("selection changed", () => changeCount > 1);
AddAssert("Selected beatmap still same set", () => Beatmap.Value.BeatmapSetInfo.ID == previousSetID); AddAssert("Selected beatmap still same set", () => Beatmap.Value.BeatmapSetInfo.OnlineID == previousSetID);
AddAssert("Selected beatmap is mania", () => Beatmap.Value.BeatmapInfo.Ruleset.ID == 3); AddAssert("Selected beatmap is mania", () => Beatmap.Value.BeatmapInfo.Ruleset.OnlineID == 3);
AddAssert("selection changed only fired twice", () => changeCount == 2); AddAssert("selection changed only fired twice", () => changeCount == 2);
@ -727,7 +728,7 @@ namespace osu.Game.Tests.Visual.SongSelect
int previousSetID = 0; int previousSetID = 0;
AddStep("record set ID", () => previousSetID = Beatmap.Value.BeatmapSetInfo.ID); AddStep("record set ID", () => previousSetID = ((IBeatmapSetInfo)Beatmap.Value.BeatmapSetInfo).OnlineID);
AddStep("Click on a difficulty", () => AddStep("Click on a difficulty", () =>
{ {
@ -738,8 +739,8 @@ namespace osu.Game.Tests.Visual.SongSelect
AddUntilStep("Check ruleset changed to mania", () => Ruleset.Value.ID == 3); AddUntilStep("Check ruleset changed to mania", () => Ruleset.Value.ID == 3);
AddAssert("Selected beatmap still same set", () => songSelect.Carousel.SelectedBeatmapInfo.BeatmapSet.ID == previousSetID); AddAssert("Selected beatmap still same set", () => songSelect.Carousel.SelectedBeatmapInfo.BeatmapSet.OnlineID == previousSetID);
AddAssert("Selected beatmap is mania", () => Beatmap.Value.BeatmapInfo.Ruleset.ID == 3); AddAssert("Selected beatmap is mania", () => Beatmap.Value.BeatmapInfo.Ruleset.OnlineID == 3);
} }
[Test] [Test]
@ -784,7 +785,7 @@ namespace osu.Game.Tests.Visual.SongSelect
AddUntilStep("Check ruleset changed to mania", () => Ruleset.Value.ID == 3); AddUntilStep("Check ruleset changed to mania", () => Ruleset.Value.ID == 3);
AddAssert("Check first item in group selected", () => Beatmap.Value.BeatmapInfo.Equals(groupIcon.Items.First().BeatmapInfo)); AddAssert("Check first item in group selected", () => Beatmap.Value.BeatmapInfo.MatchesOnlineID(groupIcon.Items.First().BeatmapInfo));
} }
[Test] [Test]
@ -815,7 +816,7 @@ namespace osu.Game.Tests.Visual.SongSelect
AddUntilStep("wait for results screen presented", () => !songSelect.IsCurrentScreen()); AddUntilStep("wait for results screen presented", () => !songSelect.IsCurrentScreen());
AddAssert("check beatmap is correct for score", () => Beatmap.Value.BeatmapInfo.Equals(getPresentBeatmap())); AddAssert("check beatmap is correct for score", () => Beatmap.Value.BeatmapInfo.MatchesOnlineID(getPresentBeatmap()));
AddAssert("check ruleset is correct for score", () => Ruleset.Value.ID == 0); AddAssert("check ruleset is correct for score", () => Ruleset.Value.ID == 0);
} }
@ -847,7 +848,7 @@ namespace osu.Game.Tests.Visual.SongSelect
AddUntilStep("wait for results screen presented", () => !songSelect.IsCurrentScreen()); AddUntilStep("wait for results screen presented", () => !songSelect.IsCurrentScreen());
AddAssert("check beatmap is correct for score", () => Beatmap.Value.BeatmapInfo.Equals(getPresentBeatmap())); AddAssert("check beatmap is correct for score", () => Beatmap.Value.BeatmapInfo.MatchesOnlineID(getPresentBeatmap()));
AddAssert("check ruleset is correct for score", () => Ruleset.Value.ID == 0); AddAssert("check ruleset is correct for score", () => Ruleset.Value.ID == 0);
} }
@ -960,7 +961,7 @@ namespace osu.Game.Tests.Visual.SongSelect
public new FilterControl FilterControl => base.FilterControl; public new FilterControl FilterControl => base.FilterControl;
public WorkingBeatmap CurrentBeatmap => Beatmap.Value; public WorkingBeatmap CurrentBeatmap => Beatmap.Value;
public WorkingBeatmap CurrentBeatmapDetailsBeatmap => BeatmapDetails.Beatmap; public IWorkingBeatmap CurrentBeatmapDetailsBeatmap => BeatmapDetails.Beatmap;
public new BeatmapCarousel Carousel => base.Carousel; public new BeatmapCarousel Carousel => base.Carousel;
public new void PresentScore(ScoreInfo score) => base.PresentScore(score); public new void PresentScore(ScoreInfo score) => base.PresentScore(score);

View File

@ -151,7 +151,7 @@ namespace osu.Game.Beatmaps
}, cancellationToken, TaskCreationOptions.HideScheduler | TaskCreationOptions.RunContinuationsAsynchronously, updateScheduler); }, cancellationToken, TaskCreationOptions.HideScheduler | TaskCreationOptions.RunContinuationsAsynchronously, updateScheduler);
} }
public Task<List<TimedDifficultyAttributes>> GetTimedDifficultyAttributesAsync(WorkingBeatmap beatmap, Ruleset ruleset, Mod[] mods, CancellationToken cancellationToken = default) public Task<List<TimedDifficultyAttributes>> GetTimedDifficultyAttributesAsync(IWorkingBeatmap beatmap, Ruleset ruleset, Mod[] mods, CancellationToken cancellationToken = default)
{ {
return Task.Factory.StartNew(() => ruleset.CreateDifficultyCalculator(beatmap).CalculateTimed(mods, cancellationToken), return Task.Factory.StartNew(() => ruleset.CreateDifficultyCalculator(beatmap).CalculateTimed(mods, cancellationToken),
cancellationToken, cancellationToken,

View File

@ -179,7 +179,7 @@ namespace osu.Game.Beatmaps
/// <summary> /// <summary>
/// A default representation of a WorkingBeatmap to use when no beatmap is available. /// A default representation of a WorkingBeatmap to use when no beatmap is available.
/// </summary> /// </summary>
public WorkingBeatmap DefaultBeatmap => workingBeatmapCache.DefaultBeatmap; public IWorkingBeatmap DefaultBeatmap => workingBeatmapCache.DefaultBeatmap;
/// <summary> /// <summary>
/// Fired when a notification should be presented to the user. /// Fired when a notification should be presented to the user.

View File

@ -9,9 +9,9 @@ namespace osu.Game.Beatmaps.Drawables
{ {
public class BeatmapBackgroundSprite : Sprite public class BeatmapBackgroundSprite : Sprite
{ {
private readonly WorkingBeatmap working; private readonly IWorkingBeatmap working;
public BeatmapBackgroundSprite(WorkingBeatmap working) public BeatmapBackgroundSprite(IWorkingBeatmap working)
{ {
if (working == null) if (working == null)
throw new ArgumentNullException(nameof(working)); throw new ArgumentNullException(nameof(working));

View File

@ -37,7 +37,7 @@ namespace osu.Game.Online.Chat
base.LoadComplete(); base.LoadComplete();
string verb; string verb;
BeatmapInfo beatmapInfo; IBeatmapInfo beatmapInfo;
switch (api.Activity.Value) switch (api.Activity.Value)
{ {
@ -57,7 +57,7 @@ namespace osu.Game.Online.Chat
break; break;
} }
string beatmapString = beatmapInfo.OnlineID.HasValue ? $"[{api.WebsiteRootUrl}/b/{beatmapInfo.OnlineID} {beatmapInfo}]" : beatmapInfo.ToString(); string beatmapString = beatmapInfo.OnlineID > 0 ? $"[{api.WebsiteRootUrl}/b/{beatmapInfo.OnlineID} {beatmapInfo}]" : beatmapInfo.ToString();
channelManager.PostMessage($"is {verb} {beatmapString}", true, target); channelManager.PostMessage($"is {verb} {beatmapString}", true, target);
Expire(); Expire();

View File

@ -30,6 +30,11 @@ namespace osu.Game.Online.Rooms
[JsonProperty("expired")] [JsonProperty("expired")]
public bool Expired { get; set; } public bool Expired { get; set; }
[JsonIgnore]
public IBindable<bool> Valid => valid;
private readonly Bindable<bool> valid = new BindableBool(true);
[JsonIgnore] [JsonIgnore]
public readonly Bindable<IBeatmapInfo> Beatmap = new Bindable<IBeatmapInfo>(); public readonly Bindable<IBeatmapInfo> Beatmap = new Bindable<IBeatmapInfo>();
@ -69,6 +74,8 @@ namespace osu.Game.Online.Rooms
Ruleset.BindValueChanged(ruleset => RulesetID = ruleset.NewValue?.OnlineID ?? 0); Ruleset.BindValueChanged(ruleset => RulesetID = ruleset.NewValue?.OnlineID ?? 0);
} }
public void MarkInvalid() => valid.Value = false;
public void MapObjects(RulesetStore rulesets) public void MapObjects(RulesetStore rulesets)
{ {
Beatmap.Value ??= apiBeatmap; Beatmap.Value ??= apiBeatmap;

View File

@ -1,28 +1,87 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Difficulty.Skills;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Difficulty namespace osu.Game.Rulesets.Difficulty
{ {
/// <summary>
/// Describes the difficulty of a beatmap, as output by a <see cref="DifficultyCalculator"/>.
/// </summary>
[JsonObject(MemberSerialization.OptIn)]
public class DifficultyAttributes public class DifficultyAttributes
{ {
protected const int ATTRIB_ID_AIM = 1;
protected const int ATTRIB_ID_SPEED = 3;
protected const int ATTRIB_ID_OVERALL_DIFFICULTY = 5;
protected const int ATTRIB_ID_APPROACH_RATE = 7;
protected const int ATTRIB_ID_MAX_COMBO = 9;
protected const int ATTRIB_ID_STRAIN = 11;
protected const int ATTRIB_ID_GREAT_HIT_WINDOW = 13;
protected const int ATTRIB_ID_SCORE_MULTIPLIER = 15;
protected const int ATTRIB_ID_FLASHLIGHT = 17;
protected const int ATTRIB_ID_SLIDER_FACTOR = 19;
/// <summary>
/// The mods which were applied to the beatmap.
/// </summary>
public Mod[] Mods { get; set; } public Mod[] Mods { get; set; }
/// <summary>
/// The skills resulting from the difficulty calculation.
/// </summary>
public Skill[] Skills { get; set; } public Skill[] Skills { get; set; }
/// <summary>
/// The combined star rating of all skill.
/// </summary>
[JsonProperty("star_rating", Order = -3)]
public double StarRating { get; set; } public double StarRating { get; set; }
/// <summary>
/// The maximum achievable combo.
/// </summary>
[JsonProperty("max_combo", Order = -2)]
public int MaxCombo { get; set; } public int MaxCombo { get; set; }
/// <summary>
/// Creates new <see cref="DifficultyAttributes"/>.
/// </summary>
public DifficultyAttributes() public DifficultyAttributes()
{ {
} }
/// <summary>
/// Creates new <see cref="DifficultyAttributes"/>.
/// </summary>
/// <param name="mods">The mods which were applied to the beatmap.</param>
/// <param name="skills">The skills resulting from the difficulty calculation.</param>
/// <param name="starRating">The combined star rating of all skills.</param>
public DifficultyAttributes(Mod[] mods, Skill[] skills, double starRating) public DifficultyAttributes(Mod[] mods, Skill[] skills, double starRating)
{ {
Mods = mods; Mods = mods;
Skills = skills; Skills = skills;
StarRating = starRating; StarRating = starRating;
} }
/// <summary>
/// Converts this <see cref="DifficultyAttributes"/> to osu-web compatible database attribute mappings.
/// </summary>
/// <remarks>
/// See: osu_difficulty_attribs table.
/// </remarks>
public virtual IEnumerable<(int attributeId, object value)> ToDatabaseAttributes() => Enumerable.Empty<(int, object)>();
/// <summary>
/// Reads osu-web database attribute mappings into this <see cref="DifficultyAttributes"/> object.
/// </summary>
/// <param name="values">The attribute mappings.</param>
public virtual void FromDatabaseAttributes(IReadOnlyDictionary<int, double> values)
{
}
} }
} }

View File

@ -13,7 +13,6 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
using osu.Framework.Threading;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables; using osu.Game.Beatmaps.Drawables;
using osu.Game.Graphics; using osu.Game.Graphics;
@ -45,6 +44,8 @@ namespace osu.Game.Screens.OnlinePlay
private ExplicitContentBeatmapPill explicitContentPill; private ExplicitContentBeatmapPill explicitContentPill;
private ModDisplay modDisplay; private ModDisplay modDisplay;
private readonly IBindable<bool> valid = new Bindable<bool>();
private readonly Bindable<IBeatmapInfo> beatmap = new Bindable<IBeatmapInfo>(); private readonly Bindable<IBeatmapInfo> beatmap = new Bindable<IBeatmapInfo>();
private readonly Bindable<IRulesetInfo> ruleset = new Bindable<IRulesetInfo>(); private readonly Bindable<IRulesetInfo> ruleset = new Bindable<IRulesetInfo>();
private readonly BindableList<Mod> requiredMods = new BindableList<Mod>(); private readonly BindableList<Mod> requiredMods = new BindableList<Mod>();
@ -66,14 +67,18 @@ namespace osu.Game.Screens.OnlinePlay
this.allowSelection = allowSelection; this.allowSelection = allowSelection;
beatmap.BindTo(item.Beatmap); beatmap.BindTo(item.Beatmap);
valid.BindTo(item.Valid);
ruleset.BindTo(item.Ruleset); ruleset.BindTo(item.Ruleset);
requiredMods.BindTo(item.RequiredMods); requiredMods.BindTo(item.RequiredMods);
ShowDragHandle.Value = allowEdit; ShowDragHandle.Value = allowEdit;
} }
[Resolved]
private OsuColour colours { get; set; }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuColour colours) private void load()
{ {
if (!allowEdit) if (!allowEdit)
HandleColour = HandleColour.Opacity(0); HandleColour = HandleColour.Opacity(0);
@ -85,27 +90,43 @@ namespace osu.Game.Screens.OnlinePlay
{ {
base.LoadComplete(); base.LoadComplete();
SelectedItem.BindValueChanged(selected => maskingContainer.BorderThickness = selected.NewValue == Model ? 5 : 0, true); SelectedItem.BindValueChanged(selected =>
{
bool isCurrent = selected.NewValue == Model;
beatmap.BindValueChanged(_ => scheduleRefresh()); if (!valid.Value)
ruleset.BindValueChanged(_ => scheduleRefresh()); {
// Don't allow selection when not valid.
if (isCurrent)
{
SelectedItem.Value = selected.OldValue;
}
requiredMods.CollectionChanged += (_, __) => scheduleRefresh(); // Don't update border when not valid (the border is displaying this fact).
return;
}
maskingContainer.BorderThickness = isCurrent ? 5 : 0;
}, true);
beatmap.BindValueChanged(_ => Scheduler.AddOnce(refresh));
ruleset.BindValueChanged(_ => Scheduler.AddOnce(refresh));
valid.BindValueChanged(_ => Scheduler.AddOnce(refresh));
requiredMods.CollectionChanged += (_, __) => Scheduler.AddOnce(refresh);
refresh(); refresh();
} }
private ScheduledDelegate scheduledRefresh;
private PanelBackground panelBackground; private PanelBackground panelBackground;
private void scheduleRefresh()
{
scheduledRefresh?.Cancel();
scheduledRefresh = Schedule(refresh);
}
private void refresh() private void refresh()
{ {
if (!valid.Value)
{
maskingContainer.BorderThickness = 5;
maskingContainer.BorderColour = colours.Red;
}
difficultyIconContainer.Child = new DifficultyIcon(Item.Beatmap.Value, ruleset.Value, requiredMods, performBackgroundDifficultyLookup: false) { Size = new Vector2(32) }; difficultyIconContainer.Child = new DifficultyIcon(Item.Beatmap.Value, ruleset.Value, requiredMods, performBackgroundDifficultyLookup: false) { Size = new Vector2(32) };
panelBackground.Beatmap.Value = Item.Beatmap.Value; panelBackground.Beatmap.Value = Item.Beatmap.Value;
@ -278,7 +299,7 @@ namespace osu.Game.Screens.OnlinePlay
protected override bool OnClick(ClickEvent e) protected override bool OnClick(ClickEvent e)
{ {
if (allowSelection) if (allowSelection && valid.Value)
SelectedItem.Value = Model; SelectedItem.Value = Model;
return true; return true;
} }

View File

@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Linq;
using Humanizer; using Humanizer;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
@ -204,7 +205,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
{ {
new Drawable[] new Drawable[]
{ {
playlist = new DrawableRoomPlaylist(true, true) { RelativeSizeAxes = Axes.Both } playlist = new DrawableRoomPlaylist(true, false) { RelativeSizeAxes = Axes.Both }
}, },
new Drawable[] new Drawable[]
{ {
@ -339,9 +340,8 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
Duration.Value = DurationField.Current.Value; Duration.Value = DurationField.Current.Value;
manager?.CreateRoom(room, onSuccess, onError);
loadingLayer.Show(); loadingLayer.Show();
manager?.CreateRoom(room, onSuccess, onError);
} }
private void hideError() => ErrorText.FadeOut(50); private void hideError() => ErrorText.FadeOut(50);
@ -350,9 +350,31 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
private void onError(string text) private void onError(string text)
{ {
ErrorText.Text = text; // see https://github.com/ppy/osu-web/blob/2c97aaeb64fb4ed97c747d8383a35b30f57428c7/app/Models/Multiplayer/PlaylistItem.php#L48.
ErrorText.FadeIn(50); const string not_found_prefix = "beatmaps not found:";
if (text.StartsWith(not_found_prefix, StringComparison.Ordinal))
{
ErrorText.Text = "One or more beatmaps were not available online. Please remove or replace the highlighted items.";
int[] invalidBeatmapIDs = text
.Substring(not_found_prefix.Length + 1)
.Split(", ")
.Select(int.Parse)
.ToArray();
foreach (var item in Playlist)
{
if (invalidBeatmapIDs.Contains(item.BeatmapID))
item.MarkInvalid();
}
}
else
{
ErrorText.Text = text;
}
ErrorText.FadeIn(50);
loadingLayer.Hide(); loadingLayer.Hide();
} }
} }

View File

@ -25,7 +25,7 @@ namespace osu.Game.Screens.Play
/// </summary> /// </summary>
public class BeatmapMetadataDisplay : Container public class BeatmapMetadataDisplay : Container
{ {
private readonly WorkingBeatmap beatmap; private readonly IWorkingBeatmap beatmap;
private readonly Bindable<IReadOnlyList<Mod>> mods; private readonly Bindable<IReadOnlyList<Mod>> mods;
private readonly Drawable logoFacade; private readonly Drawable logoFacade;
private LoadingSpinner loading; private LoadingSpinner loading;
@ -43,7 +43,7 @@ namespace osu.Game.Screens.Play
} }
} }
public BeatmapMetadataDisplay(WorkingBeatmap beatmap, Bindable<IReadOnlyList<Mod>> mods, Drawable logoFacade) public BeatmapMetadataDisplay(IWorkingBeatmap beatmap, Bindable<IReadOnlyList<Mod>> mods, Drawable logoFacade)
{ {
this.beatmap = beatmap; this.beatmap = beatmap;
this.logoFacade = logoFacade; this.logoFacade = logoFacade;

View File

@ -354,7 +354,7 @@ namespace osu.Game.Screens.Play
private Drawable createUnderlayComponents() => private Drawable createUnderlayComponents() =>
DimmableStoryboard = new DimmableStoryboard(Beatmap.Value.Storyboard) { RelativeSizeAxes = Axes.Both }; DimmableStoryboard = new DimmableStoryboard(Beatmap.Value.Storyboard) { RelativeSizeAxes = Axes.Both };
private Drawable createGameplayComponents(WorkingBeatmap working, IBeatmap playableBeatmap) => new ScalingContainer(ScalingMode.Gameplay) private Drawable createGameplayComponents(IWorkingBeatmap working, IBeatmap playableBeatmap) => new ScalingContainer(ScalingMode.Gameplay)
{ {
Children = new Drawable[] Children = new Drawable[]
{ {
@ -372,7 +372,7 @@ namespace osu.Game.Screens.Play
} }
}; };
private Drawable createOverlayComponents(WorkingBeatmap working) private Drawable createOverlayComponents(IWorkingBeatmap working)
{ {
var container = new Container var container = new Container
{ {

View File

@ -15,9 +15,9 @@ namespace osu.Game.Screens.Select
{ {
internal class BeatmapInfoWedgeBackground : CompositeDrawable internal class BeatmapInfoWedgeBackground : CompositeDrawable
{ {
private readonly WorkingBeatmap beatmap; private readonly IWorkingBeatmap beatmap;
public BeatmapInfoWedgeBackground(WorkingBeatmap beatmap) public BeatmapInfoWedgeBackground(IWorkingBeatmap beatmap)
{ {
this.beatmap = beatmap; this.beatmap = beatmap;
} }

View File

@ -14,7 +14,7 @@ namespace osu.Game.Screens.Select.Carousel
{ {
public class SetPanelBackground : BufferedContainer public class SetPanelBackground : BufferedContainer
{ {
public SetPanelBackground(WorkingBeatmap working) public SetPanelBackground(IWorkingBeatmap working)
: base(cachedFrameBuffer: true) : base(cachedFrameBuffer: true)
{ {
RedrawOnScale = false; RedrawOnScale = false;

View File

@ -671,7 +671,7 @@ namespace osu.Game.Screens.Select
music.TrackChanged -= ensureTrackLooping; music.TrackChanged -= ensureTrackLooping;
} }
private void ensureTrackLooping(WorkingBeatmap beatmap, TrackChangeDirection changeDirection) private void ensureTrackLooping(IWorkingBeatmap beatmap, TrackChangeDirection changeDirection)
=> beatmap.PrepareTrackForPreviewLooping(); => beatmap.PrepareTrackForPreviewLooping();
public override bool OnBackButton() public override bool OnBackButton()

View File

@ -89,7 +89,7 @@ namespace osu.Game.Storyboards
} }
} }
public DrawableStoryboard CreateDrawable(WorkingBeatmap working = null) => public DrawableStoryboard CreateDrawable(IWorkingBeatmap working = null) =>
new DrawableStoryboard(this); new DrawableStoryboard(this);
public Drawable CreateSpriteFromResourcePath(string path, TextureStore textureStore) public Drawable CreateSpriteFromResourcePath(string path, TextureStore textureStore)

View File

@ -27,11 +27,11 @@ namespace osu.Game.Users
public abstract class InGame : UserActivity public abstract class InGame : UserActivity
{ {
public BeatmapInfo BeatmapInfo { get; } public IBeatmapInfo BeatmapInfo { get; }
public RulesetInfo Ruleset { get; } public RulesetInfo Ruleset { get; }
protected InGame(BeatmapInfo beatmapInfo, RulesetInfo ruleset) protected InGame(IBeatmapInfo beatmapInfo, RulesetInfo ruleset)
{ {
BeatmapInfo = beatmapInfo; BeatmapInfo = beatmapInfo;
Ruleset = ruleset; Ruleset = ruleset;
@ -42,7 +42,7 @@ namespace osu.Game.Users
public class InMultiplayerGame : InGame public class InMultiplayerGame : InGame
{ {
public InMultiplayerGame(BeatmapInfo beatmapInfo, RulesetInfo ruleset) public InMultiplayerGame(IBeatmapInfo beatmapInfo, RulesetInfo ruleset)
: base(beatmapInfo, ruleset) : base(beatmapInfo, ruleset)
{ {
} }
@ -52,7 +52,7 @@ namespace osu.Game.Users
public class InPlaylistGame : InGame public class InPlaylistGame : InGame
{ {
public InPlaylistGame(BeatmapInfo beatmapInfo, RulesetInfo ruleset) public InPlaylistGame(IBeatmapInfo beatmapInfo, RulesetInfo ruleset)
: base(beatmapInfo, ruleset) : base(beatmapInfo, ruleset)
{ {
} }
@ -60,7 +60,7 @@ namespace osu.Game.Users
public class InSoloGame : InGame public class InSoloGame : InGame
{ {
public InSoloGame(BeatmapInfo beatmapInfo, RulesetInfo ruleset) public InSoloGame(IBeatmapInfo beatmapInfo, RulesetInfo ruleset)
: base(beatmapInfo, ruleset) : base(beatmapInfo, ruleset)
{ {
} }
@ -68,9 +68,9 @@ namespace osu.Game.Users
public class Editing : UserActivity public class Editing : UserActivity
{ {
public BeatmapInfo BeatmapInfo { get; } public IBeatmapInfo BeatmapInfo { get; }
public Editing(BeatmapInfo info) public Editing(IBeatmapInfo info)
{ {
BeatmapInfo = info; BeatmapInfo = info;
} }