diff --git a/osu.Android.props b/osu.Android.props
index 7e17f9da16..b147fdd05b 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -52,6 +52,6 @@
-
+
diff --git a/osu.Game.Rulesets.Catch/UI/Catcher.cs b/osu.Game.Rulesets.Catch/UI/Catcher.cs
index f53e14a8c7..1197d6f9e6 100644
--- a/osu.Game.Rulesets.Catch/UI/Catcher.cs
+++ b/osu.Game.Rulesets.Catch/UI/Catcher.cs
@@ -143,14 +143,14 @@ namespace osu.Game.Rulesets.Catch.UI
var ourRadius = fruit.DisplayRadius;
float theirRadius = 0;
- const float allowance = 6;
+ const float allowance = 10;
while (caughtFruit.Any(f =>
f.LifetimeEnd == double.MaxValue &&
Vector2Extensions.Distance(f.Position, fruit.Position) < (ourRadius + (theirRadius = f.DrawSize.X / 2 * f.Scale.X)) / (allowance / 2)))
{
var diff = (ourRadius + theirRadius) / allowance;
- fruit.X += (RNG.NextSingle() - 0.5f) * 2 * diff;
+ fruit.X += (RNG.NextSingle() - 0.5f) * diff * 2;
fruit.Y -= RNG.NextSingle() * diff;
}
diff --git a/osu.Game.Rulesets.Mania/Replays/ManiaReplayFrame.cs b/osu.Game.Rulesets.Mania/Replays/ManiaReplayFrame.cs
index b93e372027..8c73c36e99 100644
--- a/osu.Game.Rulesets.Mania/Replays/ManiaReplayFrame.cs
+++ b/osu.Game.Rulesets.Mania/Replays/ManiaReplayFrame.cs
@@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
+using System.Linq;
using osu.Game.Beatmaps;
using osu.Game.Replays.Legacy;
using osu.Game.Rulesets.Mania.Beatmaps;
@@ -26,13 +27,7 @@ namespace osu.Game.Rulesets.Mania.Replays
public void FromLegacy(LegacyReplayFrame legacyFrame, IBeatmap beatmap, ReplayFrame lastFrame = null)
{
- // We don't need to fully convert, just create the converter
- var converter = new ManiaBeatmapConverter(beatmap, new ManiaRuleset());
-
- // NB: Via co-op mod, osu-stable can have two stages with floor(col/2) and ceil(col/2) columns. This will need special handling
- // elsewhere in the game if we do choose to support the old co-op mod anyway. For now, assume that there is only one stage.
-
- var stage = new StageDefinition { Columns = converter.TargetColumns };
+ var maniaBeatmap = (ManiaBeatmap)beatmap;
var normalAction = ManiaAction.Key1;
var specialAction = ManiaAction.Special1;
@@ -42,7 +37,7 @@ namespace osu.Game.Rulesets.Mania.Replays
while (activeColumns > 0)
{
- var isSpecial = stage.IsSpecialColumn(counter);
+ var isSpecial = maniaBeatmap.Stages.First().IsSpecialColumn(counter);
if ((activeColumns & 1) > 0)
Actions.Add(isSpecial ? specialAction : normalAction);
@@ -59,17 +54,15 @@ namespace osu.Game.Rulesets.Mania.Replays
public LegacyReplayFrame ToLegacy(IBeatmap beatmap)
{
+ var maniaBeatmap = (ManiaBeatmap)beatmap;
+
int keys = 0;
- var converter = new ManiaBeatmapConverter(beatmap, new ManiaRuleset());
-
- var stage = new StageDefinition { Columns = converter.TargetColumns };
-
var specialColumns = new List();
- for (int i = 0; i < converter.TargetColumns; i++)
+ for (int i = 0; i < maniaBeatmap.TotalColumns; i++)
{
- if (stage.IsSpecialColumn(i))
+ if (maniaBeatmap.Stages.First().IsSpecialColumn(i))
specialColumns.Add(i);
}
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs
index 2d5b9d874c..5c7f4a42b3 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs
@@ -11,6 +11,7 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu.Skinning;
+using osu.Game.Rulesets.Scoring;
using osuTK.Graphics;
using osu.Game.Skinning;
@@ -196,6 +197,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
ApplyResult(r => r.Type = r.Judgement.MaxResult);
}
+ public override void PlaySamples()
+ {
+ // rather than doing it this way, we should probably attach the sample to the tail circle.
+ // this can only be done after we stop using LegacyLastTick.
+ if (TailCircle.Result.Type != HitResult.Miss)
+ base.PlaySamples();
+ }
+
protected override void UpdateStateTransforms(ArmedState state)
{
base.UpdateStateTransforms(state);
diff --git a/osu.Game.Rulesets.Osu/Objects/SliderRepeat.cs b/osu.Game.Rulesets.Osu/Objects/SliderRepeat.cs
index a8fd3764c5..ac6c6905e4 100644
--- a/osu.Game.Rulesets.Osu/Objects/SliderRepeat.cs
+++ b/osu.Game.Rulesets.Osu/Objects/SliderRepeat.cs
@@ -34,8 +34,6 @@ namespace osu.Game.Rulesets.Osu.Objects
public class SliderRepeatJudgement : OsuJudgement
{
- public override bool IsBonus => true;
-
protected override int NumericResultFor(HitResult result) => result == MaxResult ? 30 : 0;
}
}
diff --git a/osu.Game.Rulesets.Osu/Objects/SliderTick.cs b/osu.Game.Rulesets.Osu/Objects/SliderTick.cs
index 212a84c04a..22f3f559db 100644
--- a/osu.Game.Rulesets.Osu/Objects/SliderTick.cs
+++ b/osu.Game.Rulesets.Osu/Objects/SliderTick.cs
@@ -36,8 +36,6 @@ namespace osu.Game.Rulesets.Osu.Objects
public class SliderTickJudgement : OsuJudgement
{
- public override bool IsBonus => true;
-
protected override int NumericResultFor(HitResult result) => result == MaxResult ? 10 : 0;
}
}
diff --git a/osu.Game.Tests/Resources/storyboard_no_video.osu b/osu.Game.Tests/Resources/storyboard_no_video.osu
new file mode 100644
index 0000000000..25f1ff6361
--- /dev/null
+++ b/osu.Game.Tests/Resources/storyboard_no_video.osu
@@ -0,0 +1,31 @@
+osu file format v14
+
+[Events]
+//Background and Video events
+0,0,"BG.jpg",0,0
+Video,0,"video.avi"
+//Break Periods
+//Storyboard Layer 0 (Background)
+//Storyboard Layer 1 (Fail)
+//Storyboard Layer 2 (Pass)
+//Storyboard Layer 3 (Foreground)
+//Storyboard Layer 4 (Overlay)
+//Storyboard Sound Samples
+
+[TimingPoints]
+1674,333.333333333333,4,2,1,70,1,0
+1674,-100,4,2,1,70,0,0
+3340,-100,4,2,1,70,0,0
+3507,-100,4,2,1,70,0,0
+3673,-100,4,2,1,70,0,0
+
+[Colours]
+Combo1 : 240,80,80
+Combo2 : 171,252,203
+Combo3 : 128,128,255
+Combo4 : 249,254,186
+
+[HitObjects]
+148,303,1674,5,6,3:2:0:0:
+378,252,1840,1,0,0:0:0:0:
+389,270,2340,5,2,0:1:0:0:
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs
index afeda5fb7c..5ee17aeea2 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs
@@ -3,8 +3,10 @@
using System.ComponentModel;
using System.Linq;
+using osu.Framework.Testing;
using osu.Game.Rulesets;
using osu.Game.Screens.Play;
+using osu.Game.Screens.Play.Break;
namespace osu.Game.Tests.Visual.Gameplay
{
@@ -23,10 +25,11 @@ namespace osu.Game.Tests.Visual.Gameplay
{
AddUntilStep("score above zero", () => Player.ScoreProcessor.TotalScore.Value > 0);
AddUntilStep("key counter counted keys", () => Player.HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses > 2));
- AddStep("seek to break time", () => Player.GameplayClockContainer.Seek(Player.BreakOverlay.Breaks.First().StartTime));
+ AddStep("seek to break time", () => Player.GameplayClockContainer.Seek(Player.ChildrenOfType().First().Breaks.First().StartTime));
AddUntilStep("wait for seek to complete", () =>
Player.HUDOverlay.Progress.ReferenceClock.CurrentTime >= Player.BreakOverlay.Breaks.First().StartTime);
- AddAssert("test keys not counting", () => !Player.HUDOverlay.KeyCounter.IsCounting);
+ AddAssert("keys not counting", () => !Player.HUDOverlay.KeyCounter.IsCounting);
+ AddAssert("overlay displays 100% accuracy", () => Player.BreakOverlay.ChildrenOfType().Single().AccuracyDisplay.Current.Value == 1);
AddStep("rewind", () => Player.GameplayClockContainer.Seek(-80000));
AddUntilStep("key counter reset", () => Player.HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses == 0));
}
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBreakOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBreakTracker.cs
similarity index 80%
rename from osu.Game.Tests/Visual/Gameplay/TestSceneBreakOverlay.cs
rename to osu.Game.Tests/Visual/Gameplay/TestSceneBreakTracker.cs
index 19dce303ea..ff25e609c1 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneBreakOverlay.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBreakTracker.cs
@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
+using osu.Framework.Graphics;
using osu.Framework.Timing;
using osu.Game.Beatmaps.Timing;
using osu.Game.Screens.Play;
@@ -12,14 +13,16 @@ using osu.Game.Screens.Play;
namespace osu.Game.Tests.Visual.Gameplay
{
[TestFixture]
- public class TestSceneBreakOverlay : OsuTestScene
+ public class TestSceneBreakTracker : OsuTestScene
{
public override IReadOnlyList RequiredTypes => new[]
{
typeof(BreakOverlay),
};
- private readonly TestBreakOverlay breakOverlay;
+ private readonly BreakOverlay breakOverlay;
+
+ private readonly TestBreakTracker breakTracker;
private readonly IReadOnlyList testBreaks = new List
{
@@ -35,9 +38,23 @@ namespace osu.Game.Tests.Visual.Gameplay
},
};
- public TestSceneBreakOverlay()
+ public TestSceneBreakTracker()
{
- Add(breakOverlay = new TestBreakOverlay(true));
+ AddRange(new Drawable[]
+ {
+ breakTracker = new TestBreakTracker(),
+ breakOverlay = new BreakOverlay(true, null)
+ {
+ ProcessCustomClock = false,
+ }
+ });
+ }
+
+ protected override void Update()
+ {
+ base.Update();
+
+ breakOverlay.Clock = breakTracker.Clock;
}
[Test]
@@ -88,7 +105,7 @@ namespace osu.Game.Tests.Visual.Gameplay
loadBreaksStep("multiple breaks", testBreaks);
seekAndAssertBreak("seek to break start", testBreaks[1].StartTime, true);
- AddAssert("is skipped to break #2", () => breakOverlay.CurrentBreakIndex == 1);
+ AddAssert("is skipped to break #2", () => breakTracker.CurrentBreakIndex == 1);
seekAndAssertBreak("seek to break middle", testBreaks[1].StartTime + testBreaks[1].Duration / 2, true);
seekAndAssertBreak("seek to break end", testBreaks[1].EndTime, false);
@@ -110,7 +127,7 @@ namespace osu.Game.Tests.Visual.Gameplay
private void addShowBreakStep(double seconds)
{
- AddStep($"show '{seconds}s' break", () => breakOverlay.Breaks = new List
+ AddStep($"show '{seconds}s' break", () => breakOverlay.Breaks = breakTracker.Breaks = new List
{
new BreakPeriod
{
@@ -122,12 +139,12 @@ namespace osu.Game.Tests.Visual.Gameplay
private void setClock(bool useManual)
{
- AddStep($"set {(useManual ? "manual" : "realtime")} clock", () => breakOverlay.SwitchClock(useManual));
+ AddStep($"set {(useManual ? "manual" : "realtime")} clock", () => breakTracker.SwitchClock(useManual));
}
private void loadBreaksStep(string breakDescription, IReadOnlyList breaks)
{
- AddStep($"load {breakDescription}", () => breakOverlay.Breaks = breaks);
+ AddStep($"load {breakDescription}", () => breakOverlay.Breaks = breakTracker.Breaks = breaks);
seekAndAssertBreak("seek back to 0", 0, false);
}
@@ -151,17 +168,18 @@ namespace osu.Game.Tests.Visual.Gameplay
private void seekAndAssertBreak(string seekStepDescription, double time, bool shouldBeBreak)
{
- AddStep(seekStepDescription, () => breakOverlay.ManualClockTime = time);
+ AddStep(seekStepDescription, () => breakTracker.ManualClockTime = time);
AddAssert($"is{(!shouldBeBreak ? " not" : string.Empty)} break time", () =>
{
- breakOverlay.ProgressTime();
- return breakOverlay.IsBreakTime.Value == shouldBeBreak;
+ breakTracker.ProgressTime();
+ return breakTracker.IsBreakTime.Value == shouldBeBreak;
});
}
- private class TestBreakOverlay : BreakOverlay
+ private class TestBreakTracker : BreakTracker
{
- private readonly FramedClock framedManualClock;
+ public readonly FramedClock FramedManualClock;
+
private readonly ManualClock manualClock;
private IFrameBasedClock originalClock;
@@ -173,20 +191,19 @@ namespace osu.Game.Tests.Visual.Gameplay
set => manualClock.CurrentTime = value;
}
- public TestBreakOverlay(bool letterboxing)
- : base(letterboxing)
+ public TestBreakTracker()
{
- framedManualClock = new FramedClock(manualClock = new ManualClock());
+ FramedManualClock = new FramedClock(manualClock = new ManualClock());
ProcessCustomClock = false;
}
public void ProgressTime()
{
- framedManualClock.ProcessFrame();
+ FramedManualClock.ProcessFrame();
Update();
}
- public void SwitchClock(bool setManual) => Clock = setManual ? framedManualClock : originalClock;
+ public void SwitchClock(bool setManual) => Clock = setManual ? FramedManualClock : originalClock;
protected override void LoadComplete()
{
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboard.cs
index ff8437311e..9f1492a25f 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboard.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboard.cs
@@ -9,8 +9,12 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
+using osu.Game.Beatmaps.Formats;
+using osu.Game.IO;
using osu.Game.Overlays;
+using osu.Game.Storyboards;
using osu.Game.Storyboards.Drawables;
+using osu.Game.Tests.Resources;
using osuTK.Graphics;
namespace osu.Game.Tests.Visual.Gameplay
@@ -54,7 +58,11 @@ namespace osu.Game.Tests.Visual.Gameplay
State = { Value = Visibility.Visible },
}
});
+ }
+ [Test]
+ public void TestStoryboard()
+ {
AddStep("Restart", restart);
AddToggleStep("Passing", passing =>
{
@@ -62,6 +70,12 @@ namespace osu.Game.Tests.Visual.Gameplay
});
}
+ [Test]
+ public void TestStoryboardMissingVideo()
+ {
+ AddStep("Load storyboard with missing video", loadStoryboardNoVideo);
+ }
+
[BackgroundDependencyLoader]
private void load()
{
@@ -94,5 +108,28 @@ namespace osu.Game.Tests.Visual.Gameplay
storyboardContainer.Add(storyboard);
decoupledClock.ChangeSource(working.Track);
}
+
+ private void loadStoryboardNoVideo()
+ {
+ if (storyboard != null)
+ storyboardContainer.Remove(storyboard);
+
+ var decoupledClock = new DecoupleableInterpolatingFramedClock { IsCoupled = true };
+ storyboardContainer.Clock = decoupledClock;
+
+ Storyboard sb;
+
+ using (var str = TestResources.OpenResource("storyboard_no_video.osu"))
+ using (var bfr = new LineBufferedReader(str))
+ {
+ var decoder = new LegacyStoryboardDecoder();
+ sb = decoder.Decode(bfr);
+ }
+
+ storyboard = sb.CreateDrawable(Beatmap.Value);
+
+ storyboardContainer.Add(storyboard);
+ decoupledClock.ChangeSource(Beatmap.Value.Track);
+ }
}
}
diff --git a/osu.Game.Tests/Visual/Menus/TestSceneLoader.cs b/osu.Game.Tests/Visual/Menus/TestSceneLoader.cs
index b3064ba9be..c44363d9ea 100644
--- a/osu.Game.Tests/Visual/Menus/TestSceneLoader.cs
+++ b/osu.Game.Tests/Visual/Menus/TestSceneLoader.cs
@@ -36,8 +36,6 @@ namespace osu.Game.Tests.Visual.Menus
[Test]
public void TestInstantLoad()
{
- // visual only, very impossible to test this using asserts.
-
AddStep("load immediately", () =>
{
loader = new TestLoader();
@@ -46,12 +44,17 @@ namespace osu.Game.Tests.Visual.Menus
LoadScreen(loader);
});
- AddAssert("spinner did not display", () => loader.LoadingSpinner?.Alpha == 0);
+ spinnerNotPresentOrHidden();
AddUntilStep("loaded", () => loader.ScreenLoaded);
AddUntilStep("not current", () => !loader.IsCurrentScreen());
+
+ spinnerNotPresentOrHidden();
}
+ private void spinnerNotPresentOrHidden() =>
+ AddAssert("spinner did not display", () => loader.LoadingSpinner == null || loader.LoadingSpinner.Alpha == 0);
+
[Test]
public void TestDelayedLoad()
{
diff --git a/osu.Game/Graphics/Containers/UserDimContainer.cs b/osu.Game/Graphics/Containers/UserDimContainer.cs
index 4485ce3447..39c1fdad52 100644
--- a/osu.Game/Graphics/Containers/UserDimContainer.cs
+++ b/osu.Game/Graphics/Containers/UserDimContainer.cs
@@ -40,7 +40,7 @@ namespace osu.Game.Graphics.Containers
///
/// Whether player is in break time.
- /// Must be bound to to allow for dim adjustments in gameplay.
+ /// Must be bound to to allow for dim adjustments in gameplay.
///
public readonly IBindable IsBreakTime = new Bindable();
diff --git a/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs
index 59d39a1c3c..e7f2f21465 100644
--- a/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs
+++ b/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs
@@ -1,6 +1,7 @@
// 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;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Configuration;
@@ -56,24 +57,32 @@ namespace osu.Game.Overlays.Settings.Sections.Input
},
};
- rawInputToggle.ValueChanged += enabled =>
+ if (RuntimeInfo.OS != RuntimeInfo.Platform.Windows)
{
- // this is temporary until we support per-handler settings.
- const string raw_mouse_handler = @"OsuTKRawMouseHandler";
- const string standard_mouse_handler = @"OsuTKMouseHandler";
-
- ignoredInputHandler.Value = enabled.NewValue ? standard_mouse_handler : raw_mouse_handler;
- };
-
- ignoredInputHandler = config.GetBindable(FrameworkSetting.IgnoredInputHandlers);
- ignoredInputHandler.ValueChanged += handler =>
+ rawInputToggle.Disabled = true;
+ sensitivity.Bindable.Disabled = true;
+ }
+ else
{
- bool raw = !handler.NewValue.Contains("Raw");
- rawInputToggle.Value = raw;
- sensitivity.Bindable.Disabled = !raw;
- };
+ rawInputToggle.ValueChanged += enabled =>
+ {
+ // this is temporary until we support per-handler settings.
+ const string raw_mouse_handler = @"OsuTKRawMouseHandler";
+ const string standard_mouse_handler = @"OsuTKMouseHandler";
- ignoredInputHandler.TriggerChange();
+ ignoredInputHandler.Value = enabled.NewValue ? standard_mouse_handler : raw_mouse_handler;
+ };
+
+ ignoredInputHandler = config.GetBindable(FrameworkSetting.IgnoredInputHandlers);
+ ignoredInputHandler.ValueChanged += handler =>
+ {
+ bool raw = !handler.NewValue.Contains("Raw");
+ rawInputToggle.Value = raw;
+ sensitivity.Bindable.Disabled = !raw;
+ };
+
+ ignoredInputHandler.TriggerChange();
+ }
}
private class SensitivitySetting : SettingsSlider
diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
index aa29e42fac..5b5802fa9d 100644
--- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
+++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
@@ -344,7 +344,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
/// Plays all the hit sounds for this .
/// This is invoked automatically when this is hit.
///
- public void PlaySamples() => Samples?.Play();
+ public virtual void PlaySamples() => Samples?.Play();
protected override void Update()
{
diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs
index 27993ff173..5062c92afe 100644
--- a/osu.Game/Rulesets/UI/DrawableRuleset.cs
+++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs
@@ -72,9 +72,9 @@ namespace osu.Game.Rulesets.UI
///
public override Playfield Playfield => playfield.Value;
- private Container overlays;
+ public override Container Overlays { get; } = new Container { RelativeSizeAxes = Axes.Both };
- public override Container Overlays => overlays;
+ public override Container FrameStableComponents { get; } = new Container { RelativeSizeAxes = Axes.Both };
public override GameplayClock FrameStableClock => frameStabilityContainer.GameplayClock;
@@ -187,11 +187,12 @@ namespace osu.Game.Rulesets.UI
FrameStablePlayback = FrameStablePlayback,
Children = new Drawable[]
{
+ FrameStableComponents,
KeyBindingInputManager
.WithChild(CreatePlayfieldAdjustmentContainer()
.WithChild(Playfield)
),
- overlays = new Container { RelativeSizeAxes = Axes.Both }
+ Overlays,
}
},
};
@@ -406,10 +407,15 @@ namespace osu.Game.Rulesets.UI
public abstract Playfield Playfield { get; }
///
- /// Place to put drawables above hit objects but below UI.
+ /// Content to be placed above hitobjects. Will be affected by frame stability.
///
public abstract Container Overlays { get; }
+ ///
+ /// Components to be run potentially multiple times in line with frame-stable gameplay.
+ ///
+ public abstract Container FrameStableComponents { get; }
+
///
/// The frame-stable clock which is being used for playfield display.
///
diff --git a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs
index e569bb8459..3ba28aad45 100644
--- a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs
+++ b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs
@@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.UI
{
///
/// A container which consumes a parent gameplay clock and standardises frame counts for children.
- /// Will ensure a minimum of 40 frames per clock second is maintained, regardless of any system lag or seeks.
+ /// Will ensure a minimum of 50 frames per clock second is maintained, regardless of any system lag or seeks.
///
public class FrameStabilityContainer : Container, IHasReplayHandler
{
diff --git a/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs b/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs
index 58b64e1b8f..c356dd246d 100644
--- a/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs
+++ b/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs
@@ -45,9 +45,6 @@ namespace osu.Game.Scoring.Legacy
if (workingBeatmap is DummyWorkingBeatmap)
throw new BeatmapNotFoundException();
- currentBeatmap = workingBeatmap.Beatmap;
- scoreInfo.Beatmap = currentBeatmap.BeatmapInfo;
-
scoreInfo.User = new User { Username = sr.ReadString() };
// MD5Hash
@@ -68,6 +65,9 @@ namespace osu.Game.Scoring.Legacy
scoreInfo.Mods = currentRuleset.ConvertFromLegacyMods((LegacyMods)sr.ReadInt32()).ToArray();
+ currentBeatmap = workingBeatmap.GetPlayableBeatmap(currentRuleset.RulesetInfo, scoreInfo.Mods);
+ scoreInfo.Beatmap = currentBeatmap.BeatmapInfo;
+
/* score.HpGraphString = */
sr.ReadString();
diff --git a/osu.Game/Screens/Play/BreakOverlay.cs b/osu.Game/Screens/Play/BreakOverlay.cs
index ee8be87352..c978f4e96d 100644
--- a/osu.Game/Screens/Play/BreakOverlay.cs
+++ b/osu.Game/Screens/Play/BreakOverlay.cs
@@ -2,8 +2,6 @@
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
-using osu.Framework.Allocation;
-using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
@@ -16,8 +14,6 @@ namespace osu.Game.Screens.Play
{
public class BreakOverlay : Container
{
- private readonly ScoreProcessor scoreProcessor;
-
///
/// The duration of the break overlay fading.
///
@@ -37,10 +33,6 @@ namespace osu.Game.Screens.Play
{
breaks = value;
- // reset index in case the new breaks list is smaller than last one
- isBreakTime.Value = false;
- CurrentBreakIndex = 0;
-
if (IsLoaded)
initializeBreaks();
}
@@ -48,27 +40,17 @@ namespace osu.Game.Screens.Play
public override bool RemoveCompletedTransforms => false;
- ///
- /// Whether the gameplay is currently in a break.
- ///
- public IBindable IsBreakTime => isBreakTime;
-
- protected int CurrentBreakIndex;
-
- private readonly BindableBool isBreakTime = new BindableBool();
-
private readonly Container remainingTimeAdjustmentBox;
private readonly Container remainingTimeBox;
private readonly RemainingTimeCounter remainingTimeCounter;
- private readonly BreakInfo info;
private readonly BreakArrows breakArrows;
- private readonly double gameplayStartTime;
- public BreakOverlay(bool letterboxing, double gameplayStartTime = 0, ScoreProcessor scoreProcessor = null)
+ public BreakOverlay(bool letterboxing, ScoreProcessor scoreProcessor)
{
- this.gameplayStartTime = gameplayStartTime;
- this.scoreProcessor = scoreProcessor;
RelativeSizeAxes = Axes.Both;
+
+ BreakInfo info;
+
Child = fadeContainer = new Container
{
Alpha = 0,
@@ -119,13 +101,11 @@ namespace osu.Game.Screens.Play
}
};
- if (scoreProcessor != null) bindProcessor(scoreProcessor);
- }
-
- [BackgroundDependencyLoader(true)]
- private void load(GameplayClock clock)
- {
- if (clock != null) Clock = clock;
+ if (scoreProcessor != null)
+ {
+ info.AccuracyDisplay.Current.BindTo(scoreProcessor.Accuracy);
+ info.GradeDisplay.Current.BindTo(scoreProcessor.Rank);
+ }
}
protected override void LoadComplete()
@@ -134,42 +114,6 @@ namespace osu.Game.Screens.Play
initializeBreaks();
}
- protected override void Update()
- {
- base.Update();
- updateBreakTimeBindable();
- }
-
- private void updateBreakTimeBindable() =>
- isBreakTime.Value = getCurrentBreak()?.HasEffect == true
- || Clock.CurrentTime < gameplayStartTime
- || scoreProcessor?.HasCompleted == true;
-
- private BreakPeriod getCurrentBreak()
- {
- if (breaks?.Count > 0)
- {
- var time = Clock.CurrentTime;
-
- if (time > breaks[CurrentBreakIndex].EndTime)
- {
- while (time > breaks[CurrentBreakIndex].EndTime && CurrentBreakIndex < breaks.Count - 1)
- CurrentBreakIndex++;
- }
- else
- {
- while (time < breaks[CurrentBreakIndex].StartTime && CurrentBreakIndex > 0)
- CurrentBreakIndex--;
- }
-
- var closest = breaks[CurrentBreakIndex];
-
- return closest.Contains(time) ? closest : null;
- }
-
- return null;
- }
-
private void initializeBreaks()
{
FinishTransforms(true);
@@ -207,11 +151,5 @@ namespace osu.Game.Screens.Play
}
}
}
-
- private void bindProcessor(ScoreProcessor processor)
- {
- info.AccuracyDisplay.Current.BindTo(processor.Accuracy);
- info.GradeDisplay.Current.BindTo(processor.Rank);
- }
}
}
diff --git a/osu.Game/Screens/Play/BreakTracker.cs b/osu.Game/Screens/Play/BreakTracker.cs
new file mode 100644
index 0000000000..64262d52b5
--- /dev/null
+++ b/osu.Game/Screens/Play/BreakTracker.cs
@@ -0,0 +1,82 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Collections.Generic;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Game.Beatmaps.Timing;
+using osu.Game.Rulesets.Scoring;
+
+namespace osu.Game.Screens.Play
+{
+ public class BreakTracker : Component
+ {
+ private readonly ScoreProcessor scoreProcessor;
+
+ private readonly double gameplayStartTime;
+
+ ///
+ /// Whether the gameplay is currently in a break.
+ ///
+ public IBindable IsBreakTime => isBreakTime;
+
+ protected int CurrentBreakIndex;
+
+ private readonly BindableBool isBreakTime = new BindableBool();
+
+ private IReadOnlyList breaks;
+
+ public IReadOnlyList Breaks
+ {
+ get => breaks;
+ set
+ {
+ breaks = value;
+
+ // reset index in case the new breaks list is smaller than last one
+ isBreakTime.Value = false;
+ CurrentBreakIndex = 0;
+ }
+ }
+
+ public BreakTracker(double gameplayStartTime = 0, ScoreProcessor scoreProcessor = null)
+ {
+ this.gameplayStartTime = gameplayStartTime;
+ this.scoreProcessor = scoreProcessor;
+ }
+
+ protected override void Update()
+ {
+ base.Update();
+
+ isBreakTime.Value = getCurrentBreak()?.HasEffect == true
+ || Clock.CurrentTime < gameplayStartTime
+ || scoreProcessor?.HasCompleted == true;
+ }
+
+ private BreakPeriod getCurrentBreak()
+ {
+ if (breaks?.Count > 0)
+ {
+ var time = Clock.CurrentTime;
+
+ if (time > breaks[CurrentBreakIndex].EndTime)
+ {
+ while (time > breaks[CurrentBreakIndex].EndTime && CurrentBreakIndex < breaks.Count - 1)
+ CurrentBreakIndex++;
+ }
+ else
+ {
+ while (time < breaks[CurrentBreakIndex].StartTime && CurrentBreakIndex > 0)
+ CurrentBreakIndex--;
+ }
+
+ var closest = breaks[CurrentBreakIndex];
+
+ return closest.Contains(time) ? closest : null;
+ }
+
+ return null;
+ }
+ }
+}
diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs
index dc5bac9fd1..63ec3b0d2d 100644
--- a/osu.Game/Screens/Play/Player.cs
+++ b/osu.Game/Screens/Play/Player.cs
@@ -76,6 +76,8 @@ namespace osu.Game.Screens.Play
public BreakOverlay BreakOverlay;
+ private BreakTracker breakTracker;
+
protected ScoreProcessor ScoreProcessor { get; private set; }
protected HealthProcessor HealthProcessor { get; private set; }
@@ -204,7 +206,7 @@ namespace osu.Game.Screens.Play
foreach (var mod in Mods.Value.OfType())
mod.ApplyToHealthProcessor(HealthProcessor);
- BreakOverlay.IsBreakTime.BindValueChanged(onBreakTimeChanged, true);
+ breakTracker.IsBreakTime.BindValueChanged(onBreakTimeChanged, true);
}
private void addUnderlayComponents(Container target)
@@ -231,12 +233,30 @@ namespace osu.Game.Screens.Play
DrawableRuleset,
new ComboEffects(ScoreProcessor)
});
+
+ DrawableRuleset.FrameStableComponents.AddRange(new Drawable[]
+ {
+ ScoreProcessor,
+ HealthProcessor,
+ breakTracker = new BreakTracker(DrawableRuleset.GameplayStartTime, ScoreProcessor)
+ {
+ Breaks = working.Beatmap.Breaks
+ }
+ });
+
+ HealthProcessor.IsBreakTime.BindTo(breakTracker.IsBreakTime);
}
private void addOverlayComponents(Container target, WorkingBeatmap working)
{
target.AddRange(new[]
{
+ BreakOverlay = new BreakOverlay(working.Beatmap.BeatmapInfo.LetterboxInBreaks, ScoreProcessor)
+ {
+ Clock = DrawableRuleset.FrameStableClock,
+ ProcessCustomClock = false,
+ Breaks = working.Beatmap.Breaks
+ },
// display the cursor above some HUD elements.
DrawableRuleset.Cursor?.CreateProxy() ?? new Container(),
DrawableRuleset.ResumeOverlay?.CreateProxy() ?? new Container(),
@@ -293,20 +313,8 @@ namespace osu.Game.Screens.Play
performImmediateExit();
},
},
- failAnimation = new FailAnimation(DrawableRuleset) { OnComplete = onFailComplete, }
+ failAnimation = new FailAnimation(DrawableRuleset) { OnComplete = onFailComplete, },
});
-
- DrawableRuleset.Overlays.Add(BreakOverlay = new BreakOverlay(working.Beatmap.BeatmapInfo.LetterboxInBreaks, DrawableRuleset.GameplayStartTime, ScoreProcessor)
- {
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- Breaks = working.Beatmap.Breaks
- });
-
- DrawableRuleset.Overlays.Add(ScoreProcessor);
- DrawableRuleset.Overlays.Add(HealthProcessor);
-
- HealthProcessor.IsBreakTime.BindTo(BreakOverlay.IsBreakTime);
}
private void onBreakTimeChanged(ValueChangedEvent isBreakTime)
@@ -318,7 +326,7 @@ namespace osu.Game.Screens.Play
private void updatePauseOnFocusLostState() =>
HUDOverlay.HoldToQuit.PauseOnFocusLost = PauseOnFocusLost
&& !DrawableRuleset.HasReplayLoaded.Value
- && !BreakOverlay.IsBreakTime.Value;
+ && !breakTracker.IsBreakTime.Value;
private IBeatmap loadPlayableBeatmap()
{
@@ -540,7 +548,7 @@ namespace osu.Game.Screens.Play
PauseOverlay.Hide();
// breaks and time-based conditions may allow instant resume.
- if (BreakOverlay.IsBreakTime.Value)
+ if (breakTracker.IsBreakTime.Value)
completeResume();
else
DrawableRuleset.RequestResume(completeResume);
@@ -574,8 +582,8 @@ namespace osu.Game.Screens.Play
Background.BlurAmount.Value = 0;
// bind component bindables.
- Background.IsBreakTime.BindTo(BreakOverlay.IsBreakTime);
- DimmableStoryboard.IsBreakTime.BindTo(BreakOverlay.IsBreakTime);
+ Background.IsBreakTime.BindTo(breakTracker.IsBreakTime);
+ DimmableStoryboard.IsBreakTime.BindTo(breakTracker.IsBreakTime);
Background.StoryboardReplacesBackground.BindTo(storyboardReplacesBackground);
DimmableStoryboard.StoryboardReplacesBackground.BindTo(storyboardReplacesBackground);
@@ -657,7 +665,7 @@ namespace osu.Game.Screens.Play
using (var stream = new MemoryStream())
{
- new LegacyScoreEncoder(score, gameplayBeatmap).Encode(stream);
+ new LegacyScoreEncoder(score, gameplayBeatmap.PlayableBeatmap).Encode(stream);
replayReader = new LegacyByteArrayReader(stream.ToArray(), "replay.osr");
}
}
diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardVideo.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardVideo.cs
index 00df388d09..d4dbdf1ea8 100644
--- a/osu.Game/Storyboards/Drawables/DrawableStoryboardVideo.cs
+++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardVideo.cs
@@ -55,6 +55,8 @@ namespace osu.Game.Storyboards.Drawables
{
base.LoadComplete();
+ if (videoSprite == null) return;
+
using (videoSprite.BeginAbsoluteSequence(0))
videoSprite.FadeIn(500);
}
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index 3894c06994..781c566b5f 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -23,7 +23,7 @@
-
+
diff --git a/osu.iOS.props b/osu.iOS.props
index 9cc9792ecf..a2c6106931 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -71,7 +71,7 @@
-
+
@@ -79,7 +79,7 @@
-
+