diff --git a/osu.Android.props b/osu.Android.props
index ec223f98c2..24d07b4588 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -52,7 +52,7 @@
-
+
diff --git a/osu.Desktop/Windows/GameplayWinKeyBlocker.cs b/osu.Desktop/Windows/GameplayWinKeyBlocker.cs
index efc3f21149..dbfd170ea1 100644
--- a/osu.Desktop/Windows/GameplayWinKeyBlocker.cs
+++ b/osu.Desktop/Windows/GameplayWinKeyBlocker.cs
@@ -5,23 +5,23 @@ using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Platform;
-using osu.Game;
using osu.Game.Configuration;
+using osu.Game.Screens.Play;
namespace osu.Desktop.Windows
{
public class GameplayWinKeyBlocker : Component
{
private Bindable disableWinKey;
- private Bindable localUserPlaying;
+ private IBindable localUserPlaying;
[Resolved]
private GameHost host { get; set; }
[BackgroundDependencyLoader]
- private void load(OsuGame game, OsuConfigManager config)
+ private void load(ILocalUserPlayInfo localUserInfo, OsuConfigManager config)
{
- localUserPlaying = game.LocalUserPlaying.GetBoundCopy();
+ localUserPlaying = localUserInfo.IsPlaying.GetBoundCopy();
localUserPlaying.BindValueChanged(_ => updateBlocking());
disableWinKey = config.GetBindable(OsuSetting.GameplayDisableWinKey);
diff --git a/osu.Game.Rulesets.Catch/Difficulty/Skills/Movement.cs b/osu.Game.Rulesets.Catch/Difficulty/Skills/Movement.cs
index 4372ed938c..cfb3fe40be 100644
--- a/osu.Game.Rulesets.Catch/Difficulty/Skills/Movement.cs
+++ b/osu.Game.Rulesets.Catch/Difficulty/Skills/Movement.cs
@@ -9,7 +9,7 @@ using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Catch.Difficulty.Skills
{
- public class Movement : StrainSkill
+ public class Movement : StrainDecaySkill
{
private const float absolute_player_positioning_error = 16f;
private const float normalized_hitobject_radius = 41.0f;
diff --git a/osu.Game.Rulesets.Mania/Difficulty/Skills/Strain.cs b/osu.Game.Rulesets.Mania/Difficulty/Skills/Strain.cs
index 2ba2ee6b4a..01d930d585 100644
--- a/osu.Game.Rulesets.Mania/Difficulty/Skills/Strain.cs
+++ b/osu.Game.Rulesets.Mania/Difficulty/Skills/Strain.cs
@@ -10,7 +10,7 @@ using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Mania.Difficulty.Skills
{
- public class Strain : StrainSkill
+ public class Strain : StrainDecaySkill
{
private const double individual_decay_base = 0.125;
private const double overall_decay_base = 0.30;
@@ -71,7 +71,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty.Skills
return individualStrain + overallStrain - CurrentStrain;
}
- protected override double GetPeakStrain(double offset)
+ protected override double CalculateInitialStrain(double offset)
=> applyDecay(individualStrain, offset - Previous[0].StartTime, individual_decay_base)
+ applyDecay(overallStrain, offset - Previous[0].StartTime, overall_decay_base);
diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs
index e47edc37cc..7bcd867a9c 100644
--- a/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs
+++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs
@@ -10,7 +10,7 @@ using osu.Framework.Utils;
namespace osu.Game.Rulesets.Osu.Difficulty.Skills
{
- public abstract class OsuStrainSkill : StrainSkill
+ public abstract class OsuStrainSkill : StrainDecaySkill
{
///
/// The number of sections with the highest strains, which the peak strain reductions will apply to.
diff --git a/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditorRuleset.cs b/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditorRuleset.cs
index d4f1602a46..c89527d8bd 100644
--- a/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditorRuleset.cs
+++ b/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditorRuleset.cs
@@ -64,11 +64,14 @@ namespace osu.Game.Rulesets.Osu.Edit
if (hitObject is DrawableHitCircle circle)
{
- circle.ApproachCircle
- .FadeOutFromOne(EDITOR_HIT_OBJECT_FADE_OUT_EXTENSION * 4)
- .Expire();
+ using (circle.BeginAbsoluteSequence(circle.HitStateUpdateTime))
+ {
+ circle.ApproachCircle
+ .FadeOutFromOne(EDITOR_HIT_OBJECT_FADE_OUT_EXTENSION * 4)
+ .Expire();
- circle.ApproachCircle.ScaleTo(1.1f, 300, Easing.OutQuint);
+ circle.ApproachCircle.ScaleTo(1.1f, 300, Easing.OutQuint);
+ }
}
if (hitObject is IHasMainCirclePiece mainPieceContainer)
diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs
index 769d021362..0c17ca66b9 100644
--- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs
+++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs
@@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills
///
/// Calculates the colour coefficient of taiko difficulty.
///
- public class Colour : StrainSkill
+ public class Colour : StrainDecaySkill
{
protected override double SkillMultiplier => 1;
protected override double StrainDecayBase => 0.4;
diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Rhythm.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Rhythm.cs
index a32f6ebe0d..973e55f4b4 100644
--- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Rhythm.cs
+++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Rhythm.cs
@@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills
///
/// Calculates the rhythm coefficient of taiko difficulty.
///
- public class Rhythm : StrainSkill
+ public class Rhythm : StrainDecaySkill
{
protected override double SkillMultiplier => 10;
protected override double StrainDecayBase => 0;
diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs
index 4cceadb23f..54cf233d69 100644
--- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs
+++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs
@@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills
///
/// The reference play style chosen uses two hands, with full alternating (the hand changes after every hit).
///
- public class Stamina : StrainSkill
+ public class Stamina : StrainDecaySkill
{
protected override double SkillMultiplier => 1;
protected override double StrainDecayBase => 0.4;
diff --git a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs
index 8124bd4199..bab8dfc983 100644
--- a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs
+++ b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs
@@ -50,10 +50,10 @@ namespace osu.Game.Tests.Skins.IO
var imported2 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOsk("test skin", "skinner"), "skin2.osk"));
Assert.That(imported2.ID, Is.Not.EqualTo(imported.ID));
- Assert.That(osu.Dependencies.Get().GetAllUserSkins().Count, Is.EqualTo(1));
+ Assert.That(osu.Dependencies.Get().GetAllUserSkins(true).Count, Is.EqualTo(1));
// the first should be overwritten by the second import.
- Assert.That(osu.Dependencies.Get().GetAllUserSkins().First().Files.First().FileInfoID, Is.EqualTo(imported2.Files.First().FileInfoID));
+ Assert.That(osu.Dependencies.Get().GetAllUserSkins(true).First().Files.First().FileInfoID, Is.EqualTo(imported2.Files.First().FileInfoID));
}
finally
{
@@ -76,10 +76,10 @@ namespace osu.Game.Tests.Skins.IO
var imported2 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOsk(string.Empty, string.Empty), "download.osk"));
Assert.That(imported2.ID, Is.Not.EqualTo(imported.ID));
- Assert.That(osu.Dependencies.Get().GetAllUserSkins().Count, Is.EqualTo(2));
+ Assert.That(osu.Dependencies.Get().GetAllUserSkins(true).Count, Is.EqualTo(2));
- Assert.That(osu.Dependencies.Get().GetAllUserSkins().First().Files.First().FileInfoID, Is.EqualTo(imported.Files.First().FileInfoID));
- Assert.That(osu.Dependencies.Get().GetAllUserSkins().Last().Files.First().FileInfoID, Is.EqualTo(imported2.Files.First().FileInfoID));
+ Assert.That(osu.Dependencies.Get().GetAllUserSkins(true).First().Files.First().FileInfoID, Is.EqualTo(imported.Files.First().FileInfoID));
+ Assert.That(osu.Dependencies.Get().GetAllUserSkins(true).Last().Files.First().FileInfoID, Is.EqualTo(imported2.Files.First().FileInfoID));
}
finally
{
@@ -101,10 +101,10 @@ namespace osu.Game.Tests.Skins.IO
var imported2 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOsk("test skin v2.1", "skinner"), "skin2.osk"));
Assert.That(imported2.ID, Is.Not.EqualTo(imported.ID));
- Assert.That(osu.Dependencies.Get().GetAllUserSkins().Count, Is.EqualTo(2));
+ Assert.That(osu.Dependencies.Get().GetAllUserSkins(true).Count, Is.EqualTo(2));
- Assert.That(osu.Dependencies.Get().GetAllUserSkins().First().Files.First().FileInfoID, Is.EqualTo(imported.Files.First().FileInfoID));
- Assert.That(osu.Dependencies.Get().GetAllUserSkins().Last().Files.First().FileInfoID, Is.EqualTo(imported2.Files.First().FileInfoID));
+ Assert.That(osu.Dependencies.Get().GetAllUserSkins(true).First().Files.First().FileInfoID, Is.EqualTo(imported.Files.First().FileInfoID));
+ Assert.That(osu.Dependencies.Get().GetAllUserSkins(true).Last().Files.First().FileInfoID, Is.EqualTo(imported2.Files.First().FileInfoID));
}
finally
{
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs
index 3017428039..290ba3317b 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs
@@ -19,6 +19,8 @@ namespace osu.Game.Tests.Visual.Gameplay
{
public class TestSceneHUDOverlay : OsuManualInputManagerTestScene
{
+ private OsuConfigManager localConfig;
+
private HUDOverlay hudOverlay;
[Cached]
@@ -31,8 +33,14 @@ namespace osu.Game.Tests.Visual.Gameplay
private Drawable hideTarget => hudOverlay.KeyCounter;
private FillFlowContainer keyCounterFlow => hudOverlay.KeyCounter.ChildrenOfType>().First();
- [Resolved]
- private OsuConfigManager config { get; set; }
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ Dependencies.Cache(localConfig = new OsuConfigManager(LocalStorage));
+ }
+
+ [SetUp]
+ public void SetUp() => Schedule(() => localConfig.SetValue(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Always));
[Test]
public void TestComboCounterIncrementing()
@@ -85,11 +93,7 @@ namespace osu.Game.Tests.Visual.Gameplay
{
createNew();
- HUDVisibilityMode originalConfigValue = HUDVisibilityMode.HideDuringGameplay;
-
- AddStep("get original config value", () => originalConfigValue = config.Get(OsuSetting.HUDVisibilityMode));
-
- AddStep("set hud to never show", () => config.SetValue(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Never));
+ AddStep("set hud to never show", () => localConfig.SetValue(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Never));
AddUntilStep("wait for fade", () => !hideTarget.IsPresent);
@@ -98,37 +102,28 @@ namespace osu.Game.Tests.Visual.Gameplay
AddStep("stop trigering", () => InputManager.ReleaseKey(Key.ControlLeft));
AddUntilStep("wait for fade", () => !hideTarget.IsPresent);
-
- AddStep("set original config value", () => config.SetValue(OsuSetting.HUDVisibilityMode, originalConfigValue));
}
[Test]
public void TestExternalHideDoesntAffectConfig()
{
- HUDVisibilityMode originalConfigValue = HUDVisibilityMode.HideDuringGameplay;
-
createNew();
- AddStep("get original config value", () => originalConfigValue = config.Get(OsuSetting.HUDVisibilityMode));
-
AddStep("set showhud false", () => hudOverlay.ShowHud.Value = false);
- AddAssert("config unchanged", () => originalConfigValue == config.Get(OsuSetting.HUDVisibilityMode));
+ AddAssert("config unchanged", () => localConfig.GetBindable(OsuSetting.HUDVisibilityMode).IsDefault);
AddStep("set showhud true", () => hudOverlay.ShowHud.Value = true);
- AddAssert("config unchanged", () => originalConfigValue == config.Get(OsuSetting.HUDVisibilityMode));
+ AddAssert("config unchanged", () => localConfig.GetBindable(OsuSetting.HUDVisibilityMode).IsDefault);
}
[Test]
public void TestChangeHUDVisibilityOnHiddenKeyCounter()
{
- bool keyCounterVisibleValue = false;
-
createNew();
- AddStep("save keycounter visible value", () => keyCounterVisibleValue = config.Get(OsuSetting.KeyOverlay));
- AddStep("set keycounter visible false", () =>
+ AddStep("hide key overlay", () =>
{
- config.SetValue(OsuSetting.KeyOverlay, false);
+ localConfig.SetValue(OsuSetting.KeyOverlay, false);
hudOverlay.KeyCounter.AlwaysVisible.Value = false;
});
@@ -139,24 +134,16 @@ namespace osu.Game.Tests.Visual.Gameplay
AddStep("set showhud true", () => hudOverlay.ShowHud.Value = true);
AddUntilStep("hidetarget is visible", () => hideTarget.IsPresent);
AddAssert("key counters still hidden", () => !keyCounterFlow.IsPresent);
-
- AddStep("return value", () => config.SetValue(OsuSetting.KeyOverlay, keyCounterVisibleValue));
}
[Test]
public void TestHiddenHUDDoesntBlockSkinnableComponentsLoad()
{
- HUDVisibilityMode originalConfigValue = default;
-
- AddStep("get original config value", () => originalConfigValue = config.Get(OsuSetting.HUDVisibilityMode));
-
- AddStep("set hud to never show", () => config.SetValue(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Never));
+ AddStep("set hud to never show", () => localConfig.SetValue(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Never));
createNew();
AddUntilStep("wait for hud load", () => hudOverlay.IsLoaded);
AddUntilStep("skinnable components loaded", () => hudOverlay.ChildrenOfType().Single().ComponentsLoaded);
-
- AddStep("set original config value", () => config.SetValue(OsuSetting.HUDVisibilityMode, originalConfigValue));
}
private void createNew(Action action = null)
@@ -175,5 +162,11 @@ namespace osu.Game.Tests.Visual.Gameplay
Child = hudOverlay;
});
}
+
+ protected override void Dispose(bool isDisposing)
+ {
+ localConfig?.Dispose();
+ base.Dispose(isDisposing);
+ }
}
}
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs
index 65b1d6d53a..18e4a6c575 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs
@@ -6,13 +6,17 @@ using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
+using osu.Game.Configuration;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus;
using osu.Game.Rulesets.UI;
using osu.Game.Screens.OnlinePlay.Multiplayer.Spectate;
using osu.Game.Screens.Play;
+using osu.Game.Screens.Play.HUD;
+using osu.Game.Screens.Play.PlayerSettings;
using osu.Game.Tests.Beatmaps.IO;
using osu.Game.Users;
@@ -23,6 +27,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
[Resolved]
private OsuGameBase game { get; set; }
+ [Resolved]
+ private OsuConfigManager config { get; set; }
+
[Resolved]
private BeatmapManager beatmapManager { get; set; }
@@ -80,6 +87,32 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddWaitStep("wait a bit", 20);
}
+ [Test]
+ public void TestSpectatorPlayerInteractiveElementsHidden()
+ {
+ HUDVisibilityMode originalConfigValue = default;
+
+ AddStep("get original config hud visibility", () => originalConfigValue = config.Get(OsuSetting.HUDVisibilityMode));
+ AddStep("set config hud visibility to always", () => config.SetValue(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Always));
+
+ start(new[] { PLAYER_1_ID, PLAYER_2_ID });
+ loadSpectateScreen(false);
+
+ AddUntilStep("wait for player loaders", () => this.ChildrenOfType().Count() == 2);
+ AddAssert("all player loader settings hidden", () => this.ChildrenOfType().All(l => !l.ChildrenOfType>().Any()));
+
+ AddUntilStep("wait for players to load", () => spectatorScreen.AllPlayersLoaded);
+
+ // components wrapped in skinnable target containers load asynchronously, potentially taking more than one frame to load.
+ // therefore use until step rather than direct assert to account for that.
+ AddUntilStep("all interactive elements removed", () => this.ChildrenOfType().All(p =>
+ !p.ChildrenOfType().Any() &&
+ !p.ChildrenOfType().Any() &&
+ p.ChildrenOfType().SingleOrDefault()?.ShowHandle == false));
+
+ AddStep("restore config hud visibility", () => config.SetValue(OsuSetting.HUDVisibilityMode, originalConfigValue));
+ }
+
[Test]
public void TestTeamDisplay()
{
diff --git a/osu.Game/Database/MutableDatabaseBackedStore.cs b/osu.Game/Database/MutableDatabaseBackedStore.cs
index c9d0c4bc41..b0feb7bb78 100644
--- a/osu.Game/Database/MutableDatabaseBackedStore.cs
+++ b/osu.Game/Database/MutableDatabaseBackedStore.cs
@@ -36,6 +36,11 @@ namespace osu.Game.Database
///
public IQueryable ConsumableItems => AddIncludesForConsumption(ContextFactory.Get().Set());
+ ///
+ /// Access barebones items with no includes.
+ ///
+ public IQueryable Items => ContextFactory.Get().Set();
+
///
/// Add a to the database.
///
diff --git a/osu.Game/Input/ConfineMouseTracker.cs b/osu.Game/Input/ConfineMouseTracker.cs
index 75d9c8debb..d2bf953dbc 100644
--- a/osu.Game/Input/ConfineMouseTracker.cs
+++ b/osu.Game/Input/ConfineMouseTracker.cs
@@ -7,6 +7,7 @@ using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Input;
using osu.Game.Configuration;
+using osu.Game.Screens.Play;
namespace osu.Game.Input
{
@@ -24,14 +25,14 @@ namespace osu.Game.Input
private IBindable localUserPlaying;
[BackgroundDependencyLoader]
- private void load(OsuGame game, FrameworkConfigManager frameworkConfigManager, OsuConfigManager osuConfigManager)
+ private void load(ILocalUserPlayInfo localUserInfo, FrameworkConfigManager frameworkConfigManager, OsuConfigManager osuConfigManager)
{
frameworkConfineMode = frameworkConfigManager.GetBindable(FrameworkSetting.ConfineMouseMode);
frameworkWindowMode = frameworkConfigManager.GetBindable(FrameworkSetting.WindowMode);
frameworkWindowMode.BindValueChanged(_ => updateConfineMode());
osuConfineMode = osuConfigManager.GetBindable(OsuSetting.ConfineMouseMode);
- localUserPlaying = game.LocalUserPlaying.GetBoundCopy();
+ localUserPlaying = localUserInfo.IsPlaying.GetBoundCopy();
osuConfineMode.ValueChanged += _ => updateConfineMode();
localUserPlaying.BindValueChanged(_ => updateConfineMode(), true);
diff --git a/osu.Game/Online/PollingComponent.cs b/osu.Game/Online/PollingComponent.cs
index 806c0047e7..243be8da44 100644
--- a/osu.Game/Online/PollingComponent.cs
+++ b/osu.Game/Online/PollingComponent.cs
@@ -47,39 +47,13 @@ namespace osu.Game.Online
pollIfNecessary();
}
- private bool pollIfNecessary()
+ ///
+ /// Immediately performs a .
+ ///
+ public void PollImmediately()
{
- // we must be loaded so we have access to clock.
- if (!IsLoaded) return false;
-
- // there's already a poll process running.
- if (pollingActive) return false;
-
- // don't try polling if the time between polls hasn't been set.
- if (TimeBetweenPolls.Value == 0) return false;
-
- if (!lastTimePolled.HasValue)
- {
- doPoll();
- return true;
- }
-
- if (Time.Current - lastTimePolled.Value > TimeBetweenPolls.Value)
- {
- doPoll();
- return true;
- }
-
- // not enough time has passed since the last poll. we do want to schedule a poll to happen, though.
+ lastTimePolled = Time.Current - TimeBetweenPolls.Value;
scheduleNextPoll();
- return false;
- }
-
- private void doPoll()
- {
- scheduledPoll = null;
- pollingActive = true;
- Poll().ContinueWith(_ => pollComplete());
}
///
@@ -90,13 +64,11 @@ namespace osu.Game.Online
return Task.CompletedTask;
}
- ///
- /// Immediately performs a .
- ///
- public void PollImmediately()
+ private void doPoll()
{
- lastTimePolled = Time.Current - TimeBetweenPolls.Value;
- scheduleNextPoll();
+ scheduledPoll = null;
+ pollingActive = true;
+ Poll().ContinueWith(_ => pollComplete());
}
///
@@ -111,6 +83,33 @@ namespace osu.Game.Online
pollIfNecessary();
}
+ private void pollIfNecessary()
+ {
+ // we must be loaded so we have access to clock.
+ if (!IsLoaded) return;
+
+ // there's already a poll process running.
+ if (pollingActive) return;
+
+ // don't try polling if the time between polls hasn't been set.
+ if (TimeBetweenPolls.Value == 0) return;
+
+ if (!lastTimePolled.HasValue)
+ {
+ doPoll();
+ return;
+ }
+
+ if (Time.Current - lastTimePolled.Value > TimeBetweenPolls.Value)
+ {
+ doPoll();
+ return;
+ }
+
+ // not enough time has passed since the last poll. we do want to schedule a poll to happen, though.
+ scheduleNextPoll();
+ }
+
private void scheduleNextPoll()
{
scheduledPoll?.Cancel();
diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs
index fb682e0909..0db63df69b 100644
--- a/osu.Game/OsuGame.cs
+++ b/osu.Game/OsuGame.cs
@@ -62,7 +62,7 @@ namespace osu.Game
/// The full osu! experience. Builds on top of to add menus and binding logic
/// for initial components that are generally retrieved via DI.
///
- public class OsuGame : OsuGameBase, IKeyBindingHandler
+ public class OsuGame : OsuGameBase, IKeyBindingHandler, ILocalUserPlayInfo
{
///
/// The amount of global offset to apply when a left/right anchored overlay is displayed (ie. settings or notifications).
@@ -1085,5 +1085,7 @@ namespace osu.Game
if (newScreen == null)
Exit();
}
+
+ IBindable ILocalUserPlayInfo.IsPlaying => LocalUserPlaying;
}
}
diff --git a/osu.Game/Performance/HighPerformanceSession.cs b/osu.Game/Performance/HighPerformanceSession.cs
index 661c1046f1..3ef0e0bf93 100644
--- a/osu.Game/Performance/HighPerformanceSession.cs
+++ b/osu.Game/Performance/HighPerformanceSession.cs
@@ -4,6 +4,7 @@
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
+using osu.Game.Screens.Play;
namespace osu.Game.Performance
{
@@ -12,9 +13,9 @@ namespace osu.Game.Performance
private readonly IBindable localUserPlaying = new Bindable();
[BackgroundDependencyLoader]
- private void load(OsuGame game)
+ private void load(ILocalUserPlayInfo localUserInfo)
{
- localUserPlaying.BindTo(game.LocalUserPlaying);
+ localUserPlaying.BindTo(localUserInfo.IsPlaying);
}
protected override void LoadComplete()
diff --git a/osu.Game/Rulesets/Difficulty/Skills/StrainDecaySkill.cs b/osu.Game/Rulesets/Difficulty/Skills/StrainDecaySkill.cs
new file mode 100644
index 0000000000..73bab31e82
--- /dev/null
+++ b/osu.Game/Rulesets/Difficulty/Skills/StrainDecaySkill.cs
@@ -0,0 +1,54 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using osu.Game.Rulesets.Difficulty.Preprocessing;
+using osu.Game.Rulesets.Mods;
+
+namespace osu.Game.Rulesets.Difficulty.Skills
+{
+ ///
+ /// Used to processes strain values of s, keep track of strain levels caused by the processed objects
+ /// and to calculate a final difficulty value representing the difficulty of hitting all the processed objects.
+ ///
+ public abstract class StrainDecaySkill : StrainSkill
+ {
+ ///
+ /// Strain values are multiplied by this number for the given skill. Used to balance the value of different skills between each other.
+ ///
+ protected abstract double SkillMultiplier { get; }
+
+ ///
+ /// Determines how quickly strain decays for the given skill.
+ /// For example a value of 0.15 indicates that strain decays to 15% of its original value in one second.
+ ///
+ protected abstract double StrainDecayBase { get; }
+
+ ///
+ /// The current strain level.
+ ///
+ protected double CurrentStrain { get; private set; } = 1;
+
+ protected StrainDecaySkill(Mod[] mods)
+ : base(mods)
+ {
+ }
+
+ protected override double CalculateInitialStrain(double time) => CurrentStrain * strainDecay(time - Previous[0].StartTime);
+
+ protected override double StrainValueAt(DifficultyHitObject current)
+ {
+ CurrentStrain *= strainDecay(current.DeltaTime);
+ CurrentStrain += StrainValueOf(current) * SkillMultiplier;
+
+ return CurrentStrain;
+ }
+
+ ///
+ /// Calculates the strain value of a . This value is affected by previously processed objects.
+ ///
+ protected abstract double StrainValueOf(DifficultyHitObject current);
+
+ private double strainDecay(double ms) => Math.Pow(StrainDecayBase, ms / 1000);
+ }
+}
diff --git a/osu.Game/Rulesets/Difficulty/Skills/StrainSkill.cs b/osu.Game/Rulesets/Difficulty/Skills/StrainSkill.cs
index d4fcefab9b..0880f1b08e 100644
--- a/osu.Game/Rulesets/Difficulty/Skills/StrainSkill.cs
+++ b/osu.Game/Rulesets/Difficulty/Skills/StrainSkill.cs
@@ -15,27 +15,11 @@ namespace osu.Game.Rulesets.Difficulty.Skills
///
public abstract class StrainSkill : Skill
{
- ///
- /// Strain values are multiplied by this number for the given skill. Used to balance the value of different skills between each other.
- ///
- protected abstract double SkillMultiplier { get; }
-
- ///
- /// Determines how quickly strain decays for the given skill.
- /// For example a value of 0.15 indicates that strain decays to 15% of its original value in one second.
- ///
- protected abstract double StrainDecayBase { get; }
-
///
/// The weight by which each strain value decays.
///
protected virtual double DecayWeight => 0.9;
- ///
- /// The current strain level.
- ///
- protected double CurrentStrain { get; private set; } = 1;
-
///
/// The length of each strain section.
///
@@ -52,6 +36,11 @@ namespace osu.Game.Rulesets.Difficulty.Skills
{
}
+ ///
+ /// Returns the strain value at . This value is calculated with or without respect to previous objects.
+ ///
+ protected abstract double StrainValueAt(DifficultyHitObject current);
+
///
/// Process a and update current strain values accordingly.
///
@@ -68,10 +57,7 @@ namespace osu.Game.Rulesets.Difficulty.Skills
currentSectionEnd += SectionLength;
}
- CurrentStrain *= strainDecay(current.DeltaTime);
- CurrentStrain += StrainValueOf(current) * SkillMultiplier;
-
- currentSectionPeak = Math.Max(CurrentStrain, currentSectionPeak);
+ currentSectionPeak = Math.Max(StrainValueAt(current), currentSectionPeak);
}
///
@@ -88,9 +74,9 @@ namespace osu.Game.Rulesets.Difficulty.Skills
/// The beginning of the new section in milliseconds.
private void startNewSectionFrom(double time)
{
- // The maximum strain of the new section is not zero by default, strain decays as usual regardless of section boundaries.
+ // The maximum strain of the new section is not zero by default
// This means we need to capture the strain level at the beginning of the new section, and use that as the initial peak level.
- currentSectionPeak = GetPeakStrain(time);
+ currentSectionPeak = CalculateInitialStrain(time);
}
///
@@ -98,7 +84,7 @@ namespace osu.Game.Rulesets.Difficulty.Skills
///
/// The time to retrieve the peak strain at.
/// The peak strain.
- protected virtual double GetPeakStrain(double time) => CurrentStrain * strainDecay(time - Previous[0].StartTime);
+ protected abstract double CalculateInitialStrain(double time);
///
/// Returns a live enumerable of the peak strains for each section of the beatmap,
@@ -124,12 +110,5 @@ namespace osu.Game.Rulesets.Difficulty.Skills
return difficulty;
}
-
- ///
- /// Calculates the strain value of a . This value is affected by previously processed objects.
- ///
- protected abstract double StrainValueOf(DifficultyHitObject current);
-
- private double strainDecay(double ms) => Math.Pow(StrainDecayBase, ms / 1000);
}
}
diff --git a/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs b/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs
index 186514e868..3978378c3a 100644
--- a/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs
+++ b/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs
@@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Mods
{
// Intercept and extract the internal number bindable from DifficultyBindable.
// This will provide bounds and precision specifications for the slider bar.
- difficultyBindable = ((DifficultyBindable)value).GetBoundCopy();
+ difficultyBindable = (DifficultyBindable)value.GetBoundCopy();
sliderDisplayCurrent.BindTo(difficultyBindable.CurrentNumber);
base.Current = difficultyBindable;
diff --git a/osu.Game/Rulesets/Mods/DifficultyBindable.cs b/osu.Game/Rulesets/Mods/DifficultyBindable.cs
index 664b88eef4..e4304795f2 100644
--- a/osu.Game/Rulesets/Mods/DifficultyBindable.cs
+++ b/osu.Game/Rulesets/Mods/DifficultyBindable.cs
@@ -128,6 +128,6 @@ namespace osu.Game.Rulesets.Mods
ExtendedLimits.UnbindFrom(otherDifficultyBindable.ExtendedLimits);
}
- public new DifficultyBindable GetBoundCopy() => new DifficultyBindable { BindTarget = this };
+ protected override Bindable CreateInstance() => new DifficultyBindable();
}
}
diff --git a/osu.Game/Screens/Edit/BindableBeatDivisor.cs b/osu.Game/Screens/Edit/BindableBeatDivisor.cs
index ff33f0c70d..dfe2992a7c 100644
--- a/osu.Game/Screens/Edit/BindableBeatDivisor.cs
+++ b/osu.Game/Screens/Edit/BindableBeatDivisor.cs
@@ -41,6 +41,8 @@ namespace osu.Game.Screens.Edit
protected override int DefaultMaxValue => VALID_DIVISORS.Last();
protected override int DefaultPrecision => 1;
+ protected override Bindable CreateInstance() => new BindableBeatDivisor();
+
///
/// Retrieves the appropriate colour for a beat divisor.
///
diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs
index 6e57b8e88c..911c9fea51 100644
--- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs
+++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs
@@ -166,14 +166,9 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
}
if (IsSelected)
- {
border.Show();
- colour = colour.Lighten(0.3f);
- }
else
- {
border.Hide();
- }
if (Item is IHasDuration duration && duration.Duration > 0)
circle.Colour = ColourInfo.GradientHorizontal(colour, colour.Lighten(0.4f));
@@ -212,14 +207,9 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
for (int i = 0; i < repeats.RepeatCount; i++)
{
- repeatsContainer.Add(new Circle
+ repeatsContainer.Add(new Tick
{
- Size = new Vector2(circle_size / 3),
- Alpha = 0.2f,
- Anchor = Anchor.CentreLeft,
- Origin = Anchor.Centre,
- RelativePositionAxes = Axes.X,
- X = (float)(i + 1) / (repeats.RepeatCount + 1),
+ X = (float)(i + 1) / (repeats.RepeatCount + 1)
});
}
}
@@ -233,6 +223,17 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
public override Vector2 ScreenSpaceSelectionPoint => ScreenSpaceDrawQuad.TopLeft;
+ private class Tick : Circle
+ {
+ public Tick()
+ {
+ Size = new Vector2(circle_size / 4);
+ Anchor = Anchor.CentreLeft;
+ Origin = Anchor.Centre;
+ RelativePositionAxes = Axes.X;
+ }
+ }
+
public class DragArea : Circle
{
private readonly HitObject hitObject;
@@ -304,20 +305,15 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
private void updateState()
{
- if (hasMouseDown)
- {
- this.ScaleTo(0.7f, 200, Easing.OutQuint);
- }
- else if (IsHovered)
- {
- this.ScaleTo(0.8f, 200, Easing.OutQuint);
- }
- else
- {
- this.ScaleTo(0.6f, 200, Easing.OutQuint);
- }
+ float scale = 0.5f;
- this.FadeTo(IsHovered || hasMouseDown ? 0.8f : 0.2f, 200, Easing.OutQuint);
+ if (hasMouseDown)
+ scale = 0.6f;
+ else if (IsHovered)
+ scale = 0.7f;
+
+ this.ScaleTo(scale, 200, Easing.OutQuint);
+ this.FadeTo(IsHovered || hasMouseDown ? 1f : 0.9f, 200, Easing.OutQuint);
}
[Resolved]
diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs
index 3e8d07d002..8bed3d6049 100644
--- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs
+++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs
@@ -186,16 +186,16 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
searchTextBox.Current.BindValueChanged(_ => updateFilterDebounced());
ruleset.BindValueChanged(_ => UpdateFilter());
- ListingPollingComponent.InitialRoomsReceived.BindValueChanged(_ => updateLoadingLayer());
-
isIdle.BindValueChanged(_ => updatePollingRate(this.IsCurrentScreen()), true);
if (ongoingOperationTracker != null)
{
operationInProgress.BindTo(ongoingOperationTracker.InProgress);
- operationInProgress.BindValueChanged(_ => updateLoadingLayer(), true);
+ operationInProgress.BindValueChanged(_ => updateLoadingLayer());
}
+ ListingPollingComponent.InitialRoomsReceived.BindValueChanged(_ => updateLoadingLayer(), true);
+
updateFilter();
}
diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/RoomSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Match/Components/RoomSettingsOverlay.cs
index 5f0ce0feed..eec512347b 100644
--- a/osu.Game/Screens/OnlinePlay/Match/Components/RoomSettingsOverlay.cs
+++ b/osu.Game/Screens/OnlinePlay/Match/Components/RoomSettingsOverlay.cs
@@ -45,11 +45,13 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components
protected override void PopIn()
{
+ base.PopIn();
Settings.MoveToY(0, TRANSITION_DURATION, Easing.OutQuint);
}
protected override void PopOut()
{
+ base.PopOut();
Settings.MoveToY(-1, TRANSITION_DURATION, Easing.InSine);
}
diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs
index 97fed2040d..d152fc3913 100644
--- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs
+++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs
@@ -25,19 +25,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
[Resolved]
private MultiplayerClient client { get; set; }
- private MultiplayerListingPollingComponent multiplayerListingPollingComponent => (MultiplayerListingPollingComponent)ListingPollingComponent;
-
- private readonly IBindable isConnected = new Bindable();
-
- protected override void LoadComplete()
- {
- base.LoadComplete();
-
- isConnected.BindTo(client.IsConnected);
- isConnected.BindValueChanged(c => Scheduler.AddOnce(() => multiplayerListingPollingComponent.AllowPolling = c.NewValue));
- multiplayerListingPollingComponent.AllowPolling = isConnected.Value;
- }
-
public override void OnResuming(IScreen last)
{
base.OnResuming(last);
@@ -47,7 +34,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
if (last is MultiplayerMatchSubScreen match)
{
RoomManager.RemoveRoom(match.Room);
- multiplayerListingPollingComponent.PollImmediately();
+ ListingPollingComponent.PollImmediately();
}
}
@@ -84,27 +71,29 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
private class MultiplayerListingPollingComponent : ListingPollingComponent
{
- private bool allowPolling;
+ [Resolved]
+ private MultiplayerClient client { get; set; }
- public bool AllowPolling
+ private readonly IBindable isConnected = new Bindable();
+
+ [BackgroundDependencyLoader]
+ private void load()
{
- get => allowPolling;
- set
+ isConnected.BindTo(client.IsConnected);
+ isConnected.BindValueChanged(c => Scheduler.AddOnce(() =>
{
- if (allowPolling == value)
- return;
-
- allowPolling = value;
-
- if (!allowPolling)
- return;
-
- if (IsLoaded)
+ if (isConnected.Value && IsLoaded)
PollImmediately();
- }
+ }), true);
}
- protected override Task Poll() => AllowPolling ? base.Poll() : Task.CompletedTask;
+ protected override Task Poll()
+ {
+ if (!isConnected.Value)
+ return Task.CompletedTask;
+
+ return base.Poll();
+ }
}
}
}
diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs
index 2c157b0564..ececa1e497 100644
--- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs
+++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs
@@ -25,7 +25,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
/// The score containing the player's replay.
/// The clock controlling the gameplay running state.
public MultiSpectatorPlayer([NotNull] Score score, [NotNull] ISpectatorPlayerClock spectatorPlayerClock)
- : base(score)
+ : base(score, new PlayerConfiguration { AllowUserInteraction = false })
{
this.spectatorPlayerClock = spectatorPlayerClock;
}
@@ -34,6 +34,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
private void load()
{
spectatorPlayerClock.WaitingOnFrames.BindTo(waitingOnFrames);
+
+ HUDOverlay.PlayerSettingsOverlay.Expire();
+ HUDOverlay.HoldToQuit.Expire();
}
protected override void UpdateAfterChildren()
diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayerLoader.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayerLoader.cs
index 5a1d28e9c4..14bd8fa6dc 100644
--- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayerLoader.cs
+++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayerLoader.cs
@@ -3,6 +3,7 @@
using System;
using JetBrains.Annotations;
+using osu.Framework.Allocation;
using osu.Game.Scoring;
using osu.Game.Screens.Menu;
using osu.Game.Screens.Play;
@@ -19,6 +20,12 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
{
}
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ PlayerSettings.Expire();
+ }
+
protected override void LogoArriving(OsuLogo logo, bool resuming)
{
}
diff --git a/osu.Game/Screens/Play/ILocalUserPlayInfo.cs b/osu.Game/Screens/Play/ILocalUserPlayInfo.cs
new file mode 100644
index 0000000000..9a2259b12f
--- /dev/null
+++ b/osu.Game/Screens/Play/ILocalUserPlayInfo.cs
@@ -0,0 +1,17 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Framework.Bindables;
+
+namespace osu.Game.Screens.Play
+{
+ [Cached]
+ public interface ILocalUserPlayInfo
+ {
+ ///
+ /// Whether the local user is currently playing.
+ ///
+ IBindable IsPlaying { get; }
+ }
+}
diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs
index 09eaf1c543..5461c6ac6c 100644
--- a/osu.Game/Screens/Play/Player.cs
+++ b/osu.Game/Screens/Play/Player.cs
@@ -38,7 +38,7 @@ namespace osu.Game.Screens.Play
{
[Cached]
[Cached(typeof(ISamplePlaybackDisabler))]
- public abstract class Player : ScreenWithBeatmapBackground, ISamplePlaybackDisabler
+ public abstract class Player : ScreenWithBeatmapBackground, ISamplePlaybackDisabler, ILocalUserPlayInfo
{
///
/// The delay upon completion of the beatmap before displaying the results screen.
@@ -1052,5 +1052,7 @@ namespace osu.Game.Screens.Play
#endregion
IBindable ISamplePlaybackDisabler.SamplePlaybackDisabled => samplePlaybackDisabled;
+
+ IBindable ILocalUserPlayInfo.IsPlaying => LocalUserPlaying;
}
}
diff --git a/osu.Game/Screens/Play/PlayerConfiguration.cs b/osu.Game/Screens/Play/PlayerConfiguration.cs
index 18ee73374f..3aa424e5d5 100644
--- a/osu.Game/Screens/Play/PlayerConfiguration.cs
+++ b/osu.Game/Screens/Play/PlayerConfiguration.cs
@@ -20,6 +20,11 @@ namespace osu.Game.Screens.Play
///
public bool AllowRestart { get; set; } = true;
+ ///
+ /// Whether the player should be able to interact with this player instance.
+ ///
+ public bool AllowUserInteraction { get; set; } = true;
+
///
/// Whether the player should be allowed to skip intros/outros, advancing to the start of gameplay or the end of a storyboard.
///
diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs
index 5f6b4ca2b0..969527a758 100644
--- a/osu.Game/Screens/Play/PlayerLoader.cs
+++ b/osu.Game/Screens/Play/PlayerLoader.cs
@@ -46,9 +46,14 @@ namespace osu.Game.Screens.Play
protected override bool PlayResumeSound => false;
- protected BeatmapMetadataDisplay MetadataInfo;
+ protected BeatmapMetadataDisplay MetadataInfo { get; private set; }
- protected VisualSettings VisualSettings;
+ ///
+ /// A fill flow containing the player settings groups, exposed for the ability to hide it from inheritors of the player loader.
+ ///
+ protected FillFlowContainer PlayerSettings { get; private set; }
+
+ protected VisualSettings VisualSettings { get; private set; }
protected Task LoadTask { get; private set; }
@@ -140,7 +145,7 @@ namespace osu.Game.Screens.Play
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
},
- new FillFlowContainer
+ PlayerSettings = new FillFlowContainer
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
diff --git a/osu.Game/Screens/Play/SongProgress.cs b/osu.Game/Screens/Play/SongProgress.cs
index f28622f42e..b27a9c5f5d 100644
--- a/osu.Game/Screens/Play/SongProgress.cs
+++ b/osu.Game/Screens/Play/SongProgress.cs
@@ -119,7 +119,8 @@ namespace osu.Game.Screens.Play
if (drawableRuleset != null)
{
- AllowSeeking.BindTo(drawableRuleset.HasReplayLoaded);
+ if (player?.Configuration.AllowUserInteraction == true)
+ ((IBindable)AllowSeeking).BindTo(drawableRuleset.HasReplayLoaded);
referenceClock = drawableRuleset.FrameStableClock;
Objects = drawableRuleset.Objects;
diff --git a/osu.Game/Screens/Play/SpectatorPlayer.cs b/osu.Game/Screens/Play/SpectatorPlayer.cs
index f662a479ec..1dae28092a 100644
--- a/osu.Game/Screens/Play/SpectatorPlayer.cs
+++ b/osu.Game/Screens/Play/SpectatorPlayer.cs
@@ -23,7 +23,8 @@ namespace osu.Game.Screens.Play
protected override bool CheckModsAllowFailure() => false; // todo: better support starting mid-way through beatmap
- public SpectatorPlayer(Score score)
+ public SpectatorPlayer(Score score, PlayerConfiguration configuration = null)
+ : base(configuration)
{
this.score = score;
}
diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs
index ea55fd28c2..0f805990b9 100644
--- a/osu.Game/Skinning/SkinManager.cs
+++ b/osu.Game/Skinning/SkinManager.cs
@@ -105,12 +105,18 @@ namespace osu.Game.Skinning
/// Returns a list of all usable s that have been loaded by the user.
///
/// A newly allocated list of available .
- public List GetAllUserSkins() => ModelStore.ConsumableItems.Where(s => !s.DeletePending).ToList();
+ public List GetAllUserSkins(bool includeFiles = false)
+ {
+ if (includeFiles)
+ return ModelStore.ConsumableItems.Where(s => !s.DeletePending).ToList();
+
+ return ModelStore.Items.Where(s => !s.DeletePending).ToList();
+ }
public void SelectRandomSkin()
{
// choose from only user skins, removing the current selection to ensure a new one is chosen.
- var randomChoices = GetAllUsableSkins().Where(s => s.ID != CurrentSkinInfo.Value.ID).ToArray();
+ var randomChoices = ModelStore.Items.Where(s => !s.DeletePending && s.ID != CurrentSkinInfo.Value.ID).ToArray();
if (randomChoices.Length == 0)
{
@@ -118,7 +124,8 @@ namespace osu.Game.Skinning
return;
}
- CurrentSkinInfo.Value = randomChoices.ElementAt(RNG.Next(0, randomChoices.Length));
+ var chosen = randomChoices.ElementAt(RNG.Next(0, randomChoices.Length));
+ CurrentSkinInfo.Value = ModelStore.ConsumableItems.Single(i => i.ID == chosen.ID);
}
protected override SkinInfo CreateModel(ArchiveReader archive) => new SkinInfo { Name = archive.Name };
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index d4dba9330f..928620b32e 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -36,7 +36,7 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
diff --git a/osu.iOS.props b/osu.iOS.props
index 7e514afe74..77f9052e85 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -70,7 +70,7 @@
-
+
@@ -93,7 +93,7 @@
-
+