diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj
index e2fc4d14f6..803927bc6f 100644
--- a/osu.Desktop/osu.Desktop.csproj
+++ b/osu.Desktop/osu.Desktop.csproj
@@ -27,9 +27,9 @@
-
-
-
+
+
+
diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs
index ab0afb08d7..c7ea29f8c0 100644
--- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs
+++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs
@@ -74,42 +74,42 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
private void initialiseHyperDash(List objects)
{
- // todo: add difficulty adjust.
- double halfCatcherWidth = CatcherArea.CATCHER_SIZE * (objects.FirstOrDefault()?.Scale ?? 1) / CatchPlayfield.BASE_WIDTH / 2;
+ List objectWithDroplets = new List();
+ foreach (var currentObject in objects)
+ {
+ if (currentObject is Fruit)
+ objectWithDroplets.Add(currentObject);
+ if (currentObject is JuiceStream)
+ foreach (var currentJuiceElement in currentObject.NestedHitObjects)
+ if (!(currentJuiceElement is TinyDroplet))
+ objectWithDroplets.Add((CatchHitObject)currentJuiceElement);
+ }
+
+ objectWithDroplets.Sort((h1, h2) => h1.StartTime.CompareTo(h2.StartTime));
+
+ double halfCatcherWidth = CatcherArea.GetCatcherSize(Beatmap.BeatmapInfo.BaseDifficulty) / 2;
int lastDirection = 0;
double lastExcess = halfCatcherWidth;
- int objCount = objects.Count;
-
- for (int i = 0; i < objCount - 1; i++)
+ for (int i = 0; i < objectWithDroplets.Count - 1; i++)
{
- CatchHitObject currentObject = objects[i];
-
- // not needed?
- // if (currentObject is TinyDroplet) continue;
-
- CatchHitObject nextObject = objects[i + 1];
-
- // while (nextObject is TinyDroplet)
- // {
- // if (++i == objCount - 1) break;
- // nextObject = objects[i + 1];
- // }
+ CatchHitObject currentObject = objectWithDroplets[i];
+ CatchHitObject nextObject = objectWithDroplets[i + 1];
int thisDirection = nextObject.X > currentObject.X ? 1 : -1;
- double timeToNext = nextObject.StartTime - ((currentObject as IHasEndTime)?.EndTime ?? currentObject.StartTime) - 4;
+ double timeToNext = nextObject.StartTime - currentObject.StartTime;
double distanceToNext = Math.Abs(nextObject.X - currentObject.X) - (lastDirection == thisDirection ? lastExcess : halfCatcherWidth);
-
- if (timeToNext * CatcherArea.Catcher.BASE_SPEED < distanceToNext)
+ float distanceToHyper = (float)(timeToNext * CatcherArea.Catcher.BASE_SPEED - distanceToNext);
+ if (distanceToHyper < 0)
{
currentObject.HyperDashTarget = nextObject;
lastExcess = halfCatcherWidth;
}
else
{
- //currentObject.DistanceToHyperDash = timeToNext - distanceToNext;
- lastExcess = MathHelper.Clamp(timeToNext - distanceToNext, 0, halfCatcherWidth);
+ currentObject.DistanceToHyperDash = distanceToHyper;
+ lastExcess = MathHelper.Clamp(distanceToHyper, 0, halfCatcherWidth);
}
lastDirection = thisDirection;
diff --git a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs
index 621fc100c2..0c50dae9fb 100644
--- a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs
+++ b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs
@@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Catch.Objects
public int IndexInBeatmap { get; set; }
- public virtual FruitVisualRepresentation VisualRepresentation => (FruitVisualRepresentation)(IndexInBeatmap % 4);
+ public virtual FruitVisualRepresentation VisualRepresentation => (FruitVisualRepresentation)(ComboIndex % 4);
public virtual bool NewCombo { get; set; }
@@ -27,7 +27,9 @@ namespace osu.Game.Rulesets.Catch.Objects
public int ComboIndex { get; set; }
///
- /// The distance for a fruit to to next hyper if it's not a hyper.
+ /// Difference between the distance to the next object
+ /// and the distance that would have triggered a hyper dash.
+ /// A value close to 0 indicates a difficult jump (for difficulty calculation).
///
public float DistanceToHyperDash { get; set; }
diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs
index d49be69856..102ec7fb3b 100644
--- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs
+++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs
@@ -22,6 +22,8 @@ namespace osu.Game.Rulesets.Catch.UI
private readonly CatcherArea catcherArea;
+ protected override bool UserScrollSpeedAdjustment => false;
+
public CatchPlayfield(BeatmapDifficulty difficulty, Func> getVisualRepresentation)
: base(BASE_WIDTH)
{
diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs
index 9460512a8d..be56ccf8c1 100644
--- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs
+++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs
@@ -107,6 +107,11 @@ namespace osu.Game.Rulesets.Catch.UI
public bool AttemptCatch(CatchHitObject obj) => MovableCatcher.AttemptCatch(obj);
+ public static float GetCatcherSize(BeatmapDifficulty difficulty)
+ {
+ return CATCHER_SIZE / CatchPlayfield.BASE_WIDTH * (1.0f - 0.7f * (difficulty.CircleSize - 5) / 5);
+ }
+
public class Catcher : Container, IKeyBindingHandler
{
///
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs
index f3b7d60cf0..8d27502b3c 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs
@@ -4,7 +4,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using osu.Framework.Input.States;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Osu.Objects;
@@ -77,7 +76,7 @@ namespace osu.Game.Rulesets.Osu.Mods
wasLeft = !wasLeft;
}
- osuInputManager.HandleCustomInput(new InputState(), state);
+ state.Apply(osuInputManager.CurrentState, osuInputManager);
}
public void ApplyToRulesetContainer(RulesetContainer rulesetContainer)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTransform.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTransform.cs
new file mode 100644
index 0000000000..440b314e5f
--- /dev/null
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModTransform.cs
@@ -0,0 +1,53 @@
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System;
+using System.Collections.Generic;
+using osu.Framework.Graphics;
+using osu.Game.Graphics;
+using osu.Game.Rulesets.Mods;
+using osu.Game.Rulesets.Objects.Drawables;
+using osu.Game.Rulesets.Osu.Objects;
+using OpenTK;
+
+namespace osu.Game.Rulesets.Osu.Mods
+{
+ internal class OsuModTransform : Mod, IApplicableToDrawableHitObjects
+ {
+ public override string Name => "Transform";
+ public override string ShortenedName => "TR";
+ public override FontAwesome Icon => FontAwesome.fa_arrows;
+ public override ModType Type => ModType.Fun;
+ public override string Description => "Everything rotates. EVERYTHING.";
+ public override double ScoreMultiplier => 1;
+ public override Type[] IncompatibleMods => new[] { typeof(OsuModWiggle) };
+
+ private float theta;
+
+ public void ApplyToDrawableHitObjects(IEnumerable drawables)
+ {
+ foreach (var drawable in drawables)
+ {
+ var hitObject = (OsuHitObject) drawable.HitObject;
+
+ float appearDistance = (float)(hitObject.TimePreempt - hitObject.TimeFadeIn) / 2;
+
+ Vector2 originalPosition = drawable.Position;
+ Vector2 appearOffset = new Vector2((float)Math.Cos(theta), (float)Math.Sin(theta)) * appearDistance;
+
+ //the - 1 and + 1 prevents the hit objects to appear in the wrong position.
+ double appearTime = hitObject.StartTime - hitObject.TimePreempt - 1;
+ double moveDuration = hitObject.TimePreempt + 1;
+
+ using (drawable.BeginAbsoluteSequence(appearTime, true))
+ {
+ drawable
+ .MoveToOffset(appearOffset)
+ .MoveTo(originalPosition, moveDuration, Easing.InOutSine);
+ }
+
+ theta += (float) hitObject.TimeFadeIn / 1000;
+ }
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs b/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs
new file mode 100644
index 0000000000..2e601c9078
--- /dev/null
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs
@@ -0,0 +1,67 @@
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System;
+using System.Collections.Generic;
+using osu.Framework.Graphics;
+using osu.Game.Graphics;
+using osu.Game.Rulesets.Mods;
+using osu.Game.Rulesets.Objects.Drawables;
+using osu.Game.Rulesets.Objects.Types;
+using osu.Game.Rulesets.Osu.Objects;
+using OpenTK;
+
+namespace osu.Game.Rulesets.Osu.Mods
+{
+ internal class OsuModWiggle : Mod, IApplicableToDrawableHitObjects
+ {
+ public override string Name => "Wiggle";
+ public override string ShortenedName => "WG";
+ public override FontAwesome Icon => FontAwesome.fa_certificate;
+ public override ModType Type => ModType.Fun;
+ public override string Description => "They just won't stay still...";
+ public override double ScoreMultiplier => 1;
+ public override Type[] IncompatibleMods => new[] { typeof(OsuModTransform) };
+
+ private const int wiggle_duration = 90; // (ms) Higher = fewer wiggles
+ private const int wiggle_strength = 10; // Higher = stronger wiggles
+
+ public void ApplyToDrawableHitObjects(IEnumerable drawables)
+ {
+ foreach (var drawable in drawables)
+ drawable.ApplyCustomUpdateState += drawableOnApplyCustomUpdateState;
+ }
+
+ private void drawableOnApplyCustomUpdateState(DrawableHitObject drawable, ArmedState state)
+ {
+ var osuObject = (OsuHitObject)drawable.HitObject;
+ Vector2 origin = drawable.Position;
+
+ Random objRand = new Random((int)osuObject.StartTime);
+
+ // Wiggle all objects during TimePreempt
+ int amountWiggles = (int)osuObject.TimePreempt / wiggle_duration;
+
+ void wiggle()
+ {
+ float nextAngle = (float)(objRand.NextDouble() * 2 * Math.PI);
+ float nextDist = (float)(objRand.NextDouble() * wiggle_strength);
+ drawable.MoveTo(new Vector2((float)(nextDist * Math.Cos(nextAngle) + origin.X), (float)(nextDist * Math.Sin(nextAngle) + origin.Y)), wiggle_duration);
+ }
+
+ for (int i = 0; i < amountWiggles; i++)
+ using (drawable.BeginAbsoluteSequence(osuObject.StartTime - osuObject.TimePreempt + i * wiggle_duration, true))
+ wiggle();
+
+ // Keep wiggling sliders and spinners for their duration
+ if (!(osuObject is IHasEndTime endTime))
+ return;
+
+ amountWiggles = (int)(endTime.Duration / wiggle_duration);
+
+ for (int i = 0; i < amountWiggles; i++)
+ using (drawable.BeginAbsoluteSequence(osuObject.StartTime + i * wiggle_duration, true))
+ wiggle();
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs
index fa6e9a018a..6736d10dab 100644
--- a/osu.Game.Rulesets.Osu/OsuRuleset.cs
+++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs
@@ -117,6 +117,11 @@ namespace osu.Game.Rulesets.Osu
new OsuModRelax(),
new OsuModAutopilot(),
};
+ case ModType.Fun:
+ return new Mod[] {
+ new OsuModTransform(),
+ new OsuModWiggle(),
+ };
default:
return new Mod[] { };
}
diff --git a/osu.Game.Tests/Visual/TestCaseGameplayMenuOverlay.cs b/osu.Game.Tests/Visual/TestCaseGameplayMenuOverlay.cs
index 45b5ec2c11..417b0f94d7 100644
--- a/osu.Game.Tests/Visual/TestCaseGameplayMenuOverlay.cs
+++ b/osu.Game.Tests/Visual/TestCaseGameplayMenuOverlay.cs
@@ -8,14 +8,14 @@ using System.Linq;
using OpenTK.Input;
using osu.Framework.Allocation;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Input.EventArgs;
using osu.Framework.Logging;
using osu.Game.Screens.Play;
+using OpenTK;
namespace osu.Game.Tests.Visual
{
[Description("player pause/fail screens")]
- public class TestCaseGameplayMenuOverlay : OsuTestCase
+ public class TestCaseGameplayMenuOverlay : ManualInputManagerTestCase
{
public override IReadOnlyList RequiredTypes => new[] { typeof(FailOverlay), typeof(PauseContainer) };
@@ -73,12 +73,18 @@ namespace osu.Game.Tests.Visual
{
AddStep("Show overlay", () => failOverlay.Show());
- AddStep("Hover first button", () => failOverlay.Buttons.First().TriggerOnMouseMove(null));
+ AddStep("Hover first button", () => InputManager.MoveMouseTo(failOverlay.Buttons.First()));
AddStep("Hide overlay", () => failOverlay.Hide());
AddAssert("Overlay state is reset", () => !failOverlay.Buttons.Any(b => b.Selected));
}
+ private void press(Key key)
+ {
+ InputManager.PressKey(key);
+ InputManager.ReleaseKey(key);
+ }
+
///
/// Tests that pressing enter after an overlay shows doesn't trigger an event because a selection hasn't occurred.
///
@@ -86,7 +92,7 @@ namespace osu.Game.Tests.Visual
{
AddStep("Show overlay", () => pauseOverlay.Show());
- AddStep("Press enter", () => pauseOverlay.TriggerOnKeyDown(null, new KeyDownEventArgs { Key = Key.Enter }));
+ AddStep("Press enter", () => press(Key.Enter));
AddAssert("Overlay still open", () => pauseOverlay.State == Visibility.Visible);
AddStep("Hide overlay", () => pauseOverlay.Hide());
@@ -99,7 +105,7 @@ namespace osu.Game.Tests.Visual
{
AddStep("Show overlay", () => pauseOverlay.Show());
- AddStep("Up arrow", () => pauseOverlay.TriggerOnKeyDown(null, new KeyDownEventArgs { Key = Key.Up }));
+ AddStep("Up arrow", () => press(Key.Up));
AddAssert("Last button selected", () => pauseOverlay.Buttons.Last().Selected);
AddStep("Hide overlay", () => pauseOverlay.Hide());
@@ -112,7 +118,7 @@ namespace osu.Game.Tests.Visual
{
AddStep("Show overlay", () => pauseOverlay.Show());
- AddStep("Down arrow", () => pauseOverlay.TriggerOnKeyDown(null, new KeyDownEventArgs { Key = Key.Down }));
+ AddStep("Down arrow", () => press(Key.Down));
AddAssert("First button selected", () => pauseOverlay.Buttons.First().Selected);
AddStep("Hide overlay", () => pauseOverlay.Hide());
@@ -125,11 +131,11 @@ namespace osu.Game.Tests.Visual
{
AddStep("Show overlay", () => failOverlay.Show());
- AddStep("Up arrow", () => failOverlay.TriggerOnKeyDown(null, new KeyDownEventArgs { Key = Key.Up }));
+ AddStep("Up arrow", () => press(Key.Up));
AddAssert("Last button selected", () => failOverlay.Buttons.Last().Selected);
- AddStep("Up arrow", () => failOverlay.TriggerOnKeyDown(null, new KeyDownEventArgs { Key = Key.Up }));
+ AddStep("Up arrow", () => press(Key.Up));
AddAssert("First button selected", () => failOverlay.Buttons.First().Selected);
- AddStep("Up arrow", () => failOverlay.TriggerOnKeyDown(null, new KeyDownEventArgs { Key = Key.Up }));
+ AddStep("Up arrow", () => press(Key.Up));
AddAssert("Last button selected", () => failOverlay.Buttons.Last().Selected);
AddStep("Hide overlay", () => failOverlay.Hide());
@@ -142,11 +148,11 @@ namespace osu.Game.Tests.Visual
{
AddStep("Show overlay", () => failOverlay.Show());
- AddStep("Down arrow", () => failOverlay.TriggerOnKeyDown(null, new KeyDownEventArgs { Key = Key.Down }));
+ AddStep("Down arrow", () => press(Key.Down));
AddAssert("First button selected", () => failOverlay.Buttons.First().Selected);
- AddStep("Down arrow", () => failOverlay.TriggerOnKeyDown(null, new KeyDownEventArgs { Key = Key.Down }));
+ AddStep("Down arrow", () => press(Key.Down));
AddAssert("Last button selected", () => failOverlay.Buttons.Last().Selected);
- AddStep("Down arrow", () => failOverlay.TriggerOnKeyDown(null, new KeyDownEventArgs { Key = Key.Down }));
+ AddStep("Down arrow", () => press(Key.Down));
AddAssert("First button selected", () => failOverlay.Buttons.First().Selected);
AddStep("Hide overlay", () => failOverlay.Hide());
@@ -161,8 +167,8 @@ namespace osu.Game.Tests.Visual
var secondButton = pauseOverlay.Buttons.Skip(1).First();
- AddStep("Down arrow", () => pauseOverlay.TriggerOnKeyDown(null, new KeyDownEventArgs { Key = Key.Down }));
- AddStep("Hover second button", () => secondButton.TriggerOnMouseMove(null));
+ AddStep("Down arrow", () => press(Key.Down));
+ AddStep("Hover second button", () => InputManager.MoveMouseTo(secondButton));
AddAssert("First button not selected", () => !pauseOverlay.Buttons.First().Selected);
AddAssert("Second button selected", () => secondButton.Selected);
@@ -174,12 +180,16 @@ namespace osu.Game.Tests.Visual
///
private void testKeySelectionAfterMouseSelection()
{
- AddStep("Show overlay", () => pauseOverlay.Show());
+ AddStep("Show overlay", () =>
+ {
+ pauseOverlay.Show();
+ InputManager.MoveMouseTo(Vector2.Zero);
+ });
var secondButton = pauseOverlay.Buttons.Skip(1).First();
- AddStep("Hover second button", () => secondButton.TriggerOnMouseMove(null));
- AddStep("Up arrow", () => pauseOverlay.TriggerOnKeyDown(null, new KeyDownEventArgs { Key = Key.Up }));
+ AddStep("Hover second button", () => InputManager.MoveMouseTo(secondButton));
+ AddStep("Up arrow", () => press(Key.Up));
AddAssert("Second button not selected", () => !secondButton.Selected);
AddAssert("First button selected", () => pauseOverlay.Buttons.First().Selected);
@@ -195,9 +205,9 @@ namespace osu.Game.Tests.Visual
var secondButton = pauseOverlay.Buttons.Skip(1).First();
- AddStep("Hover second button", () => secondButton.TriggerOnMouseMove(null));
- AddStep("Unhover second button", () => secondButton.TriggerOnHoverLost(null));
- AddStep("Down arrow", () => pauseOverlay.TriggerOnKeyDown(null, new KeyDownEventArgs { Key = Key.Down }));
+ AddStep("Hover second button", () => InputManager.MoveMouseTo(secondButton));
+ AddStep("Unhover second button", () => InputManager.MoveMouseTo(Vector2.Zero));
+ AddStep("Down arrow", () => press(Key.Down));
AddAssert("First button selected", () => pauseOverlay.Buttons.First().Selected); // Initial state condition
AddStep("Hide overlay", () => pauseOverlay.Hide());
@@ -218,7 +228,7 @@ namespace osu.Game.Tests.Visual
var lastAction = pauseOverlay.OnRetry;
pauseOverlay.OnRetry = () => triggered = true;
- retryButton.TriggerOnClick();
+ retryButton.Click();
pauseOverlay.OnRetry = lastAction;
});
@@ -235,23 +245,28 @@ namespace osu.Game.Tests.Visual
AddStep("Select second button", () =>
{
- pauseOverlay.TriggerOnKeyDown(null, new KeyDownEventArgs { Key = Key.Down });
- pauseOverlay.TriggerOnKeyDown(null, new KeyDownEventArgs { Key = Key.Down });
+ press(Key.Down);
+ press(Key.Down);
});
- var retryButton = pauseOverlay.Buttons.Skip(1).First();
-
bool triggered = false;
+ Action lastAction = null;
AddStep("Press enter", () =>
{
- var lastAction = pauseOverlay.OnRetry;
+ lastAction = pauseOverlay.OnRetry;
pauseOverlay.OnRetry = () => triggered = true;
-
- retryButton.TriggerOnKeyDown(null, new KeyDownEventArgs { Key = Key.Enter });
- pauseOverlay.OnRetry = lastAction;
+ press(Key.Enter);
});
- AddAssert("Action was triggered", () => triggered);
+ AddAssert("Action was triggered", () =>
+ {
+ if (lastAction != null)
+ {
+ pauseOverlay.OnRetry = lastAction;
+ lastAction = null;
+ }
+ return triggered;
+ });
AddAssert("Overlay is closed", () => pauseOverlay.State == Visibility.Hidden);
}
}
diff --git a/osu.Game.Tests/Visual/TestCaseKeyCounter.cs b/osu.Game.Tests/Visual/TestCaseKeyCounter.cs
index b98875cd6a..178b47ed33 100644
--- a/osu.Game.Tests/Visual/TestCaseKeyCounter.cs
+++ b/osu.Game.Tests/Visual/TestCaseKeyCounter.cs
@@ -1,32 +1,45 @@
// Copyright (c) 2007-2018 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+using System;
+using System.Collections.Generic;
+using System.Linq;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.MathUtils;
+using osu.Framework.Timing;
using osu.Game.Screens.Play;
using OpenTK.Input;
namespace osu.Game.Tests.Visual
{
[TestFixture]
- public class TestCaseKeyCounter : OsuTestCase
+ public class TestCaseKeyCounter : ManualInputManagerTestCase
{
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(KeyCounterKeyboard),
+ typeof(KeyCounterMouse),
+ typeof(KeyCounterCollection)
+ };
+
public TestCaseKeyCounter()
{
+ KeyCounterKeyboard rewindTestKeyCounterKeyboard;
KeyCounterCollection kc = new KeyCounterCollection
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Children = new KeyCounter[]
{
- new KeyCounterKeyboard(Key.Z),
+ rewindTestKeyCounterKeyboard = new KeyCounterKeyboard(Key.X),
new KeyCounterKeyboard(Key.X),
new KeyCounterMouse(MouseButton.Left),
new KeyCounterMouse(MouseButton.Right),
},
};
+
AddStep("Add random", () =>
{
Key key = (Key)((int)Key.A + RNG.Next(26));
@@ -34,7 +47,57 @@ namespace osu.Game.Tests.Visual
});
AddSliderStep("Fade time", 0, 200, 50, v => kc.FadeTime = v);
+ Key testKey = ((KeyCounterKeyboard)kc.Children.First()).Key;
+ double time1 = 0;
+
+ AddStep($"Press {testKey} key", () =>
+ {
+ InputManager.PressKey(testKey);
+ InputManager.ReleaseKey(testKey);
+ });
+
+ AddAssert($"Check {testKey} counter after keypress", () => rewindTestKeyCounterKeyboard.CountPresses == 1);
+
+ AddStep($"Press {testKey} key", () =>
+ {
+ InputManager.PressKey(testKey);
+ InputManager.ReleaseKey(testKey);
+ time1 = Clock.CurrentTime;
+ });
+
+ AddAssert($"Check {testKey} counter after keypress", () => rewindTestKeyCounterKeyboard.CountPresses == 2);
+
+ IFrameBasedClock oldClock = null;
+
+ AddStep($"Rewind {testKey} counter once", () =>
+ {
+ oldClock = rewindTestKeyCounterKeyboard.Clock;
+ rewindTestKeyCounterKeyboard.Clock = new FramedOffsetClock(new FixedClock(time1 - 10));
+ });
+
+ AddAssert($"Check {testKey} counter after rewind", () => rewindTestKeyCounterKeyboard.CountPresses == 1);
+
+ AddStep($"Rewind {testKey} counter to zero", () => rewindTestKeyCounterKeyboard.Clock = new FramedOffsetClock(new FixedClock(0)));
+
+ AddAssert($"Check {testKey} counter after rewind", () => rewindTestKeyCounterKeyboard.CountPresses == 0);
+
+ AddStep("Restore clock", () => rewindTestKeyCounterKeyboard.Clock = oldClock);
+
Add(kc);
}
+
+ private class FixedClock : IClock
+ {
+ private readonly double time;
+
+ public FixedClock(double time)
+ {
+ this.time = time;
+ }
+
+ public double CurrentTime => time;
+ public double Rate => 1;
+ public bool IsRunning => false;
+ }
}
}
diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs
index 303a19aab3..1aa4818393 100644
--- a/osu.Game/Beatmaps/BeatmapInfo.cs
+++ b/osu.Game/Beatmaps/BeatmapInfo.cs
@@ -27,13 +27,15 @@ namespace osu.Game.Beatmaps
[JsonProperty("id")]
public int? OnlineBeatmapID
{
- get { return onlineBeatmapID; }
- set { onlineBeatmapID = value > 0 ? value : null; }
+ get => onlineBeatmapID;
+ set => onlineBeatmapID = value > 0 ? value : null;
}
[JsonIgnore]
public int BeatmapSetInfoID { get; set; }
+ public BeatmapSetOnlineStatus Status { get; set; } = BeatmapSetOnlineStatus.None;
+
[Required]
public BeatmapSetInfo BeatmapSet { get; set; }
@@ -82,7 +84,7 @@ namespace osu.Game.Beatmaps
[JsonIgnore]
public string StoredBookmarks
{
- get { return string.Join(",", Bookmarks); }
+ get => string.Join(",", Bookmarks);
set
{
if (string.IsNullOrEmpty(value))
@@ -93,8 +95,7 @@ namespace osu.Game.Beatmaps
Bookmarks = value.Split(',').Select(v =>
{
- int val;
- bool result = int.TryParse(v, out val);
+ bool result = int.TryParse(v, out int val);
return new { result, val };
}).Where(p => p.result).Select(p => p.val).ToArray();
}
diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs
index 21df9a6c68..aa653d88f9 100644
--- a/osu.Game/Beatmaps/BeatmapManager.cs
+++ b/osu.Game/Beatmaps/BeatmapManager.cs
@@ -1,4 +1,4 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Copyright (c) 2007-2018 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
@@ -104,7 +104,7 @@ namespace osu.Game.Beatmaps
validateOnlineIds(beatmapSet.Beatmaps);
foreach (BeatmapInfo b in beatmapSet.Beatmaps)
- fetchAndPopulateOnlineIDs(b, beatmapSet.Beatmaps);
+ fetchAndPopulateOnlineValues(b, beatmapSet.Beatmaps);
// check if a set already exists with the same online id, delete if it does.
if (beatmapSet.OnlineBeatmapSetID != null)
@@ -388,21 +388,22 @@ namespace osu.Game.Beatmaps
}
///
- /// Query the API to populate mising OnlineBeatmapID / OnlineBeatmapSetID properties.
+ /// Query the API to populate missing values like OnlineBeatmapID / OnlineBeatmapSetID or (Rank-)Status.
///
/// The beatmap to populate.
/// The other beatmaps contained within this set.
/// Whether to re-query if the provided beatmap already has populated values.
/// True if population was successful.
- private bool fetchAndPopulateOnlineIDs(BeatmapInfo beatmap, IEnumerable otherBeatmaps, bool force = false)
+ private bool fetchAndPopulateOnlineValues(BeatmapInfo beatmap, IEnumerable otherBeatmaps, bool force = false)
{
if (api?.State != APIState.Online)
return false;
- if (!force && beatmap.OnlineBeatmapID != null && beatmap.BeatmapSet.OnlineBeatmapSetID != null)
+ if (!force && beatmap.OnlineBeatmapID != null && beatmap.BeatmapSet.OnlineBeatmapSetID != null
+ && beatmap.Status != BeatmapSetOnlineStatus.None && beatmap.BeatmapSet.Status != BeatmapSetOnlineStatus.None)
return true;
- Logger.Log("Attempting online lookup for IDs...", LoggingTarget.Database);
+ Logger.Log("Attempting online lookup for the missing values...", LoggingTarget.Database);
try
{
@@ -414,6 +415,9 @@ namespace osu.Game.Beatmaps
Logger.Log($"Successfully mapped to {res.OnlineBeatmapSetID} / {res.OnlineBeatmapID}.", LoggingTarget.Database);
+ beatmap.Status = res.Status;
+ beatmap.BeatmapSet.Status = res.BeatmapSet.Status;
+
if (otherBeatmaps.Any(b => b.OnlineBeatmapID == res.OnlineBeatmapID))
{
Logger.Log("Another beatmap in the same set already mapped to this ID. We'll skip adding it this time.", LoggingTarget.Database);
@@ -422,6 +426,7 @@ namespace osu.Game.Beatmaps
beatmap.BeatmapSet.OnlineBeatmapSetID = res.OnlineBeatmapSetID;
beatmap.OnlineBeatmapID = res.OnlineBeatmapID;
+
return true;
}
catch (Exception e)
diff --git a/osu.Game/Beatmaps/BeatmapProcessor.cs b/osu.Game/Beatmaps/BeatmapProcessor.cs
index 9d7cd673dc..9db2c5f08e 100644
--- a/osu.Game/Beatmaps/BeatmapProcessor.cs
+++ b/osu.Game/Beatmaps/BeatmapProcessor.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Linq;
+using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
namespace osu.Game.Beatmaps
@@ -44,6 +45,25 @@ namespace osu.Game.Beatmaps
public virtual void PostProcess()
{
+ void updateNestedCombo(HitObject obj, int comboIndex, int indexInCurrentCombo)
+ {
+ if (obj is IHasComboInformation objectComboInfo)
+ {
+ objectComboInfo.ComboIndex = comboIndex;
+ objectComboInfo.IndexInCurrentCombo = indexInCurrentCombo;
+ foreach (var nestedObject in obj.NestedHitObjects)
+ updateNestedCombo(nestedObject, comboIndex, indexInCurrentCombo);
+ }
+ }
+
+ foreach (var hitObject in Beatmap.HitObjects)
+ {
+ if (hitObject is IHasComboInformation objectComboInfo)
+ {
+ foreach (var nested in hitObject.NestedHitObjects)
+ updateNestedCombo(nested, objectComboInfo.ComboIndex, objectComboInfo.IndexInCurrentCombo);
+ }
+ }
}
}
}
diff --git a/osu.Game/Beatmaps/BeatmapSetInfo.cs b/osu.Game/Beatmaps/BeatmapSetInfo.cs
index ebebe42097..7a7d010a31 100644
--- a/osu.Game/Beatmaps/BeatmapSetInfo.cs
+++ b/osu.Game/Beatmaps/BeatmapSetInfo.cs
@@ -17,10 +17,12 @@ namespace osu.Game.Beatmaps
public int? OnlineBeatmapSetID
{
- get { return onlineBeatmapSetID; }
- set { onlineBeatmapSetID = value > 0 ? value : null; }
+ get => onlineBeatmapSetID;
+ set => onlineBeatmapSetID = value > 0 ? value : null;
}
+ public BeatmapSetOnlineStatus Status { get; set; } = BeatmapSetOnlineStatus.None;
+
public BeatmapMetadata Metadata { get; set; }
public List Beatmaps { get; set; }
diff --git a/osu.Game/Beatmaps/Drawables/BeatmapSetOnlineStatusPill.cs b/osu.Game/Beatmaps/Drawables/BeatmapSetOnlineStatusPill.cs
index c7e97cef55..da281b4db3 100644
--- a/osu.Game/Beatmaps/Drawables/BeatmapSetOnlineStatusPill.cs
+++ b/osu.Game/Beatmaps/Drawables/BeatmapSetOnlineStatusPill.cs
@@ -1,7 +1,6 @@
// Copyright (c) 2007-2018 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-using System;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
@@ -14,20 +13,35 @@ namespace osu.Game.Beatmaps.Drawables
{
private readonly OsuSpriteText statusText;
- private BeatmapSetOnlineStatus status = BeatmapSetOnlineStatus.None;
+ private BeatmapSetOnlineStatus status;
+
public BeatmapSetOnlineStatus Status
{
- get { return status; }
+ get => status;
set
{
- if (value == status) return;
+ if (status == value)
+ return;
status = value;
- statusText.Text = Enum.GetName(typeof(BeatmapSetOnlineStatus), Status)?.ToUpperInvariant();
+ Alpha = value == BeatmapSetOnlineStatus.None ? 0 : 1;
+ statusText.Text = value.ToString().ToUpperInvariant();
}
}
- public BeatmapSetOnlineStatusPill(float textSize, MarginPadding textPadding)
+ public float TextSize
+ {
+ get => statusText.TextSize;
+ set => statusText.TextSize = value;
+ }
+
+ public MarginPadding TextPadding
+ {
+ get => statusText.Padding;
+ set => statusText.Padding = value;
+ }
+
+ public BeatmapSetOnlineStatusPill()
{
AutoSizeAxes = Axes.Both;
Masking = true;
@@ -45,10 +59,10 @@ namespace osu.Game.Beatmaps.Drawables
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Font = @"Exo2.0-Bold",
- TextSize = textSize,
- Padding = textPadding,
},
};
+
+ Status = BeatmapSetOnlineStatus.None;
}
}
}
diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs
index a2b44aab52..e0a22460ef 100644
--- a/osu.Game/Beatmaps/WorkingBeatmap.cs
+++ b/osu.Game/Beatmaps/WorkingBeatmap.cs
@@ -135,7 +135,7 @@ namespace osu.Game.Beatmaps
public bool BackgroundLoaded => background.IsResultAvailable;
public Texture Background => background.Value;
- protected virtual bool BackgroundStillValid(Texture b) => b == null || !b.IsDisposed;
+ protected virtual bool BackgroundStillValid(Texture b) => b == null || b.Available;
protected abstract Texture GetBackground();
private readonly RecyclableLazy background;
diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs
index e9fe943f15..2a31df462e 100644
--- a/osu.Game/Database/ArchiveModelManager.cs
+++ b/osu.Game/Database/ArchiveModelManager.cs
@@ -59,7 +59,7 @@ namespace osu.Game.Database
// ReSharper disable once NotAccessedField.Local (we should keep a reference to this so it is not finalised)
private ArchiveImportIPCChannel ipc;
- private readonly List cachedEvents = new List();
+ private readonly List queuedEvents = new List();
///
/// Allows delaying of outwards events until an operation is confirmed (at a database level).
@@ -77,20 +77,27 @@ namespace osu.Game.Database
/// Whether the flushed events should be performed.
private void flushEvents(bool perform)
{
+ Action[] events;
+ lock (queuedEvents)
+ {
+ events = queuedEvents.ToArray();
+ queuedEvents.Clear();
+ }
+
if (perform)
{
- foreach (var a in cachedEvents)
+ foreach (var a in events)
a.Invoke();
}
- cachedEvents.Clear();
delayingEvents = false;
}
private void handleEvent(Action a)
{
if (delayingEvents)
- cachedEvents.Add(a);
+ lock (queuedEvents)
+ queuedEvents.Add(a);
else
a.Invoke();
}
@@ -432,6 +439,13 @@ namespace osu.Game.Database
return Task.CompletedTask;
}
+ if (!stable.ExistsDirectory(ImportFromStablePath))
+ {
+ // This handles situations like when the user does not have a Skins folder
+ Logger.Log($"No {ImportFromStablePath} folder available in osu!stable installation", LoggingTarget.Information, LogLevel.Error);
+ return Task.CompletedTask;
+ }
+
return Task.Factory.StartNew(() => Import(stable.GetDirectories(ImportFromStablePath).Select(f => stable.GetFullPath(f)).ToArray()), TaskCreationOptions.LongRunning);
}
diff --git a/osu.Game/Graphics/Backgrounds/Background.cs b/osu.Game/Graphics/Backgrounds/Background.cs
index 6fc8b0e070..d3d530a540 100644
--- a/osu.Game/Graphics/Backgrounds/Background.cs
+++ b/osu.Game/Graphics/Backgrounds/Background.cs
@@ -6,7 +6,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
-using OpenTK.Graphics;
namespace osu.Game.Graphics.Backgrounds
{
@@ -28,7 +27,6 @@ namespace osu.Game.Graphics.Backgrounds
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
- Colour = Color4.DarkGray,
FillMode = FillMode.Fill,
});
}
diff --git a/osu.Game/Input/Handlers/ReplayInputHandler.cs b/osu.Game/Input/Handlers/ReplayInputHandler.cs
index 5f53868b28..0a62c6ca72 100644
--- a/osu.Game/Input/Handlers/ReplayInputHandler.cs
+++ b/osu.Game/Input/Handlers/ReplayInputHandler.cs
@@ -3,10 +3,13 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using osu.Framework.Input.Handlers;
using osu.Framework.Input.StateChanges;
+using osu.Framework.Input.StateChanges.Events;
using osu.Framework.Input.States;
using osu.Framework.Platform;
+using osu.Game.Rulesets.UI;
using OpenTK;
namespace osu.Game.Input.Handlers
@@ -40,7 +43,29 @@ namespace osu.Game.Input.Handlers
public void Apply(InputState state, IInputStateChangeHandler handler)
{
- handler.HandleCustomInput(state, this);
+ if (!(state is RulesetInputManagerInputState inputState))
+ throw new InvalidOperationException($"{nameof(ReplayState)} should only be applied to a {nameof(RulesetInputManagerInputState)}");
+
+ var lastPressed = inputState.LastReplayState?.PressedActions ?? new List();
+ var released = lastPressed.Except(PressedActions).ToArray();
+ var pressed = PressedActions.Except(lastPressed).ToArray();
+
+ inputState.LastReplayState = this;
+
+ handler.HandleInputStateChange(new ReplayStateChangeEvent(state, this, released, pressed));
+ }
+ }
+
+ public class ReplayStateChangeEvent : InputStateChangeEvent
+ {
+ public readonly T[] ReleasedActions;
+ public readonly T[] PressedActions;
+
+ public ReplayStateChangeEvent(InputState state, IInput input, T[] releasedActions, T[] pressedActions)
+ : base(state, input)
+ {
+ ReleasedActions = releasedActions;
+ PressedActions = pressedActions;
}
}
}
diff --git a/osu.Game/Migrations/20180913080842_AddRankStatus.Designer.cs b/osu.Game/Migrations/20180913080842_AddRankStatus.Designer.cs
new file mode 100644
index 0000000000..5ab43da046
--- /dev/null
+++ b/osu.Game/Migrations/20180913080842_AddRankStatus.Designer.cs
@@ -0,0 +1,380 @@
+//
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using osu.Game.Database;
+
+namespace osu.Game.Migrations
+{
+ [DbContext(typeof(OsuDbContext))]
+ [Migration("20180913080842_AddRankStatus")]
+ partial class AddRankStatus
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "2.1.2-rtm-30932");
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ApproachRate");
+
+ b.Property("CircleSize");
+
+ b.Property("DrainRate");
+
+ b.Property("OverallDifficulty");
+
+ b.Property("SliderMultiplier");
+
+ b.Property("SliderTickRate");
+
+ b.HasKey("ID");
+
+ b.ToTable("BeatmapDifficulty");
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("AudioLeadIn");
+
+ b.Property("BaseDifficultyID");
+
+ b.Property("BeatDivisor");
+
+ b.Property("BeatmapSetInfoID");
+
+ b.Property("Countdown");
+
+ b.Property("DistanceSpacing");
+
+ b.Property("GridSize");
+
+ b.Property("Hash");
+
+ b.Property("Hidden");
+
+ b.Property("LetterboxInBreaks");
+
+ b.Property("MD5Hash");
+
+ b.Property("MetadataID");
+
+ b.Property("OnlineBeatmapID");
+
+ b.Property("Path");
+
+ b.Property("RulesetID");
+
+ b.Property("SpecialStyle");
+
+ b.Property("StackLeniency");
+
+ b.Property("StarDifficulty");
+
+ b.Property("Status");
+
+ b.Property("StoredBookmarks");
+
+ b.Property("TimelineZoom");
+
+ b.Property("Version");
+
+ b.Property("WidescreenStoryboard");
+
+ b.HasKey("ID");
+
+ b.HasIndex("BaseDifficultyID");
+
+ b.HasIndex("BeatmapSetInfoID");
+
+ b.HasIndex("Hash");
+
+ b.HasIndex("MD5Hash");
+
+ b.HasIndex("MetadataID");
+
+ b.HasIndex("OnlineBeatmapID")
+ .IsUnique();
+
+ b.HasIndex("RulesetID");
+
+ b.ToTable("BeatmapInfo");
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Artist");
+
+ b.Property("ArtistUnicode");
+
+ b.Property("AudioFile");
+
+ b.Property("AuthorString")
+ .HasColumnName("Author");
+
+ b.Property("BackgroundFile");
+
+ b.Property("PreviewTime");
+
+ b.Property("Source");
+
+ b.Property("Tags");
+
+ b.Property("Title");
+
+ b.Property("TitleUnicode");
+
+ b.HasKey("ID");
+
+ b.ToTable("BeatmapMetadata");
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("BeatmapSetInfoID");
+
+ b.Property("FileInfoID");
+
+ b.Property("Filename")
+ .IsRequired();
+
+ b.HasKey("ID");
+
+ b.HasIndex("BeatmapSetInfoID");
+
+ b.HasIndex("FileInfoID");
+
+ b.ToTable("BeatmapSetFileInfo");
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("DeletePending");
+
+ b.Property("Hash");
+
+ b.Property("MetadataID");
+
+ b.Property("OnlineBeatmapSetID");
+
+ b.Property("Protected");
+
+ b.Property("Status");
+
+ b.HasKey("ID");
+
+ b.HasIndex("DeletePending");
+
+ b.HasIndex("Hash")
+ .IsUnique();
+
+ b.HasIndex("MetadataID");
+
+ b.HasIndex("OnlineBeatmapSetID")
+ .IsUnique();
+
+ b.ToTable("BeatmapSetInfo");
+ });
+
+ modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("IntKey")
+ .HasColumnName("Key");
+
+ b.Property("RulesetID");
+
+ b.Property("StringValue")
+ .HasColumnName("Value");
+
+ b.Property("Variant");
+
+ b.HasKey("ID");
+
+ b.HasIndex("RulesetID", "Variant");
+
+ b.ToTable("Settings");
+ });
+
+ modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("IntAction")
+ .HasColumnName("Action");
+
+ b.Property("KeysString")
+ .HasColumnName("Keys");
+
+ b.Property("RulesetID");
+
+ b.Property("Variant");
+
+ b.HasKey("ID");
+
+ b.HasIndex("IntAction");
+
+ b.HasIndex("RulesetID", "Variant");
+
+ b.ToTable("KeyBinding");
+ });
+
+ modelBuilder.Entity("osu.Game.IO.FileInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Hash");
+
+ b.Property("ReferenceCount");
+
+ b.HasKey("ID");
+
+ b.HasIndex("Hash")
+ .IsUnique();
+
+ b.HasIndex("ReferenceCount");
+
+ b.ToTable("FileInfo");
+ });
+
+ modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Available");
+
+ b.Property("InstantiationInfo");
+
+ b.Property("Name");
+
+ b.Property("ShortName");
+
+ b.HasKey("ID");
+
+ b.HasIndex("Available");
+
+ b.HasIndex("ShortName")
+ .IsUnique();
+
+ b.ToTable("RulesetInfo");
+ });
+
+ modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("FileInfoID");
+
+ b.Property("Filename")
+ .IsRequired();
+
+ b.Property("SkinInfoID");
+
+ b.HasKey("ID");
+
+ b.HasIndex("FileInfoID");
+
+ b.HasIndex("SkinInfoID");
+
+ b.ToTable("SkinFileInfo");
+ });
+
+ modelBuilder.Entity("osu.Game.Skinning.SkinInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Creator");
+
+ b.Property("DeletePending");
+
+ b.Property("Name");
+
+ b.HasKey("ID");
+
+ b.ToTable("SkinInfo");
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b =>
+ {
+ b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty")
+ .WithMany()
+ .HasForeignKey("BaseDifficultyID")
+ .OnDelete(DeleteBehavior.Cascade);
+
+ b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet")
+ .WithMany("Beatmaps")
+ .HasForeignKey("BeatmapSetInfoID")
+ .OnDelete(DeleteBehavior.Cascade);
+
+ b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata")
+ .WithMany("Beatmaps")
+ .HasForeignKey("MetadataID");
+
+ b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset")
+ .WithMany()
+ .HasForeignKey("RulesetID")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b =>
+ {
+ b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo")
+ .WithMany("Files")
+ .HasForeignKey("BeatmapSetInfoID")
+ .OnDelete(DeleteBehavior.Cascade);
+
+ b.HasOne("osu.Game.IO.FileInfo", "FileInfo")
+ .WithMany()
+ .HasForeignKey("FileInfoID")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b =>
+ {
+ b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata")
+ .WithMany("BeatmapSets")
+ .HasForeignKey("MetadataID");
+ });
+
+ modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b =>
+ {
+ b.HasOne("osu.Game.IO.FileInfo", "FileInfo")
+ .WithMany()
+ .HasForeignKey("FileInfoID")
+ .OnDelete(DeleteBehavior.Cascade);
+
+ b.HasOne("osu.Game.Skinning.SkinInfo")
+ .WithMany("Files")
+ .HasForeignKey("SkinInfoID")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/osu.Game/Migrations/20180913080842_AddRankStatus.cs b/osu.Game/Migrations/20180913080842_AddRankStatus.cs
new file mode 100644
index 0000000000..bba4944bb7
--- /dev/null
+++ b/osu.Game/Migrations/20180913080842_AddRankStatus.cs
@@ -0,0 +1,33 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace osu.Game.Migrations
+{
+ public partial class AddRankStatus : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AddColumn(
+ name: "Status",
+ table: "BeatmapSetInfo",
+ nullable: false,
+ defaultValue: -3); // NONE
+
+ migrationBuilder.AddColumn(
+ name: "Status",
+ table: "BeatmapInfo",
+ nullable: false,
+ defaultValue: -3); // NONE
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropColumn(
+ name: "Status",
+ table: "BeatmapSetInfo");
+
+ migrationBuilder.DropColumn(
+ name: "Status",
+ table: "BeatmapInfo");
+ }
+ }
+}
diff --git a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs
index 6dbeaed62f..fde5c9fd82 100644
--- a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs
+++ b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs
@@ -1,7 +1,8 @@
//
-
+using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using osu.Game.Database;
namespace osu.Game.Migrations
@@ -13,7 +14,7 @@ namespace osu.Game.Migrations
{
#pragma warning disable 612, 618
modelBuilder
- .HasAnnotation("ProductVersion", "2.1.1-rtm-30846");
+ .HasAnnotation("ProductVersion", "2.1.2-rtm-30932");
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b =>
{
@@ -78,6 +79,8 @@ namespace osu.Game.Migrations
b.Property("StarDifficulty");
+ b.Property("Status");
+
b.Property("StoredBookmarks");
b.Property("TimelineZoom");
@@ -173,6 +176,8 @@ namespace osu.Game.Migrations
b.Property("Protected");
+ b.Property("Status");
+
b.HasKey("ID");
b.HasIndex("DeletePending");
diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs
index 99e4392374..193ccf1f6b 100644
--- a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs
+++ b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs
@@ -15,6 +15,12 @@ namespace osu.Game.Online.API.Requests.Responses
[JsonProperty(@"beatmapset_id")]
public int OnlineBeatmapSetID { get; set; }
+ [JsonProperty(@"status")]
+ public BeatmapSetOnlineStatus Status { get; set; }
+
+ [JsonProperty(@"beatmapset")]
+ public APIBeatmapSet BeatmapSet { get; set; }
+
[JsonProperty(@"playcount")]
private int playCount { get; set; }
@@ -59,11 +65,13 @@ namespace osu.Game.Online.API.Requests.Responses
Ruleset = rulesets.GetRuleset(ruleset),
StarDifficulty = starDifficulty,
OnlineBeatmapID = OnlineBeatmapID,
+ Version = version,
+ Status = Status,
BeatmapSet = new BeatmapSetInfo
{
OnlineBeatmapSetID = OnlineBeatmapSetID,
+ Status = BeatmapSet?.Status ?? BeatmapSetOnlineStatus.None
},
- Version = version,
BaseDifficulty = new BeatmapDifficulty
{
DrainRate = drainRate,
diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs
index bbaaa0c756..8446285070 100644
--- a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs
+++ b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs
@@ -20,10 +20,13 @@ namespace osu.Game.Online.API.Requests.Responses
[JsonProperty(@"id")]
public int? OnlineBeatmapSetID
{
- get { return onlineBeatmapSetID; }
- set { onlineBeatmapSetID = value > 0 ? value : null; }
+ get => onlineBeatmapSetID;
+ set => onlineBeatmapSetID = value > 0 ? value : null;
}
+ [JsonProperty(@"status")]
+ public BeatmapSetOnlineStatus Status { get; set; }
+
[JsonProperty(@"preview_url")]
private string preview { get; set; }
@@ -42,9 +45,6 @@ namespace osu.Game.Online.API.Requests.Responses
[JsonProperty(@"storyboard")]
private bool hasStoryboard { get; set; }
- [JsonProperty(@"status")]
- private BeatmapSetOnlineStatus status { get; set; }
-
[JsonProperty(@"submitted_date")]
private DateTimeOffset submitted { get; set; }
@@ -57,7 +57,7 @@ namespace osu.Game.Online.API.Requests.Responses
[JsonProperty(@"user_id")]
private long creatorId
{
- set { Author.Id = value; }
+ set => Author.Id = value;
}
[JsonProperty(@"beatmaps")]
@@ -69,6 +69,7 @@ namespace osu.Game.Online.API.Requests.Responses
{
OnlineBeatmapSetID = OnlineBeatmapSetID,
Metadata = this,
+ Status = Status,
OnlineInfo = new BeatmapSetOnlineInfo
{
Covers = covers,
@@ -76,7 +77,7 @@ namespace osu.Game.Online.API.Requests.Responses
PlayCount = playCount,
FavouriteCount = favouriteCount,
BPM = bpm,
- Status = status,
+ Status = Status,
HasVideo = hasVideo,
HasStoryboard = hasStoryboard,
Submitted = submitted,
diff --git a/osu.Game/Online/Chat/InfoMessage.cs b/osu.Game/Online/Chat/InfoMessage.cs
index 2ff901deb1..103a999591 100644
--- a/osu.Game/Online/Chat/InfoMessage.cs
+++ b/osu.Game/Online/Chat/InfoMessage.cs
@@ -15,11 +15,7 @@ namespace osu.Game.Online.Chat
Timestamp = DateTimeOffset.Now;
Content = message;
- Sender = new User
- {
- Username = @"system",
- Colour = @"0000ff",
- };
+ Sender = User.SYSTEM_USER;
}
}
}
diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs
index eb5532800f..b12d2a3d3a 100644
--- a/osu.Game/OsuGame.cs
+++ b/osu.Game/OsuGame.cs
@@ -359,7 +359,7 @@ namespace osu.Game
loadComponentSingleFile(beatmapSetOverlay = new BeatmapSetOverlay { Depth = -3 }, mainContent.Add);
loadComponentSingleFile(musicController = new MusicController
{
- Depth = -4,
+ Depth = -5,
Position = new Vector2(0, Toolbar.HEIGHT),
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs
index 18391c1177..b3072a02d9 100644
--- a/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs
+++ b/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs
@@ -66,7 +66,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
},
};
- Action = () => playButton.TriggerOnClick();
+ Action = () => playButton.Click();
Playing.ValueChanged += newValue => progress.FadeTo(newValue ? 1 : 0, 100);
}
diff --git a/osu.Game/Overlays/BeatmapSet/Header.cs b/osu.Game/Overlays/BeatmapSet/Header.cs
index afba99f928..6f01fae92d 100644
--- a/osu.Game/Overlays/BeatmapSet/Header.cs
+++ b/osu.Game/Overlays/BeatmapSet/Header.cs
@@ -230,10 +230,12 @@ namespace osu.Game.Overlays.BeatmapSet
Spacing = new Vector2(10),
Children = new Drawable[]
{
- onlineStatusPill = new BeatmapSetOnlineStatusPill(14, new MarginPadding { Horizontal = 25, Vertical = 8 })
+ onlineStatusPill = new BeatmapSetOnlineStatusPill
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
+ TextSize = 14,
+ TextPadding = new MarginPadding { Horizontal = 25, Vertical = 8 }
},
Details = new Details(),
},
diff --git a/osu.Game/Overlays/Chat/ChatTabControl.cs b/osu.Game/Overlays/Chat/ChatTabControl.cs
index 2e3c9f9c5f..d9327e73e8 100644
--- a/osu.Game/Overlays/Chat/ChatTabControl.cs
+++ b/osu.Game/Overlays/Chat/ChatTabControl.cs
@@ -13,6 +13,7 @@ using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.Chat;
using OpenTK;
+using OpenTK.Input;
using OpenTK.Graphics;
using osu.Framework.Configuration;
using System;
@@ -143,6 +144,17 @@ namespace osu.Game.Overlays.Chat
textBold.FadeOut(transition_length, Easing.OutQuint);
}
+ protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
+ {
+ if (args.Button == MouseButton.Middle)
+ {
+ closeButton.Action();
+ return true;
+ }
+
+ return false;
+ }
+
protected override bool OnHover(InputState state)
{
if (IsRemovable)
diff --git a/osu.Game/Overlays/Dialog/PopupDialog.cs b/osu.Game/Overlays/Dialog/PopupDialog.cs
index c9c90b4555..3f79fa98e5 100644
--- a/osu.Game/Overlays/Dialog/PopupDialog.cs
+++ b/osu.Game/Overlays/Dialog/PopupDialog.cs
@@ -199,7 +199,7 @@ namespace osu.Game.Overlays.Dialog
switch (action)
{
case GlobalAction.Select:
- Buttons.OfType().FirstOrDefault()?.TriggerOnClick();
+ Buttons.OfType().FirstOrDefault()?.Click();
return true;
}
@@ -252,7 +252,7 @@ namespace osu.Game.Overlays.Dialog
if (!actionInvoked)
// In the case a user did not choose an action before a hide was triggered, press the last button.
// This is presumed to always be a sane default "cancel" action.
- buttonsContainer.Last().TriggerOnClick();
+ buttonsContainer.Last().Click();
base.PopOut();
content.FadeOut(EXIT_DURATION, Easing.InSine);
@@ -261,7 +261,7 @@ namespace osu.Game.Overlays.Dialog
private void pressButtonAtIndex(int index)
{
if (index < Buttons.Count())
- Buttons.Skip(index).First().TriggerOnClick();
+ Buttons.Skip(index).First().Click();
}
}
}
diff --git a/osu.Game/Overlays/Direct/DirectGridPanel.cs b/osu.Game/Overlays/Direct/DirectGridPanel.cs
index eb940bff60..44b6a75d3c 100644
--- a/osu.Game/Overlays/Direct/DirectGridPanel.cs
+++ b/osu.Game/Overlays/Direct/DirectGridPanel.cs
@@ -7,11 +7,11 @@ using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Localisation;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.States;
+using osu.Framework.Localisation;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
@@ -44,7 +44,7 @@ namespace osu.Game.Overlays.Direct
}
[BackgroundDependencyLoader]
- private void load(OsuColour colours, LocalisationEngine localisation)
+ private void load(OsuColour colours)
{
Content.CornerRadius = 4;
@@ -74,13 +74,13 @@ namespace osu.Game.Overlays.Direct
{
new OsuSpriteText
{
- Text = localisation.GetUnicodePreference(SetInfo.Metadata.TitleUnicode, SetInfo.Metadata.Title),
+ Text = new LocalisedString((SetInfo.Metadata.TitleUnicode, SetInfo.Metadata.Title)),
TextSize = 18,
Font = @"Exo2.0-BoldItalic",
},
new OsuSpriteText
{
- Text = localisation.GetUnicodePreference(SetInfo.Metadata.ArtistUnicode, SetInfo.Metadata.Artist),
+ Text = new LocalisedString((SetInfo.Metadata.ArtistUnicode, SetInfo.Metadata.Artist)),
Font = @"Exo2.0-BoldItalic",
},
},
@@ -217,8 +217,10 @@ namespace osu.Game.Overlays.Direct
statusContainer.Add(new IconPill(FontAwesome.fa_image));
}
- statusContainer.Add(new BeatmapSetOnlineStatusPill(12, new MarginPadding { Horizontal = 10, Vertical = 5 })
+ statusContainer.Add(new BeatmapSetOnlineStatusPill
{
+ TextSize = 12,
+ TextPadding = new MarginPadding { Horizontal = 10, Vertical = 5 },
Status = SetInfo.OnlineInfo?.Status ?? BeatmapSetOnlineStatus.None,
});
diff --git a/osu.Game/Overlays/Direct/DirectListPanel.cs b/osu.Game/Overlays/Direct/DirectListPanel.cs
index 850ead37f6..6cb5ebad4e 100644
--- a/osu.Game/Overlays/Direct/DirectListPanel.cs
+++ b/osu.Game/Overlays/Direct/DirectListPanel.cs
@@ -10,8 +10,8 @@ using osu.Framework.Graphics.Colour;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Framework.Allocation;
-using osu.Framework.Localisation;
using osu.Framework.Graphics.Shapes;
+using osu.Framework.Localisation;
using osu.Game.Beatmaps;
namespace osu.Game.Overlays.Direct
@@ -39,7 +39,7 @@ namespace osu.Game.Overlays.Direct
}
[BackgroundDependencyLoader]
- private void load(LocalisationEngine localisation, OsuColour colours)
+ private void load(OsuColour colours)
{
Content.CornerRadius = 5;
@@ -94,13 +94,13 @@ namespace osu.Game.Overlays.Direct
{
new OsuSpriteText
{
- Current = localisation.GetUnicodePreference(SetInfo.Metadata.TitleUnicode, SetInfo.Metadata.Title),
+ Text = new LocalisedString((SetInfo.Metadata.TitleUnicode, SetInfo.Metadata.Title)),
TextSize = 18,
Font = @"Exo2.0-BoldItalic",
},
new OsuSpriteText
{
- Current = localisation.GetUnicodePreference(SetInfo.Metadata.ArtistUnicode, SetInfo.Metadata.Artist),
+ Text = new LocalisedString((SetInfo.Metadata.ArtistUnicode, SetInfo.Metadata.Artist)),
Font = @"Exo2.0-BoldItalic",
},
}
diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs
index 86baaf3905..d480bedc5e 100644
--- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs
+++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs
@@ -50,7 +50,7 @@ namespace osu.Game.Overlays.KeyBinding
private FillFlowContainer buttons;
- public IEnumerable FilterTerms => bindings.Select(b => b.KeyCombination.ReadableString()).Prepend(text.Text);
+ public IEnumerable FilterTerms => bindings.Select(b => b.KeyCombination.ReadableString()).Prepend((string)text.Text);
public KeyBindingRow(object action, IEnumerable bindings)
{
diff --git a/osu.Game/Overlays/MainSettings.cs b/osu.Game/Overlays/MainSettings.cs
index 6e8b4494dc..b22904e724 100644
--- a/osu.Game/Overlays/MainSettings.cs
+++ b/osu.Game/Overlays/MainSettings.cs
@@ -155,7 +155,7 @@ namespace osu.Game.Overlays
switch (action)
{
case GlobalAction.Back:
- TriggerOnClick();
+ Click();
return true;
}
diff --git a/osu.Game/Overlays/Music/PlaylistItem.cs b/osu.Game/Overlays/Music/PlaylistItem.cs
index 62c9020160..ee3f22290b 100644
--- a/osu.Game/Overlays/Music/PlaylistItem.cs
+++ b/osu.Game/Overlays/Music/PlaylistItem.cs
@@ -28,8 +28,8 @@ namespace osu.Game.Overlays.Music
private SpriteIcon handle;
private TextFlowContainer text;
private IEnumerable titleSprites;
- private UnicodeBindableString titleBind;
- private UnicodeBindableString artistBind;
+ private ILocalisedBindableString titleBind;
+ private ILocalisedBindableString artistBind;
public readonly BeatmapSetInfo BeatmapSetInfo;
@@ -74,7 +74,7 @@ namespace osu.Game.Overlays.Music
}
[BackgroundDependencyLoader]
- private void load(OsuColour colours, LocalisationEngine localisation)
+ private void load(OsuColour colours, LocalisationManager localisation)
{
hoverColour = colours.Yellow;
artistColour = colours.Gray9;
@@ -97,11 +97,10 @@ namespace osu.Game.Overlays.Music
},
};
- titleBind = localisation.GetUnicodePreference(metadata.TitleUnicode, metadata.Title);
- artistBind = localisation.GetUnicodePreference(metadata.ArtistUnicode, metadata.Artist);
+ titleBind = localisation.GetLocalisedString(new LocalisedString((metadata.TitleUnicode, metadata.Title)));
+ artistBind = localisation.GetLocalisedString(new LocalisedString((metadata.ArtistUnicode, metadata.Artist)));
- artistBind.ValueChanged += newText => recreateText();
- artistBind.TriggerChange();
+ artistBind.BindValueChanged(newText => recreateText(), true);
}
private void recreateText()
diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs
index 886b5fb95b..5cccb2b0aa 100644
--- a/osu.Game/Overlays/MusicController.cs
+++ b/osu.Game/Overlays/MusicController.cs
@@ -47,7 +47,6 @@ namespace osu.Game.Overlays
private PlaylistOverlay playlist;
private BeatmapManager beatmaps;
- private LocalisationEngine localisation;
private List beatmapSets;
private BeatmapSetInfo currentSet;
@@ -67,11 +66,10 @@ namespace osu.Game.Overlays
}
[BackgroundDependencyLoader]
- private void load(BindableBeatmap beatmap, BeatmapManager beatmaps, OsuColour colours, LocalisationEngine localisation)
+ private void load(BindableBeatmap beatmap, BeatmapManager beatmaps, OsuColour colours)
{
this.beatmap.BindTo(beatmap);
this.beatmaps = beatmaps;
- this.localisation = localisation;
Children = new Drawable[]
{
@@ -351,17 +349,14 @@ namespace osu.Game.Overlays
{
if (beatmap?.Beatmap == null) //this is not needed if a placeholder exists
{
- title.Current = null;
title.Text = @"Nothing to play";
-
- artist.Current = null;
artist.Text = @"Nothing to play";
}
else
{
BeatmapMetadata metadata = beatmap.Metadata;
- title.Current = localisation.GetUnicodePreference(metadata.TitleUnicode, metadata.Title);
- artist.Current = localisation.GetUnicodePreference(metadata.ArtistUnicode, metadata.Artist);
+ title.Text = new LocalisedString((metadata.TitleUnicode, metadata.Title));
+ artist.Text = new LocalisedString((metadata.ArtistUnicode, metadata.Artist));
}
});
diff --git a/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs b/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs
index 1a1f13933d..4278598bf5 100644
--- a/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs
+++ b/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs
@@ -29,7 +29,7 @@ namespace osu.Game.Overlays.Profile.Sections
public string TooltipText { get; }
[BackgroundDependencyLoader(true)]
- private void load(LocalisationEngine locale, BeatmapSetOverlay beatmapSetOverlay)
+ private void load(BeatmapSetOverlay beatmapSetOverlay)
{
Action = () =>
{
@@ -46,16 +46,14 @@ namespace osu.Game.Overlays.Profile.Sections
{
new OsuSpriteText
{
- Current = locale.GetUnicodePreference(
- $"{beatmap.Metadata.TitleUnicode ?? beatmap.Metadata.Title} [{beatmap.Version}] ",
- $"{beatmap.Metadata.Title ?? beatmap.Metadata.TitleUnicode} [{beatmap.Version}] "
- ),
+ Text = new LocalisedString(($"{beatmap.Metadata.TitleUnicode ?? beatmap.Metadata.Title} [{beatmap.Version}] ",
+ $"{beatmap.Metadata.Title ?? beatmap.Metadata.TitleUnicode} [{beatmap.Version}] ")),
TextSize = 15,
Font = "Exo2.0-SemiBoldItalic",
},
new OsuSpriteText
{
- Current = locale.GetUnicodePreference(beatmap.Metadata.ArtistUnicode, beatmap.Metadata.Artist),
+ Text = new LocalisedString((beatmap.Metadata.ArtistUnicode, beatmap.Metadata.Artist)),
TextSize = 12,
Padding = new MarginPadding { Top = 3 },
Font = "Exo2.0-RegularItalic",
diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs
index 4a8164c6df..df9370d0d8 100644
--- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs
+++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs
@@ -35,6 +35,8 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
letterboxing = config.GetBindable(FrameworkSetting.Letterboxing);
sizeFullscreen = config.GetBindable(FrameworkSetting.SizeFullscreen);
+ Container resolutionSettingsContainer;
+
Children = new Drawable[]
{
windowModeDropdown = new SettingsEnumDropdown
@@ -42,12 +44,10 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
LabelText = "Screen mode",
Bindable = config.GetBindable(FrameworkSetting.WindowMode),
},
- resolutionDropdown = new SettingsDropdown
+ resolutionSettingsContainer = new Container
{
- LabelText = "Resolution",
- ShowsDefaultIndicator = false,
- Items = getResolutions(),
- Bindable = sizeFullscreen
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y
},
new SettingsCheckbox
{
@@ -81,16 +81,29 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
},
};
- windowModeDropdown.Bindable.BindValueChanged(windowMode =>
+ var resolutions = getResolutions();
+
+ if (resolutions.Count > 1)
{
- if (windowMode == WindowMode.Fullscreen)
+ resolutionSettingsContainer.Child = resolutionDropdown = new SettingsDropdown
{
- resolutionDropdown.Show();
- sizeFullscreen.TriggerChange();
- }
- else
- resolutionDropdown.Hide();
- }, true);
+ LabelText = "Resolution",
+ ShowsDefaultIndicator = false,
+ Items = resolutions,
+ Bindable = sizeFullscreen
+ };
+
+ windowModeDropdown.Bindable.BindValueChanged(windowMode =>
+ {
+ if (windowMode == WindowMode.Fullscreen)
+ {
+ resolutionDropdown.Show();
+ sizeFullscreen.TriggerChange();
+ }
+ else
+ resolutionDropdown.Hide();
+ });
+ }
letterboxing.BindValueChanged(isVisible =>
{
@@ -102,7 +115,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
}, true);
}
- private IEnumerable> getResolutions()
+ private IReadOnlyList> getResolutions()
{
var resolutions = new KeyValuePair("Default", new Size(9999, 9999)).Yield();
@@ -112,8 +125,8 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
.OrderByDescending(r => r.Width)
.ThenByDescending(r => r.Height)
.Select(res => new KeyValuePair($"{res.Width}x{res.Height}", new Size(res.Width, res.Height)))
- .Distinct()).ToList();
- return resolutions;
+ .Distinct());
+ return resolutions.ToList();
}
}
}
diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs
index 57e9a528d2..835ec808bc 100644
--- a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs
+++ b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs
@@ -13,57 +13,59 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
{
public class GeneralSettings : SettingsSubsection
{
- private TriangleButton importButton;
- private TriangleButton deleteButton;
+ protected override string Header => "General";
+
+ private TriangleButton importBeatmapsButton;
+ private TriangleButton importSkinsButton;
+ private TriangleButton deleteSkinsButton;
+ private TriangleButton deleteBeatmapsButton;
private TriangleButton restoreButton;
private TriangleButton undeleteButton;
- protected override string Header => "General";
-
[BackgroundDependencyLoader]
private void load(BeatmapManager beatmaps, SkinManager skins, DialogOverlay dialogOverlay)
{
Children = new Drawable[]
{
- importButton = new SettingsButton
+ importBeatmapsButton = new SettingsButton
{
Text = "Import beatmaps from stable",
Action = () =>
{
- importButton.Enabled.Value = false;
- beatmaps.ImportFromStableAsync().ContinueWith(t => Schedule(() => importButton.Enabled.Value = true));
+ importBeatmapsButton.Enabled.Value = false;
+ beatmaps.ImportFromStableAsync().ContinueWith(t => Schedule(() => importBeatmapsButton.Enabled.Value = true));
}
},
- deleteButton = new DangerousSettingsButton
+ deleteBeatmapsButton = new DangerousSettingsButton
{
Text = "Delete ALL beatmaps",
Action = () =>
{
dialogOverlay?.Push(new DeleteAllBeatmapsDialog(() =>
{
- deleteButton.Enabled.Value = false;
- Task.Run(() => beatmaps.Delete(beatmaps.GetAllUsableBeatmapSets())).ContinueWith(t => Schedule(() => deleteButton.Enabled.Value = true));
+ deleteBeatmapsButton.Enabled.Value = false;
+ Task.Run(() => beatmaps.Delete(beatmaps.GetAllUsableBeatmapSets())).ContinueWith(t => Schedule(() => deleteBeatmapsButton.Enabled.Value = true));
}));
}
},
- importButton = new SettingsButton
+ importSkinsButton = new SettingsButton
{
Text = "Import skins from stable",
Action = () =>
{
- importButton.Enabled.Value = false;
- skins.ImportFromStableAsync().ContinueWith(t => Schedule(() => importButton.Enabled.Value = true));
+ importSkinsButton.Enabled.Value = false;
+ skins.ImportFromStableAsync().ContinueWith(t => Schedule(() => importSkinsButton.Enabled.Value = true));
}
},
- deleteButton = new DangerousSettingsButton
+ deleteSkinsButton = new DangerousSettingsButton
{
Text = "Delete ALL skins",
Action = () =>
{
dialogOverlay?.Push(new DeleteAllBeatmapsDialog(() =>
{
- deleteButton.Enabled.Value = false;
- Task.Run(() => skins.Delete(skins.GetAllUserSkins())).ContinueWith(t => Schedule(() => deleteButton.Enabled.Value = true));
+ deleteSkinsButton.Enabled.Value = false;
+ Task.Run(() => skins.Delete(skins.GetAllUserSkins())).ContinueWith(t => Schedule(() => deleteSkinsButton.Enabled.Value = true));
}));
}
},
diff --git a/osu.Game/Overlays/UserProfileOverlay.cs b/osu.Game/Overlays/UserProfileOverlay.cs
index ea077ff645..c106446fe0 100644
--- a/osu.Game/Overlays/UserProfileOverlay.cs
+++ b/osu.Game/Overlays/UserProfileOverlay.cs
@@ -77,9 +77,11 @@ namespace osu.Game.Overlays
public void ShowUser(User user, bool fetchOnline = true)
{
+ if (user == User.SYSTEM_USER) return;
+
Show();
- if (user.Id == Header?.User.Id)
+ if (user.Id == Header?.User?.Id)
return;
userReq?.Cancel();
diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
index 7e3e955740..a274d9b12f 100644
--- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
+++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
@@ -7,6 +7,8 @@ using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Extensions.TypeExtensions;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Primitives;
using osu.Game.Audio;
using osu.Game.Graphics;
using osu.Game.Rulesets.Judgements;
@@ -165,6 +167,14 @@ namespace osu.Game.Rulesets.Objects.Drawables
}
}
+ public override bool UpdateSubTreeMasking(Drawable source, RectangleF maskingBounds)
+ {
+ if (!AllJudged)
+ return false;
+
+ return base.UpdateSubTreeMasking(source, maskingBounds);
+ }
+
protected override void UpdateAfterChildren()
{
base.UpdateAfterChildren();
diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs
index b05efce146..af1dc98fec 100644
--- a/osu.Game/Rulesets/UI/RulesetInputManager.cs
+++ b/osu.Game/Rulesets/UI/RulesetInputManager.cs
@@ -1,7 +1,6 @@
// Copyright (c) 2007-2018 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
@@ -10,7 +9,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Input;
using osu.Framework.Input.Bindings;
using osu.Framework.Input.EventArgs;
-using osu.Framework.Input.StateChanges;
+using osu.Framework.Input.StateChanges.Events;
using osu.Framework.Input.States;
using osu.Framework.Timing;
using osu.Game.Configuration;
@@ -56,33 +55,20 @@ namespace osu.Game.Rulesets.UI
#region Action mapping (for replays)
- private List lastPressedActions = new List();
-
- public override void HandleCustomInput(InputState state, IInput input)
+ public override void HandleInputStateChange(InputStateChangeEvent inputStateChange)
{
- if (!(input is ReplayState replayState))
+ if (inputStateChange is ReplayStateChangeEvent replayStateChanged)
{
- base.HandleCustomInput(state, input);
- return;
- }
+ foreach (var action in replayStateChanged.ReleasedActions)
+ KeyBindingContainer.TriggerReleased(action);
- if (state is RulesetInputManagerInputState inputState)
+ foreach (var action in replayStateChanged.PressedActions)
+ KeyBindingContainer.TriggerPressed(action);
+ }
+ else
{
- inputState.LastReplayState = replayState;
+ base.HandleInputStateChange(inputStateChange);
}
-
- // Here we handle states specifically coming from a replay source.
- // These have extra action information rather than keyboard keys or mouse buttons.
-
- List newActions = replayState.PressedActions;
-
- foreach (var released in lastPressedActions.Except(newActions))
- KeyBindingContainer.TriggerReleased(released);
-
- foreach (var pressed in newActions.Except(lastPressedActions))
- KeyBindingContainer.TriggerPressed(pressed);
-
- lastPressedActions = newActions;
}
#endregion
diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs
index 78561cecbf..e326cdb0ca 100644
--- a/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs
+++ b/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs
@@ -4,19 +4,14 @@
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Textures;
-using osu.Framework.Graphics.Transforms;
-using OpenTK;
using osu.Game.Beatmaps;
using osu.Game.Graphics.Backgrounds;
namespace osu.Game.Screens.Backgrounds
{
- public class BackgroundScreenBeatmap : BackgroundScreen
+ public class BackgroundScreenBeatmap : BlurrableBackgroundScreen
{
- private Background background;
-
private WorkingBeatmap beatmap;
- private Vector2 blurTarget;
public WorkingBeatmap Beatmap
{
@@ -30,21 +25,21 @@ namespace osu.Game.Screens.Backgrounds
Schedule(() =>
{
- LoadComponentAsync(new BeatmapBackground(beatmap), b =>
+ LoadComponentAsync(new BeatmapBackground(beatmap), b => Schedule(() =>
{
float newDepth = 0;
- if (background != null)
+ if (Background != null)
{
- newDepth = background.Depth + 1;
- background.FinishTransforms();
- background.FadeOut(250);
- background.Expire();
+ newDepth = Background.Depth + 1;
+ Background.FinishTransforms();
+ Background.FadeOut(250);
+ Background.Expire();
}
b.Depth = newDepth;
- Add(background = b);
- background.BlurSigma = blurTarget;
- });
+ Add(Background = b);
+ Background.BlurSigma = BlurTarget;
+ }));
});
}
}
@@ -54,9 +49,6 @@ namespace osu.Game.Screens.Backgrounds
Beatmap = beatmap;
}
- public TransformSequence BlurTo(Vector2 sigma, double duration, Easing easing = Easing.None)
- => background?.BlurTo(blurTarget = sigma, duration, easing);
-
public override bool Equals(BackgroundScreen other)
{
var otherBeatmapBackground = other as BackgroundScreenBeatmap;
diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs
index 38df9b13ef..989883c8b3 100644
--- a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs
+++ b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs
@@ -3,32 +3,32 @@
using osu.Framework.Allocation;
using osu.Framework.Graphics;
+using osu.Framework.MathUtils;
using osu.Framework.Threading;
using osu.Game.Graphics.Backgrounds;
namespace osu.Game.Screens.Backgrounds
{
- public class BackgroundScreenDefault : BackgroundScreen
+ public class BackgroundScreenDefault : BlurrableBackgroundScreen
{
private int currentDisplay;
private const int background_count = 5;
private string backgroundName => $@"Menu/menu-background-{currentDisplay % background_count + 1}";
- private Background current;
-
[BackgroundDependencyLoader]
private void load()
{
+ currentDisplay = RNG.Next(0, background_count);
display(new Background(backgroundName));
}
private void display(Background newBackground)
{
- current?.FadeOut(800, Easing.InOutSine);
- current?.Expire();
+ Background?.FadeOut(800, Easing.InOutSine);
+ Background?.Expire();
- Add(current = newBackground);
+ Add(Background = newBackground);
currentDisplay++;
}
diff --git a/osu.Game/Screens/BlurrableBackgroundScreen.cs b/osu.Game/Screens/BlurrableBackgroundScreen.cs
new file mode 100644
index 0000000000..92d32badc4
--- /dev/null
+++ b/osu.Game/Screens/BlurrableBackgroundScreen.cs
@@ -0,0 +1,20 @@
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Transforms;
+using osu.Game.Graphics.Backgrounds;
+using OpenTK;
+
+namespace osu.Game.Screens
+{
+ public abstract class BlurrableBackgroundScreen : BackgroundScreen
+ {
+ protected Background Background;
+
+ protected Vector2 BlurTarget;
+
+ public TransformSequence BlurTo(Vector2 sigma, double duration, Easing easing = Easing.None)
+ => Background?.BlurTo(BlurTarget = sigma, duration, easing);
+ }
+}
diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs
index fa9f6ceb8b..015557fa82 100644
--- a/osu.Game/Screens/Menu/ButtonSystem.cs
+++ b/osu.Game/Screens/Menu/ButtonSystem.cs
@@ -115,7 +115,7 @@ namespace osu.Game.Screens.Menu
case GlobalAction.Back:
return goBack();
case GlobalAction.Select:
- logo?.TriggerOnClick();
+ logo?.Click();
return true;
default:
return false;
@@ -133,7 +133,7 @@ namespace osu.Game.Screens.Menu
sampleBack?.Play();
return true;
case ButtonSystemState.Play:
- backButton.TriggerOnClick();
+ backButton.Click();
return true;
default:
return false;
@@ -150,10 +150,10 @@ namespace osu.Game.Screens.Menu
State = ButtonSystemState.TopLevel;
return true;
case ButtonSystemState.TopLevel:
- buttonsTopLevel.First().TriggerOnClick();
+ buttonsTopLevel.First().Click();
return false;
case ButtonSystemState.Play:
- buttonsPlay.First().TriggerOnClick();
+ buttonsPlay.First().Click();
return false;
}
}
diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs
index 7e97859be6..2dd6e1d7e1 100644
--- a/osu.Game/Screens/Menu/MainMenu.cs
+++ b/osu.Game/Screens/Menu/MainMenu.cs
@@ -10,6 +10,7 @@ using osu.Framework.Input.EventArgs;
using osu.Framework.Input.States;
using osu.Framework.Screens;
using osu.Game.Beatmaps;
+using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Screens.Backgrounds;
using osu.Game.Screens.Charts;
@@ -64,6 +65,20 @@ namespace osu.Game.Screens.Menu
},
sideFlashes = new MenuSideFlashes(),
};
+
+ buttons.StateChanged += state =>
+ {
+ switch (state)
+ {
+ case ButtonSystemState.Initial:
+ case ButtonSystemState.Exit:
+ background.FadeColour(Color4.White, 500, Easing.OutSine);
+ break;
+ default:
+ background.FadeColour(OsuColour.Gray(0.8f), 500, Easing.OutSine);
+ break;
+ }
+ };
}
[BackgroundDependencyLoader(true)]
diff --git a/osu.Game/Screens/Menu/OsuLogo.cs b/osu.Game/Screens/Menu/OsuLogo.cs
index f0f765a4c9..5ad6427fd8 100644
--- a/osu.Game/Screens/Menu/OsuLogo.cs
+++ b/osu.Game/Screens/Menu/OsuLogo.cs
@@ -84,11 +84,10 @@ namespace osu.Game.Screens.Menu
private const double early_activation = 60;
+ public override bool IsPresent => base.IsPresent || Scheduler.HasPendingTasks;
+
public OsuLogo()
{
- // Required to make Schedule calls run in OsuScreen even when we are not visible.
- AlwaysPresent = true;
-
EarlyActivationMilliseconds = early_activation;
Size = new Vector2(default_size);
diff --git a/osu.Game/Screens/Multi/Components/BeatmapTitle.cs b/osu.Game/Screens/Multi/Components/BeatmapTitle.cs
index 42863754c5..6dc59f5cac 100644
--- a/osu.Game/Screens/Multi/Components/BeatmapTitle.cs
+++ b/osu.Game/Screens/Multi/Components/BeatmapTitle.cs
@@ -1,7 +1,6 @@
// Copyright (c) 2007-2018 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Localisation;
@@ -14,8 +13,6 @@ namespace osu.Game.Screens.Multi.Components
{
private readonly OsuSpriteText beatmapTitle, beatmapDash, beatmapArtist;
- private LocalisationEngine localisation;
-
public float TextSize
{
set { beatmapTitle.TextSize = beatmapDash.TextSize = beatmapArtist.TextSize = value; }
@@ -48,12 +45,6 @@ namespace osu.Game.Screens.Multi.Components
};
}
- [BackgroundDependencyLoader]
- private void load(LocalisationEngine localisation)
- {
- this.localisation = localisation;
- }
-
protected override void LoadComplete()
{
base.LoadComplete();
@@ -64,15 +55,14 @@ namespace osu.Game.Screens.Multi.Components
{
if (beatmap == null)
{
- beatmapTitle.Current = beatmapArtist.Current = null;
beatmapTitle.Text = "Changing map";
beatmapDash.Text = beatmapArtist.Text = string.Empty;
}
else
{
- beatmapTitle.Current = localisation.GetUnicodePreference(beatmap.Metadata.TitleUnicode, beatmap.Metadata.Title);
+ beatmapTitle.Text = new LocalisedString((beatmap.Metadata.TitleUnicode, beatmap.Metadata.Title));
beatmapDash.Text = @" - ";
- beatmapArtist.Current = localisation.GetUnicodePreference(beatmap.Metadata.ArtistUnicode, beatmap.Metadata.Artist);
+ beatmapArtist.Text = new LocalisedString((beatmap.Metadata.ArtistUnicode, beatmap.Metadata.Artist));
}
}
}
diff --git a/osu.Game/Screens/Play/GameplayMenuOverlay.cs b/osu.Game/Screens/Play/GameplayMenuOverlay.cs
index 1ca3bc2189..f50b3e9661 100644
--- a/osu.Game/Screens/Play/GameplayMenuOverlay.cs
+++ b/osu.Game/Screens/Play/GameplayMenuOverlay.cs
@@ -38,7 +38,7 @@ namespace osu.Game.Screens.Play
///
/// Action that is invoked when is triggered.
///
- protected virtual Action BackAction => () => InternalButtons.Children.Last().TriggerOnClick();
+ protected virtual Action BackAction => () => InternalButtons.Children.Last().Click();
public abstract string Header { get; }
public abstract string Description { get; }
diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs
index f51ea6fe3e..eb137f5447 100644
--- a/osu.Game/Screens/Play/HUDOverlay.cs
+++ b/osu.Game/Screens/Play/HUDOverlay.cs
@@ -69,7 +69,7 @@ namespace osu.Game.Screens.Play
Direction = FillDirection.Vertical,
Children = new Drawable[]
{
- KeyCounter = CreateKeyCounter(),
+ KeyCounter = CreateKeyCounter(adjustableClock as IFrameBasedClock),
HoldToQuit = CreateQuitButton(),
}
}
@@ -194,12 +194,13 @@ namespace osu.Game.Screens.Play
Margin = new MarginPadding { Top = 20 }
};
- protected virtual KeyCounterCollection CreateKeyCounter() => new KeyCounterCollection
+ protected virtual KeyCounterCollection CreateKeyCounter(IFrameBasedClock offsetClock) => new KeyCounterCollection
{
FadeTime = 50,
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight,
Margin = new MarginPadding(10),
+ AudioClock = offsetClock
};
protected virtual ScoreCounter CreateScoreCounter() => new ScoreCounter(6)
diff --git a/osu.Game/Screens/Play/KeyCounter.cs b/osu.Game/Screens/Play/KeyCounter.cs
index 2c31e61114..d1efe4cab7 100644
--- a/osu.Game/Screens/Play/KeyCounter.cs
+++ b/osu.Game/Screens/Play/KeyCounter.cs
@@ -1,6 +1,8 @@
// Copyright (c) 2007-2018 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+using System.Collections.Generic;
+using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@@ -19,6 +21,9 @@ namespace osu.Game.Screens.Play
private Container textLayer;
private SpriteText countSpriteText;
+ private readonly List states = new List();
+ private KeyCounterState currentState;
+
public bool IsCounting { get; set; } = true;
private int countPresses;
public int CountPresses
@@ -45,7 +50,10 @@ namespace osu.Game.Screens.Play
isLit = value;
updateGlowSprite(value);
if (value && IsCounting)
+ {
CountPresses++;
+ saveState();
+ }
}
}
}
@@ -128,6 +136,32 @@ namespace osu.Game.Screens.Play
}
}
- public void ResetCount() => CountPresses = 0;
+ public void ResetCount()
+ {
+ CountPresses = 0;
+ states.Clear();
+ }
+
+ protected override void Update()
+ {
+ base.Update();
+
+ if (currentState?.Time > Clock.CurrentTime)
+ restoreStateTo(Clock.CurrentTime);
+ }
+
+ private void saveState()
+ {
+ if (currentState == null || currentState.Time < Clock.CurrentTime)
+ states.Add(currentState = new KeyCounterState(Clock.CurrentTime, CountPresses));
+ }
+
+ private void restoreStateTo(double time)
+ {
+ states.RemoveAll(state => state.Time > time);
+
+ currentState = states.LastOrDefault();
+ CountPresses = currentState?.Count ?? 0;
+ }
}
}
diff --git a/osu.Game/Screens/Play/KeyCounterCollection.cs b/osu.Game/Screens/Play/KeyCounterCollection.cs
index 5cb5bb152a..76c102c840 100644
--- a/osu.Game/Screens/Play/KeyCounterCollection.cs
+++ b/osu.Game/Screens/Play/KeyCounterCollection.cs
@@ -3,15 +3,15 @@
using System;
using System.Linq;
+using osu.Framework.Allocation;
+using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using OpenTK.Graphics;
-using osu.Framework.Configuration;
-using osu.Framework.Allocation;
-using osu.Framework.Input.EventArgs;
-using osu.Framework.Input.States;
+using osu.Framework.Input.Events;
+using osu.Framework.Timing;
using osu.Game.Configuration;
using OpenTK;
+using OpenTK.Graphics;
namespace osu.Game.Screens.Play
{
@@ -37,6 +37,9 @@ namespace osu.Game.Screens.Play
key.FadeTime = FadeTime;
key.KeyDownTextColor = KeyDownTextColor;
key.KeyUpTextColor = KeyUpTextColor;
+ // Use the same clock object as SongProgress for saving KeyCounter state
+ if (AudioClock != null)
+ key.Clock = AudioClock;
}
public void ResetCount()
@@ -118,6 +121,8 @@ namespace osu.Game.Screens.Play
public override bool HandleKeyboardInput => receptor == null;
public override bool HandleMouseInput => receptor == null;
+ public IFrameBasedClock AudioClock { get; set; }
+
private Receptor receptor;
public Receptor GetReceptor()
@@ -146,13 +151,18 @@ namespace osu.Game.Screens.Play
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => true;
- protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) => Target.Children.Any(c => c.TriggerOnKeyDown(state, args));
-
- protected override bool OnKeyUp(InputState state, KeyUpEventArgs args) => Target.Children.Any(c => c.TriggerOnKeyUp(state, args));
-
- protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) => Target.Children.Any(c => c.TriggerOnMouseDown(state, args));
-
- protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) => Target.Children.Any(c => c.TriggerOnMouseUp(state, args));
+ protected override bool Handle(UIEvent e)
+ {
+ switch (e)
+ {
+ case KeyDownEvent _:
+ case KeyUpEvent _:
+ case MouseDownEvent _:
+ case MouseUpEvent _:
+ return Target.Children.Any(c => c.TriggerEvent(e));
+ }
+ return base.Handle(e);
+ }
}
}
}
diff --git a/osu.Game/Screens/Play/KeyCounterState.cs b/osu.Game/Screens/Play/KeyCounterState.cs
new file mode 100644
index 0000000000..e5c0703319
--- /dev/null
+++ b/osu.Game/Screens/Play/KeyCounterState.cs
@@ -0,0 +1,17 @@
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+namespace osu.Game.Screens.Play
+{
+ public class KeyCounterState
+ {
+ public KeyCounterState(double time, int count)
+ {
+ Time = time;
+ Count = count;
+ }
+
+ public readonly double Time;
+ public readonly int Count;
+ }
+}
diff --git a/osu.Game/Screens/Play/PauseContainer.cs b/osu.Game/Screens/Play/PauseContainer.cs
index d9677e5daf..25e701294a 100644
--- a/osu.Game/Screens/Play/PauseContainer.cs
+++ b/osu.Game/Screens/Play/PauseContainer.cs
@@ -132,7 +132,7 @@ namespace osu.Game.Screens.Play
public override string Header => "paused";
public override string Description => "you're not going to do what i think you're going to do, are ya?";
- protected override Action BackAction => () => InternalButtons.Children.First().TriggerOnClick();
+ protected override Action BackAction => () => InternalButtons.Children.First().Click();
[BackgroundDependencyLoader]
private void load(OsuColour colours)
diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs
index fd4322c268..05a43b32f0 100644
--- a/osu.Game/Screens/Play/PlayerLoader.cs
+++ b/osu.Game/Screens/Play/PlayerLoader.cs
@@ -290,7 +290,7 @@ namespace osu.Game.Screens.Play
}
[BackgroundDependencyLoader]
- private void load(LocalisationEngine localisation)
+ private void load()
{
var metadata = beatmap?.BeatmapInfo?.Metadata ?? new BeatmapMetadata();
@@ -307,7 +307,7 @@ namespace osu.Game.Screens.Play
{
new OsuSpriteText
{
- Current = localisation.GetUnicodePreference(metadata.TitleUnicode, metadata.Title),
+ Text = new LocalisedString((metadata.TitleUnicode, metadata.Title)),
TextSize = 36,
Font = @"Exo2.0-MediumItalic",
Origin = Anchor.TopCentre,
@@ -315,7 +315,7 @@ namespace osu.Game.Screens.Play
},
new OsuSpriteText
{
- Current = localisation.GetUnicodePreference(metadata.ArtistUnicode, metadata.Artist),
+ Text = new LocalisedString((metadata.ArtistUnicode, metadata.Artist)),
TextSize = 26,
Font = @"Exo2.0-MediumItalic",
Origin = Anchor.TopCentre,
diff --git a/osu.Game/Screens/Play/SkipOverlay.cs b/osu.Game/Screens/Play/SkipOverlay.cs
index 06837c9274..046a00d79b 100644
--- a/osu.Game/Screens/Play/SkipOverlay.cs
+++ b/osu.Game/Screens/Play/SkipOverlay.cs
@@ -141,7 +141,7 @@ namespace osu.Game.Screens.Play
switch (action)
{
case GlobalAction.SkipCutscene:
- button.TriggerOnClick();
+ button.Click();
return true;
}
diff --git a/osu.Game/Screens/Ranking/ResultsPageScore.cs b/osu.Game/Screens/Ranking/ResultsPageScore.cs
index 040458e0eb..58c9cde9c7 100644
--- a/osu.Game/Screens/Ranking/ResultsPageScore.cs
+++ b/osu.Game/Screens/Ranking/ResultsPageScore.cs
@@ -13,7 +13,6 @@ using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
-using osu.Framework.Localisation;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
@@ -24,6 +23,7 @@ using osu.Game.Screens.Select.Leaderboards;
using osu.Game.Users;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Extensions;
+using osu.Framework.Localisation;
namespace osu.Game.Screens.Ranking
{
@@ -328,7 +328,7 @@ namespace osu.Game.Screens.Ranking
}
[BackgroundDependencyLoader]
- private void load(OsuColour colours, LocalisationEngine localisation)
+ private void load(OsuColour colours)
{
title.Colour = artist.Colour = colours.BlueDarker;
versionMapper.Colour = colours.Gray8;
@@ -341,8 +341,8 @@ namespace osu.Game.Screens.Ranking
versionMapper.Text = $"{beatmap.Version} - " + versionMapper.Text;
}
- title.Current = localisation.GetUnicodePreference(beatmap.Metadata.TitleUnicode, beatmap.Metadata.Title);
- artist.Current = localisation.GetUnicodePreference(beatmap.Metadata.ArtistUnicode, beatmap.Metadata.Artist);
+ title.Text = new LocalisedString((beatmap.Metadata.TitleUnicode, beatmap.Metadata.Title));
+ artist.Text = new LocalisedString((beatmap.Metadata.ArtistUnicode, beatmap.Metadata.Artist));
}
}
diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs
index d26702fcf9..4129a9596f 100644
--- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs
+++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs
@@ -127,11 +127,12 @@ namespace osu.Game.Screens.Select
public OsuSpriteText VersionLabel { get; private set; }
public OsuSpriteText TitleLabel { get; private set; }
public OsuSpriteText ArtistLabel { get; private set; }
+ public BeatmapSetOnlineStatusPill StatusPill { get; private set; }
public FillFlowContainer MapperContainer { get; private set; }
public FillFlowContainer InfoLabelContainer { get; private set; }
- private UnicodeBindableString titleBinding;
- private UnicodeBindableString artistBinding;
+ private ILocalisedBindableString titleBinding;
+ private ILocalisedBindableString artistBinding;
private readonly WorkingBeatmap beatmap;
private readonly RulesetInfo ruleset;
@@ -143,7 +144,7 @@ namespace osu.Game.Screens.Select
}
[BackgroundDependencyLoader]
- private void load(LocalisationEngine localisation)
+ private void load(LocalisationManager localisation)
{
var beatmapInfo = beatmap.BeatmapInfo;
var metadata = beatmapInfo.Metadata ?? beatmap.BeatmapSetInfo?.Metadata ?? new BeatmapMetadata();
@@ -152,8 +153,8 @@ namespace osu.Game.Screens.Select
CacheDrawnFrameBuffer = true;
RelativeSizeAxes = Axes.Both;
- titleBinding = localisation.GetUnicodePreference(metadata.TitleUnicode, metadata.Title);
- artistBinding = localisation.GetUnicodePreference(metadata.ArtistUnicode, metadata.Artist);
+ titleBinding = localisation.GetLocalisedString(new LocalisedString((metadata.TitleUnicode, metadata.Title)));
+ artistBinding = localisation.GetLocalisedString(new LocalisedString((metadata.ArtistUnicode, metadata.Artist)));
Children = new Drawable[]
{
@@ -190,7 +191,7 @@ namespace osu.Game.Screens.Select
},
new FillFlowContainer
{
- Name = "Top-aligned metadata",
+ Name = "Topleft-aligned metadata",
Anchor = Anchor.TopLeft,
Origin = Anchor.TopLeft,
Direction = FillDirection.Vertical,
@@ -207,6 +208,24 @@ namespace osu.Game.Screens.Select
}
},
new FillFlowContainer
+ {
+ Name = "Topright-aligned metadata",
+ Anchor = Anchor.TopRight,
+ Origin = Anchor.TopRight,
+ Direction = FillDirection.Vertical,
+ Margin = new MarginPadding { Top = 14, Left = 10, Right = 18, Bottom = 20 },
+ AutoSizeAxes = Axes.Both,
+ Children = new Drawable[]
+ {
+ StatusPill = new BeatmapSetOnlineStatusPill
+ {
+ TextSize = 11,
+ TextPadding = new MarginPadding { Horizontal = 8, Vertical = 2 },
+ Status = beatmapInfo.Status,
+ }
+ }
+ },
+ new FillFlowContainer
{
Name = "Centre-aligned metadata",
Anchor = Anchor.CentreLeft,
@@ -244,8 +263,13 @@ namespace osu.Game.Screens.Select
}
}
};
- artistBinding.ValueChanged += value => setMetadata(metadata.Source);
- artistBinding.TriggerChange();
+
+ titleBinding.BindValueChanged(value => setMetadata(metadata.Source));
+ artistBinding.BindValueChanged(value => setMetadata(metadata.Source), true);
+
+ // no difficulty means it can't have a status to show
+ if (beatmapInfo.Version == null)
+ StatusPill.Hide();
}
private void setMetadata(string source)
diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs
index 23f338b530..ec2622285f 100644
--- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs
+++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs
@@ -38,11 +38,8 @@ namespace osu.Game.Screens.Select.Carousel
}
[BackgroundDependencyLoader(true)]
- private void load(LocalisationEngine localisation, BeatmapManager manager, BeatmapSetOverlay beatmapOverlay, DialogOverlay overlay)
+ private void load(BeatmapManager manager, BeatmapSetOverlay beatmapOverlay, DialogOverlay overlay)
{
- if (localisation == null)
- throw new ArgumentNullException(nameof(localisation));
-
restoreHiddenRequested = s => s.Beatmaps.ForEach(manager.Restore);
dialogOverlay = overlay;
if (beatmapOverlay != null)
@@ -67,22 +64,39 @@ namespace osu.Game.Screens.Select.Carousel
new OsuSpriteText
{
Font = @"Exo2.0-BoldItalic",
- Current = localisation.GetUnicodePreference(beatmapSet.Metadata.TitleUnicode, beatmapSet.Metadata.Title),
+ Text = new LocalisedString((beatmapSet.Metadata.TitleUnicode, beatmapSet.Metadata.Title)),
TextSize = 22,
Shadow = true,
},
new OsuSpriteText
{
Font = @"Exo2.0-SemiBoldItalic",
- Current = localisation.GetUnicodePreference(beatmapSet.Metadata.ArtistUnicode, beatmapSet.Metadata.Artist),
+ Text = new LocalisedString((beatmapSet.Metadata.ArtistUnicode, beatmapSet.Metadata.Artist)),
TextSize = 17,
Shadow = true,
},
- new FillFlowContainer
+ new FillFlowContainer
{
- Margin = new MarginPadding { Top = 5 },
+ Direction = FillDirection.Horizontal,
AutoSizeAxes = Axes.Both,
- Children = ((CarouselBeatmapSet)Item).Beatmaps.Select(b => new FilterableDifficultyIcon(b)).ToList()
+ Margin = new MarginPadding { Top = 5 },
+ Children = new Drawable[]
+ {
+ new BeatmapSetOnlineStatusPill
+ {
+ Origin = Anchor.CentreLeft,
+ Anchor = Anchor.CentreLeft,
+ Margin = new MarginPadding { Right = 5 },
+ TextSize = 11,
+ TextPadding = new MarginPadding { Horizontal = 8, Vertical = 2 },
+ Status = beatmapSet.Status
+ },
+ new FillFlowContainer
+ {
+ AutoSizeAxes = Axes.Both,
+ Children = ((CarouselBeatmapSet)Item).Beatmaps.Select(b => new FilterableDifficultyIcon(b)).ToList()
+ },
+ }
}
}
}
diff --git a/osu.Game/Storyboards/CommandTimeline.cs b/osu.Game/Storyboards/CommandTimeline.cs
index 7de0756dbd..8a032064d3 100644
--- a/osu.Game/Storyboards/CommandTimeline.cs
+++ b/osu.Game/Storyboards/CommandTimeline.cs
@@ -16,10 +16,10 @@ namespace osu.Game.Storyboards
public bool HasCommands => commands.Count > 0;
private Cached startTimeBacking;
- public double StartTime => startTimeBacking.IsValid ? startTimeBacking : (startTimeBacking.Value = HasCommands ? commands.Min(c => c.StartTime) : double.MinValue);
+ public double StartTime => startTimeBacking.IsValid ? startTimeBacking : startTimeBacking.Value = HasCommands ? commands.Min(c => c.StartTime) : double.MinValue;
private Cached endTimeBacking;
- public double EndTime => endTimeBacking.IsValid ? endTimeBacking : (endTimeBacking.Value = HasCommands ? commands.Max(c => c.EndTime) : double.MaxValue);
+ public double EndTime => endTimeBacking.IsValid ? endTimeBacking : endTimeBacking.Value = HasCommands ? commands.Max(c => c.EndTime) : double.MaxValue;
public T StartValue => HasCommands ? commands.OrderBy(c => c.StartTime).First().StartValue : default(T);
public T EndValue => HasCommands ? commands.OrderByDescending(c => c.EndTime).First().EndValue : default(T);
diff --git a/osu.Game/Tests/Visual/TestCasePlayer.cs b/osu.Game/Tests/Visual/TestCasePlayer.cs
index 9afb1dd6cd..9e499cb961 100644
--- a/osu.Game/Tests/Visual/TestCasePlayer.cs
+++ b/osu.Game/Tests/Visual/TestCasePlayer.cs
@@ -54,7 +54,7 @@ namespace osu.Game.Tests.Visual
AddStep(r.Name, () => p = loadPlayerFor(r));
AddUntilStep(() => ContinueCondition(p));
- AddAssert("no leaked beatmaps", () =>
+ AddUntilStep(() =>
{
p = null;
@@ -64,9 +64,9 @@ namespace osu.Game.Tests.Visual
workingWeakReferences.ForEachAlive(_ => count++);
return count == 1;
- });
+ }, "no leaked beatmaps");
- AddAssert("no leaked players", () =>
+ AddUntilStep(() =>
{
GC.Collect();
GC.WaitForPendingFinalizers();
@@ -74,7 +74,7 @@ namespace osu.Game.Tests.Visual
playerWeakReferences.ForEachAlive(_ => count++);
return count == 1;
- });
+ }, "no leaked players");
}
}
}
diff --git a/osu.Game/Users/User.cs b/osu.Game/Users/User.cs
index f42df4023f..6c3d2bfa63 100644
--- a/osu.Game/Users/User.cs
+++ b/osu.Game/Users/User.cs
@@ -144,5 +144,14 @@ namespace osu.Game.Users
public Badge[] Badges;
public override string ToString() => Username;
+
+ ///
+ /// A user instance for displaying locally created system messages.
+ ///
+ public static readonly User SYSTEM_USER = new User
+ {
+ Username = "system",
+ Id = 0
+ };
}
}
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index 3e16e90d06..5ce04b813b 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -16,9 +16,9 @@
-
+
-
+
diff --git a/osu.TestProject.props b/osu.TestProject.props
index 58de6ec030..506d634555 100644
--- a/osu.TestProject.props
+++ b/osu.TestProject.props
@@ -11,7 +11,7 @@
-
+