diff --git a/.gitmodules b/.gitmodules
index f1c4f5d172..e69de29bb2 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +0,0 @@
-[submodule "osu-resources"]
- path = osu-resources
- url = https://github.com/ppy/osu-resources
\ No newline at end of file
diff --git a/README.md b/README.md
index a54b28b74a..94ab385bfd 100644
--- a/README.md
+++ b/README.md
@@ -31,18 +31,14 @@ If your platform is not listed above, there is still a chance you can manually b
Clone the repository **including submodules**:
```shell
-git clone --recurse-submodules https://github.com/ppy/osu
+git clone https://github.com/ppy/osu
cd osu
```
-> If you forgot the `--recurse-submodules` option, run this command inside the `osu` directory:
->
-> `git submodule update --init --recursive`
-
To update the source code to the latest commit, run the following command inside the `osu` directory:
```shell
-git pull --recurse-submodules
+git pull
```
## Building
@@ -73,6 +69,10 @@ For example, you can run osu! with the following command:
LD_LIBRARY_PATH="$(pwd)/osu.Desktop/bin/Debug/netcoreapp2.2" dotnet run --project osu.Desktop
```
+## Testing with resource/framework modifications
+
+Sometimes it may be necessary to cross-test changes in [osu-resources](https://github.com/ppy/osu-resources) or [osu-framework](https://github.com/ppy/osu-framework). This can be achieved by running some commands as documented on the [osu-resources](https://github.com/ppy/osu-resources/wiki/Testing-local-resources-checkout-with-other-projects) and [osu-framework](https://github.com/ppy/osu-framework/wiki/Testing-local-framework-checkout-with-other-projects) wiki pages.
+
## Code analysis
Code analysis can be run with `powershell ./build.ps1` or `build.sh`. This is currently only supported under windows due to [resharper cli shortcomings](https://youtrack.jetbrains.com/issue/RSRP-410004). Alternative, you can install resharper or use rider to get inline support in your IDE of choice.
diff --git a/osu-resources b/osu-resources
deleted file mode 160000
index 677897728f..0000000000
--- a/osu-resources
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 677897728f4332fa1200e0280ca02c4b987c6c47
diff --git a/osu.Desktop/OsuGameDesktop.cs b/osu.Desktop/OsuGameDesktop.cs
index c4c0cc1fdd..ef8ec0c105 100644
--- a/osu.Desktop/OsuGameDesktop.cs
+++ b/osu.Desktop/OsuGameDesktop.cs
@@ -16,7 +16,6 @@ using osu.Desktop.Updater;
using osu.Framework;
using osu.Framework.Platform.Windows;
using osu.Framework.Screens;
-using osu.Game.Screens;
using osu.Game.Screens.Menu;
namespace osu.Desktop
@@ -63,9 +62,10 @@ namespace osu.Desktop
}
}
- protected override void ScreenChanged(OsuScreen current, Screen newScreen)
+ protected override void ScreenChanged(IScreen lastScreen, IScreen newScreen)
{
- base.ScreenChanged(current, newScreen);
+ base.ScreenChanged(lastScreen, newScreen);
+
switch (newScreen)
{
case Intro _:
diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj
index 4f0ae3d65d..874f73da6d 100644
--- a/osu.Desktop/osu.Desktop.csproj
+++ b/osu.Desktop/osu.Desktop.csproj
@@ -22,7 +22,6 @@
-
diff --git a/osu.Game.Rulesets.Catch.Tests.iOS/osu.Game.Rulesets.Catch.Tests.iOS.csproj b/osu.Game.Rulesets.Catch.Tests.iOS/osu.Game.Rulesets.Catch.Tests.iOS.csproj
index da053f7598..37e7c45a4e 100644
--- a/osu.Game.Rulesets.Catch.Tests.iOS/osu.Game.Rulesets.Catch.Tests.iOS.csproj
+++ b/osu.Game.Rulesets.Catch.Tests.iOS/osu.Game.Rulesets.Catch.Tests.iOS.csproj
@@ -39,10 +39,6 @@
{58F6C80C-1253-4A0E-A465-B8C85EBEADF3}
osu.Game.Rulesets.Catch
-
- {D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}
- osu.Game.Resources
-
diff --git a/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs b/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs
index fd30a8d4ae..d40a108c5e 100644
--- a/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs
+++ b/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs
@@ -21,6 +21,7 @@ namespace osu.Game.Rulesets.Catch.Tests
[TestCase("basic")]
[TestCase("spinner")]
[TestCase("spinner-and-circles")]
+ [TestCase("slider")]
public new void Test(string name)
{
base.Test(name);
diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs
index ef7573c70b..61bb4335f3 100644
--- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs
+++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs
@@ -55,6 +55,13 @@ namespace osu.Game.Rulesets.Catch.Objects
var minDistanceFromEnd = Velocity * 0.01;
+ var tickSamples = Samples.Select(s => new SampleInfo
+ {
+ Bank = s.Bank,
+ Name = @"slidertick",
+ Volume = s.Volume
+ }).ToList();
+
AddNested(new Fruit
{
Samples = Samples,
@@ -62,15 +69,22 @@ namespace osu.Game.Rulesets.Catch.Objects
X = X
});
- double lastDropletTime = StartTime;
+ double lastTickTime = StartTime;
for (int span = 0; span < this.SpanCount(); span++)
{
var spanStartTime = StartTime + span * spanDuration;
var reversed = span % 2 == 1;
- for (double d = 0; d <= length; d += tickDistance)
+ for (double d = tickDistance;; d += tickDistance)
{
+ bool isLastTick = false;
+ if (d + minDistanceFromEnd >= length)
+ {
+ d = length;
+ isLastTick = true;
+ }
+
var timeProgress = d / length;
var distanceProgress = reversed ? 1 - timeProgress : timeProgress;
@@ -79,47 +93,42 @@ namespace osu.Game.Rulesets.Catch.Objects
if (LegacyLastTickOffset != null)
{
// If we're the last tick, apply the legacy offset
- if (span == this.SpanCount() - 1 && d + tickDistance > length)
+ if (span == this.SpanCount() - 1 && isLastTick)
time = Math.Max(StartTime + Duration / 2, time - LegacyLastTickOffset.Value);
}
- double tinyTickInterval = time - lastDropletTime;
- while (tinyTickInterval > 100)
- tinyTickInterval /= 2;
-
- for (double t = lastDropletTime + tinyTickInterval; t < time; t += tinyTickInterval)
+ int tinyTickCount = 1;
+ double tinyTickInterval = time - lastTickTime;
+ while (tinyTickInterval > 100 && tinyTickCount < 10000)
{
+ tinyTickInterval /= 2;
+ tinyTickCount *= 2;
+ }
+
+ for (int tinyTickIndex = 0; tinyTickIndex < tinyTickCount - 1; tinyTickIndex++)
+ {
+ var t = lastTickTime + (tinyTickIndex + 1) * tinyTickInterval;
double progress = reversed ? 1 - (t - spanStartTime) / spanDuration : (t - spanStartTime) / spanDuration;
AddNested(new TinyDroplet
{
StartTime = t,
X = X + Path.PositionAt(progress).X / CatchPlayfield.BASE_WIDTH,
- Samples = new List(Samples.Select(s => new SampleInfo
- {
- Bank = s.Bank,
- Name = @"slidertick",
- Volume = s.Volume
- }))
+ Samples = tickSamples
});
}
- if (d > minDistanceFromEnd && Math.Abs(d - length) > minDistanceFromEnd)
+ lastTickTime = time;
+
+ if (isLastTick)
+ break;
+
+ AddNested(new Droplet
{
- AddNested(new Droplet
- {
- StartTime = time,
- X = X + Path.PositionAt(distanceProgress).X / CatchPlayfield.BASE_WIDTH,
- Samples = new List(Samples.Select(s => new SampleInfo
- {
- Bank = s.Bank,
- Name = @"slidertick",
- Volume = s.Volume
- }))
- });
- }
-
- lastDropletTime = time;
+ StartTime = time,
+ X = X + Path.PositionAt(distanceProgress).X / CatchPlayfield.BASE_WIDTH,
+ Samples = tickSamples
+ });
}
AddNested(new Fruit
diff --git a/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/slider-expected-conversion.json b/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/slider-expected-conversion.json
new file mode 100644
index 0000000000..58c52b6867
--- /dev/null
+++ b/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/slider-expected-conversion.json
@@ -0,0 +1 @@
+{"Mappings":[{"StartTime":19184.0,"Objects":[{"StartTime":19184.0,"Position":320.0},{"StartTime":19263.0,"Position":311.730255},{"StartTime":19343.0,"Position":324.6205},{"StartTime":19423.0,"Position":343.0907},{"StartTime":19503.0,"Position":372.2917},{"StartTime":19582.0,"Position":385.194733},{"StartTime":19662.0,"Position":379.0426},{"StartTime":19742.0,"Position":385.1066},{"StartTime":19822.0,"Position":391.624664},{"StartTime":19919.0,"Position":386.27832},{"StartTime":20016.0,"Position":380.117035},{"StartTime":20113.0,"Position":381.664154},{"StartTime":20247.0,"Position":370.872864}]}]}
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/slider.osu b/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/slider.osu
new file mode 100644
index 0000000000..d48b2d7769
--- /dev/null
+++ b/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/slider.osu
@@ -0,0 +1,18 @@
+osu file format v14
+
+[General]
+Mode: 2
+
+[Difficulty]
+HPDrainRate:3
+CircleSize:2
+OverallDifficulty:4
+ApproachRate:4
+SliderMultiplier:0.9
+SliderTickRate:1
+
+[TimingPoints]
+35.4473684210527,638.298947368422,4,2,1,60,1,0
+
+[HitObjects]
+320,176,19184,2,8,P|384:168|368:232,1,150
diff --git a/osu.Game.Rulesets.Mania.Tests.iOS/osu.Game.Rulesets.Mania.Tests.iOS.csproj b/osu.Game.Rulesets.Mania.Tests.iOS/osu.Game.Rulesets.Mania.Tests.iOS.csproj
index 45ed2091a7..24abccb19d 100644
--- a/osu.Game.Rulesets.Mania.Tests.iOS/osu.Game.Rulesets.Mania.Tests.iOS.csproj
+++ b/osu.Game.Rulesets.Mania.Tests.iOS/osu.Game.Rulesets.Mania.Tests.iOS.csproj
@@ -39,10 +39,6 @@
{48F4582B-7687-4621-9CBE-5C24197CB536}
osu.Game.Rulesets.Mania
-
- {D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}
- osu.Game.Resources
-
diff --git a/osu.Game.Rulesets.Osu.Tests.iOS/osu.Game.Rulesets.Osu.Tests.iOS.csproj b/osu.Game.Rulesets.Osu.Tests.iOS/osu.Game.Rulesets.Osu.Tests.iOS.csproj
index 349e46e02d..9930a166e3 100644
--- a/osu.Game.Rulesets.Osu.Tests.iOS/osu.Game.Rulesets.Osu.Tests.iOS.csproj
+++ b/osu.Game.Rulesets.Osu.Tests.iOS/osu.Game.Rulesets.Osu.Tests.iOS.csproj
@@ -39,10 +39,6 @@
{C92A607B-1FDD-4954-9F92-03FF547D9080}
osu.Game.Rulesets.Osu
-
- {D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}
- osu.Game.Resources
-
diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs
index 83deac78a1..13a21c5c55 100644
--- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs
+++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs
@@ -88,7 +88,12 @@ namespace osu.Game.Rulesets.Osu.Difficulty
private double computeAimValue()
{
- double aimValue = Math.Pow(5.0f * Math.Max(1.0f, Attributes.AimStrain / 0.0675f) - 4.0f, 3.0f) / 100000.0f;
+ double rawAim = Attributes.AimStrain;
+
+ if (mods.Any(m => m is OsuModTouchDevice))
+ rawAim = Math.Pow(rawAim, 0.8);
+
+ double aimValue = Math.Pow(5.0f * Math.Max(1.0f, rawAim / 0.0675f) - 4.0f, 3.0f) / 100000.0f;
// Longer maps are worth more
double lengthBonus = 0.95f + 0.4f * Math.Min(1.0f, totalHits / 2000.0f) +
diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyBeatmap.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyBeatmap.cs
index 1736912e1f..068564d50c 100644
--- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyBeatmap.cs
+++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyBeatmap.cs
@@ -38,7 +38,13 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
// The first jump is formed by the first two hitobjects of the map.
// If the map has less than two OsuHitObjects, the enumerator will not return anything.
for (int i = 1; i < objects.Count; i++)
- yield return new OsuDifficultyHitObject(objects[i], objects[i - 1], timeRate);
+ {
+ var lastLast = i > 1 ? objects[i - 2] : null;
+ var last = objects[i - 1];
+ var current = objects[i];
+
+ yield return new OsuDifficultyHitObject(lastLast, last, current, timeRate);
+ }
}
}
}
diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs
index 91d6c3d7a3..4e9ac26dc5 100644
--- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs
+++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs
@@ -40,14 +40,22 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
///
public double StrainTime { get; private set; }
+ ///
+ /// Angle the player has to take to hit this .
+ /// Calculated as the angle between the circles (current-2, current-1, current).
+ ///
+ public double? Angle { get; private set; }
+
+ private readonly OsuHitObject lastLastObject;
private readonly OsuHitObject lastObject;
private readonly double timeRate;
///
/// Initializes the object calculating extra data required for difficulty calculation.
///
- public OsuDifficultyHitObject(OsuHitObject currentObject, OsuHitObject lastObject, double timeRate)
+ public OsuDifficultyHitObject(OsuHitObject lastLastObject, OsuHitObject lastObject, OsuHitObject currentObject, double timeRate)
{
+ this.lastLastObject = lastLastObject;
this.lastObject = lastObject;
this.timeRate = timeRate;
@@ -68,20 +76,30 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
scalingFactor *= 1 + smallCircleBonus;
}
- Vector2 lastCursorPosition = lastObject.StackedPosition;
-
- var lastSlider = lastObject as Slider;
- if (lastSlider != null)
+ if (lastObject is Slider lastSlider)
{
computeSliderCursorPosition(lastSlider);
- lastCursorPosition = lastSlider.LazyEndPosition ?? lastCursorPosition;
-
TravelDistance = lastSlider.LazyTravelDistance * scalingFactor;
}
+ Vector2 lastCursorPosition = getEndCursorPosition(lastObject);
+
// Don't need to jump to reach spinners
if (!(BaseObject is Spinner))
JumpDistance = (BaseObject.StackedPosition * scalingFactor - lastCursorPosition * scalingFactor).Length;
+
+ if (lastLastObject != null)
+ {
+ Vector2 lastLastCursorPosition = getEndCursorPosition(lastLastObject);
+
+ Vector2 v1 = lastLastCursorPosition - lastObject.StackedPosition;
+ Vector2 v2 = BaseObject.StackedPosition - lastCursorPosition;
+
+ float dot = Vector2.Dot(v1, v2);
+ float det = v1.X * v2.Y - v1.Y * v2.X;
+
+ Angle = Math.Abs(Math.Atan2(det, dot));
+ }
}
private void setTimingValues()
@@ -127,5 +145,19 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
computeVertex(time);
computeVertex(slider.EndTime);
}
+
+ private Vector2 getEndCursorPosition(OsuHitObject hitObject)
+ {
+ Vector2 pos = hitObject.StackedPosition;
+
+ var slider = hitObject as Slider;
+ if (slider != null)
+ {
+ computeSliderCursorPosition(slider);
+ pos = slider.LazyEndPosition ?? pos;
+ }
+
+ return pos;
+ }
}
}
diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs
index 9e5f13de62..b5e57985e9 100644
--- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs
+++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs
@@ -11,10 +11,39 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
///
public class Aim : Skill
{
+ private const double angle_bonus_begin = Math.PI / 3;
+ private const double timing_threshold = 107;
+
protected override double SkillMultiplier => 26.25;
protected override double StrainDecayBase => 0.15;
protected override double StrainValueOf(OsuDifficultyHitObject current)
- => (Math.Pow(current.TravelDistance, 0.99) + Math.Pow(current.JumpDistance, 0.99)) / current.StrainTime;
+ {
+ double result = 0;
+
+ const double scale = 90;
+
+ double applyDiminishingExp(double val) => Math.Pow(val, 0.99);
+
+ if (Previous.Count > 0)
+ {
+ if (current.Angle != null && current.Angle.Value > angle_bonus_begin)
+ {
+ var angleBonus = Math.Sqrt(
+ Math.Max(Previous[0].JumpDistance - scale, 0)
+ * Math.Pow(Math.Sin(current.Angle.Value - angle_bonus_begin), 2)
+ * Math.Max(current.JumpDistance - scale, 0));
+ result = 1.5 * applyDiminishingExp(Math.Max(0, angleBonus)) / Math.Max(timing_threshold, Previous[0].StrainTime);
+ }
+ }
+
+ double jumpDistanceExp = applyDiminishingExp(current.JumpDistance);
+ double travelDistanceExp = applyDiminishingExp(current.TravelDistance);
+
+ return Math.Max(
+ result + (jumpDistanceExp + travelDistanceExp + Math.Sqrt(travelDistanceExp * jumpDistanceExp)) / Math.Max(current.StrainTime, timing_threshold),
+ (Math.Sqrt(travelDistanceExp * jumpDistanceExp) + jumpDistanceExp + travelDistanceExp) / current.StrainTime
+ );
+ }
}
}
diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Skill.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Skill.cs
index 436d3d0853..2f23552eb9 100644
--- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Skill.cs
+++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Skill.cs
@@ -15,6 +15,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
///
public abstract class Skill
{
+ protected const double SINGLE_SPACING_THRESHOLD = 125;
+ protected const double STREAM_SPACING_THRESHOLD = 110;
+
///
/// Strain values are multiplied by this number for the given skill. Used to balance the value of different skills between each other.
///
diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs
index 809632806b..e78691ce53 100644
--- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs
+++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs
@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System;
using osu.Game.Rulesets.Osu.Difficulty.Preprocessing;
namespace osu.Game.Rulesets.Osu.Difficulty.Skills
@@ -10,30 +11,41 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
///
public class Speed : Skill
{
+ private const double angle_bonus_begin = 5 * Math.PI / 6;
+ private const double pi_over_4 = Math.PI / 4;
+ private const double pi_over_2 = Math.PI / 2;
+
protected override double SkillMultiplier => 1400;
protected override double StrainDecayBase => 0.3;
- private const double single_spacing_threshold = 125;
- private const double stream_spacing_threshold = 110;
- private const double almost_diameter = 90;
+ private const double min_speed_bonus = 75; // ~200BPM
+ private const double max_speed_bonus = 45; // ~330BPM
+ private const double speed_balancing_factor = 40;
protected override double StrainValueOf(OsuDifficultyHitObject current)
{
- double distance = current.TravelDistance + current.JumpDistance;
+ double distance = Math.Min(SINGLE_SPACING_THRESHOLD, current.TravelDistance + current.JumpDistance);
+ double deltaTime = Math.Max(max_speed_bonus, current.DeltaTime);
- double speedValue;
- if (distance > single_spacing_threshold)
- speedValue = 2.5;
- else if (distance > stream_spacing_threshold)
- speedValue = 1.6 + 0.9 * (distance - stream_spacing_threshold) / (single_spacing_threshold - stream_spacing_threshold);
- else if (distance > almost_diameter)
- speedValue = 1.2 + 0.4 * (distance - almost_diameter) / (stream_spacing_threshold - almost_diameter);
- else if (distance > almost_diameter / 2)
- speedValue = 0.95 + 0.25 * (distance - almost_diameter / 2) / (almost_diameter / 2);
- else
- speedValue = 0.95;
+ double speedBonus = 1.0;
+ if (deltaTime < min_speed_bonus)
+ speedBonus = 1 + Math.Pow((min_speed_bonus - deltaTime) / speed_balancing_factor, 2);
- return speedValue / current.StrainTime;
+ double angleBonus = 1.0;
+ if (current.Angle != null && current.Angle.Value < angle_bonus_begin)
+ {
+ angleBonus = 1 + Math.Pow(Math.Sin(1.5 * (angle_bonus_begin - current.Angle.Value)), 2) / 3.57;
+ if (current.Angle.Value < pi_over_2)
+ {
+ angleBonus = 1.28;
+ if (distance < 90 && current.Angle.Value < pi_over_4)
+ angleBonus += (1 - angleBonus) * Math.Min((90 - distance) / 10, 1);
+ else if (distance < 90)
+ angleBonus += (1 - angleBonus) * Math.Min((90 - distance) / 10, 1) * Math.Sin((pi_over_2 - current.Angle.Value) / pi_over_4);
+ }
+ }
+
+ return (1 + (speedBonus - 1) * 0.75) * angleBonus * (0.95 + speedBonus * Math.Pow(distance / SINGLE_SPACING_THRESHOLD, 3.5)) / current.StrainTime;
}
}
}
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTouchDevice.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTouchDevice.cs
new file mode 100644
index 0000000000..571756d056
--- /dev/null
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModTouchDevice.cs
@@ -0,0 +1,16 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Game.Rulesets.Mods;
+
+namespace osu.Game.Rulesets.Osu.Mods
+{
+ public class OsuModTouchDevice : Mod
+ {
+ public override string Name => "Touch Device";
+ public override string Acronym => "TD";
+ public override double ScoreMultiplier => 1;
+
+ public override bool Ranked => true;
+ }
+}
diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs
index 9415adc411..12d0a28a8f 100644
--- a/osu.Game.Rulesets.Osu/OsuRuleset.cs
+++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs
@@ -82,6 +82,9 @@ namespace osu.Game.Rulesets.Osu
if (mods.HasFlag(LegacyMods.Target))
yield return new OsuModTarget();
+
+ if (mods.HasFlag(LegacyMods.TouchDevice))
+ yield return new OsuModTouchDevice();
}
public override IEnumerable GetModsFor(ModType type)
diff --git a/osu.Game.Rulesets.Taiko.Tests.iOS/osu.Game.Rulesets.Taiko.Tests.iOS.csproj b/osu.Game.Rulesets.Taiko.Tests.iOS/osu.Game.Rulesets.Taiko.Tests.iOS.csproj
index 2ab0633786..d2817b743c 100644
--- a/osu.Game.Rulesets.Taiko.Tests.iOS/osu.Game.Rulesets.Taiko.Tests.iOS.csproj
+++ b/osu.Game.Rulesets.Taiko.Tests.iOS/osu.Game.Rulesets.Taiko.Tests.iOS.csproj
@@ -39,10 +39,6 @@
{F167E17A-7DE6-4AF5-B920-A5112296C695}
osu.Game.Rulesets.Taiko
-
- {D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}
- osu.Game.Resources
-
diff --git a/osu.Game.Tests.iOS/osu.Game.Tests.iOS.csproj b/osu.Game.Tests.iOS/osu.Game.Tests.iOS.csproj
index 636bedac13..ea5ab699f3 100644
--- a/osu.Game.Tests.iOS/osu.Game.Tests.iOS.csproj
+++ b/osu.Game.Tests.iOS/osu.Game.Tests.iOS.csproj
@@ -51,10 +51,6 @@
{F167E17A-7DE6-4AF5-B920-A5112296C695}
osu.Game.Rulesets.Taiko
-
- {D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}
- osu.Game.Resources
-
diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs
index 1221212f94..171ba91ada 100644
--- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs
+++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs
@@ -27,7 +27,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
[Test]
public void TestDecodeBeatmapVersion()
{
- using (var resStream = Resource.OpenResource("beatmap-version.osu"))
+ using (var resStream = TestResources.OpenResource("beatmap-version.osu"))
using (var stream = new StreamReader(resStream))
{
var decoder = Decoder.GetDecoder(stream);
@@ -47,7 +47,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeBeatmapGeneral()
{
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
- using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
+ using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
using (var stream = new StreamReader(resStream))
{
var beatmap = decoder.Decode(stream);
@@ -70,7 +70,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeBeatmapEditor()
{
var decoder = new LegacyBeatmapDecoder();
- using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
+ using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
using (var stream = new StreamReader(resStream))
{
var beatmapInfo = decoder.Decode(stream).BeatmapInfo;
@@ -95,7 +95,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeBeatmapMetadata()
{
var decoder = new LegacyBeatmapDecoder();
- using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
+ using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
using (var stream = new StreamReader(resStream))
{
var beatmap = decoder.Decode(stream);
@@ -119,7 +119,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeBeatmapDifficulty()
{
var decoder = new LegacyBeatmapDecoder();
- using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
+ using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
using (var stream = new StreamReader(resStream))
{
var difficulty = decoder.Decode(stream).BeatmapInfo.BaseDifficulty;
@@ -137,7 +137,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeBeatmapEvents()
{
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
- using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
+ using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
using (var stream = new StreamReader(resStream))
{
var beatmap = decoder.Decode(stream);
@@ -155,7 +155,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeBeatmapTimingPoints()
{
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
- using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
+ using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
using (var stream = new StreamReader(resStream))
{
var beatmap = decoder.Decode(stream);
@@ -190,7 +190,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeBeatmapColours()
{
var decoder = new LegacySkinDecoder();
- using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
+ using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
using (var stream = new StreamReader(resStream))
{
var comboColors = decoder.Decode(stream).ComboColours;
@@ -215,7 +215,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeBeatmapComboOffsetsOsu()
{
var decoder = new LegacyBeatmapDecoder();
- using (var resStream = Resource.OpenResource("hitobject-combo-offset.osu"))
+ using (var resStream = TestResources.OpenResource("hitobject-combo-offset.osu"))
using (var stream = new StreamReader(resStream))
{
var beatmap = decoder.Decode(stream);
@@ -237,7 +237,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeBeatmapComboOffsetsCatch()
{
var decoder = new LegacyBeatmapDecoder();
- using (var resStream = Resource.OpenResource("hitobject-combo-offset.osu"))
+ using (var resStream = TestResources.OpenResource("hitobject-combo-offset.osu"))
using (var stream = new StreamReader(resStream))
{
var beatmap = decoder.Decode(stream);
@@ -259,7 +259,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeBeatmapHitObjects()
{
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
- using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
+ using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
using (var stream = new StreamReader(resStream))
{
var hitObjects = decoder.Decode(stream).HitObjects;
@@ -286,7 +286,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeControlPointCustomSampleBank()
{
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
- using (var resStream = Resource.OpenResource("controlpoint-custom-samplebank.osu"))
+ using (var resStream = TestResources.OpenResource("controlpoint-custom-samplebank.osu"))
using (var stream = new StreamReader(resStream))
{
var hitObjects = decoder.Decode(stream).HitObjects;
@@ -307,7 +307,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeHitObjectCustomSampleBank()
{
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
- using (var resStream = Resource.OpenResource("hitobject-custom-samplebank.osu"))
+ using (var resStream = TestResources.OpenResource("hitobject-custom-samplebank.osu"))
using (var stream = new StreamReader(resStream))
{
var hitObjects = decoder.Decode(stream).HitObjects;
@@ -324,7 +324,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeHitObjectFileSamples()
{
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
- using (var resStream = Resource.OpenResource("hitobject-file-samples.osu"))
+ using (var resStream = TestResources.OpenResource("hitobject-file-samples.osu"))
using (var stream = new StreamReader(resStream))
{
var hitObjects = decoder.Decode(stream).HitObjects;
@@ -342,7 +342,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeSliderSamples()
{
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
- using (var resStream = Resource.OpenResource("slider-samples.osu"))
+ using (var resStream = TestResources.OpenResource("slider-samples.osu"))
using (var stream = new StreamReader(resStream))
{
var hitObjects = decoder.Decode(stream).HitObjects;
@@ -385,7 +385,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeHitObjectNullAdditionBank()
{
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
- using (var resStream = Resource.OpenResource("hitobject-no-addition-bank.osu"))
+ using (var resStream = TestResources.OpenResource("hitobject-no-addition-bank.osu"))
using (var stream = new StreamReader(resStream))
{
var hitObjects = decoder.Decode(stream).HitObjects;
diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs
index 5049349999..136d1de930 100644
--- a/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs
+++ b/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs
@@ -19,7 +19,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeStoryboardEvents()
{
var decoder = new LegacyStoryboardDecoder();
- using (var resStream = Resource.OpenResource("Himeringo - Yotsuya-san ni Yoroshiku (RLC) [Winber1's Extreme].osu"))
+ using (var resStream = TestResources.OpenResource("Himeringo - Yotsuya-san ni Yoroshiku (RLC) [Winber1's Extreme].osu"))
using (var stream = new StreamReader(resStream))
{
var storyboard = decoder.Decode(stream);
@@ -91,7 +91,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeVariableWithSuffix()
{
var decoder = new LegacyStoryboardDecoder();
- using (var resStream = Resource.OpenResource("variable-with-suffix.osb"))
+ using (var resStream = TestResources.OpenResource("variable-with-suffix.osb"))
using (var stream = new StreamReader(resStream))
{
var storyboard = decoder.Decode(stream);
diff --git a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs
index 44291a6805..d5ab0e43d1 100644
--- a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs
+++ b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs
@@ -146,7 +146,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
/// The after being decoded by an .
private Beatmap decode(string filename, out Beatmap jsonDecoded)
{
- using (var stream = Resource.OpenResource(filename))
+ using (var stream = TestResources.OpenResource(filename))
using (var sr = new StreamReader(stream))
{
var legacyDecoded = new LegacyBeatmapDecoder { ApplyOffsets = false }.Decode(sr);
diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs
index a159659d35..b6a8b3b06c 100644
--- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs
+++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs
@@ -12,6 +12,7 @@ using osu.Framework.Platform;
using osu.Game.IPC;
using osu.Framework.Allocation;
using osu.Game.Beatmaps;
+using osu.Game.Tests.Resources;
using SharpCompress.Archives.Zip;
namespace osu.Game.Tests.Beatmaps.IO
@@ -19,8 +20,6 @@ namespace osu.Game.Tests.Beatmaps.IO
[TestFixture]
public class ImportBeatmapTest
{
- public const string TEST_OSZ_PATH = @"../../../../osu-resources/osu.Game.Resources/Beatmaps/241526 Soleily - Renatus.osz";
-
[Test]
public void TestImportWhenClosed()
{
@@ -114,7 +113,7 @@ namespace osu.Game.Tests.Beatmaps.IO
Assert.AreEqual(0, fireCount -= 2);
- var breakTemp = createTemporaryBeatmap();
+ var breakTemp = TestResources.GetTestBeatmapForImport();
MemoryStream brokenOsu = new MemoryStream(new byte[] { 1, 3, 3, 7 });
MemoryStream brokenOsz = new MemoryStream(File.ReadAllBytes(breakTemp));
@@ -223,7 +222,7 @@ namespace osu.Game.Tests.Beatmaps.IO
var osu = loadOsu(host);
- var temp = createTemporaryBeatmap();
+ var temp = TestResources.GetTestBeatmapForImport();
var importer = new ArchiveImportIPCChannel(client);
if (!importer.ImportAsync(temp).Wait(10000))
@@ -248,7 +247,7 @@ namespace osu.Game.Tests.Beatmaps.IO
try
{
var osu = loadOsu(host);
- var temp = createTemporaryBeatmap();
+ var temp = TestResources.GetTestBeatmapForImport();
using (File.OpenRead(temp))
osu.Dependencies.Get().Import(temp);
ensureLoaded(osu);
@@ -262,17 +261,9 @@ namespace osu.Game.Tests.Beatmaps.IO
}
}
- private static string createTemporaryBeatmap()
- {
- var temp = Path.GetTempFileName() + ".osz";
- File.Copy(TEST_OSZ_PATH, temp, true);
- Assert.IsTrue(File.Exists(temp));
- return temp;
- }
-
public static BeatmapSetInfo LoadOszIntoOsu(OsuGameBase osu, string path = null)
{
- var temp = path ?? createTemporaryBeatmap();
+ var temp = path ?? TestResources.GetTestBeatmapForImport();
var manager = osu.Dependencies.Get();
diff --git a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs
index aa95e7390f..17197aff27 100644
--- a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs
+++ b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs
@@ -17,7 +17,7 @@ namespace osu.Game.Tests.Beatmaps.IO
[Test]
public void TestReadBeatmaps()
{
- using (var osz = Resource.OpenResource("Beatmaps.241526 Soleily - Renatus.osz"))
+ using (var osz = TestResources.GetTestBeatmapStream())
{
var reader = new ZipArchiveReader(osz);
string[] expected =
@@ -44,7 +44,7 @@ namespace osu.Game.Tests.Beatmaps.IO
[Test]
public void TestReadMetadata()
{
- using (var osz = Resource.OpenResource("Beatmaps.241526 Soleily - Renatus.osz"))
+ using (var osz = TestResources.GetTestBeatmapStream())
{
var reader = new ZipArchiveReader(osz);
@@ -72,7 +72,7 @@ namespace osu.Game.Tests.Beatmaps.IO
[Test]
public void TestReadFile()
{
- using (var osz = Resource.OpenResource("Beatmaps.241526 Soleily - Renatus.osz"))
+ using (var osz = TestResources.GetTestBeatmapStream())
{
var reader = new ZipArchiveReader(osz);
using (var stream = new StreamReader(
diff --git a/osu.Game.Tests/Resources/Resource.cs b/osu.Game.Tests/Resources/Resource.cs
deleted file mode 100644
index 5405436422..0000000000
--- a/osu.Game.Tests/Resources/Resource.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-using System;
-using System.IO;
-using System.Reflection;
-
-namespace osu.Game.Tests.Resources
-{
- public static class Resource
- {
- public static Stream OpenResource(string name)
- {
- var localPath = Path.GetDirectoryName(Uri.UnescapeDataString(new UriBuilder(Assembly.GetExecutingAssembly().CodeBase).Path));
-
- return Assembly.GetExecutingAssembly().GetManifestResourceStream($@"osu.Game.Tests.Resources.{name}") ??
- Assembly.LoadFrom(Path.Combine(localPath, @"osu.Game.Resources.dll")).GetManifestResourceStream($@"osu.Game.Resources.{name}");
- }
- }
-}
diff --git a/osu.Game.Tests/Resources/TestResources.cs b/osu.Game.Tests/Resources/TestResources.cs
new file mode 100644
index 0000000000..9cb85a63bf
--- /dev/null
+++ b/osu.Game.Tests/Resources/TestResources.cs
@@ -0,0 +1,28 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.IO;
+using NUnit.Framework;
+using osu.Framework.IO.Stores;
+
+namespace osu.Game.Tests.Resources
+{
+ public static class TestResources
+ {
+ public static Stream OpenResource(string name) => new DllResourceStore("osu.Game.Tests.dll").GetStream($"Resources/{name}");
+
+ public static Stream GetTestBeatmapStream() => new DllResourceStore("osu.Game.Resources.dll").GetStream("Beatmaps/241526 Soleily - Renatus.osz");
+
+ public static string GetTestBeatmapForImport()
+ {
+ var temp = Path.GetTempFileName() + ".osz";
+
+ using (var stream = GetTestBeatmapStream())
+ using (var newFile = File.Create(temp))
+ stream.CopyTo(newFile);
+
+ Assert.IsTrue(File.Exists(temp));
+ return temp;
+ }
+ }
+}
diff --git a/osu.Game.Tests/Scores/IO/ImportScoreTest.cs b/osu.Game.Tests/Scores/IO/ImportScoreTest.cs
index f5ebe313dd..e39f18c3cd 100644
--- a/osu.Game.Tests/Scores/IO/ImportScoreTest.cs
+++ b/osu.Game.Tests/Scores/IO/ImportScoreTest.cs
@@ -3,7 +3,6 @@
using System;
using System.Collections.Generic;
-using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -16,14 +15,13 @@ using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
+using osu.Game.Tests.Resources;
using osu.Game.Users;
namespace osu.Game.Tests.Scores.IO
{
public class ImportScoreTest
{
- public const string TEST_OSZ_PATH = @"../../../../osu-resources/osu.Game.Resources/Beatmaps/241526 Soleily - Renatus.osz";
-
[Test]
public void TestBasicImport()
{
@@ -132,21 +130,13 @@ namespace osu.Game.Tests.Scores.IO
return scoreManager.GetAllUsableScores().First();
}
- private string createTemporaryBeatmap()
- {
- var temp = Path.GetTempFileName() + ".osz";
- File.Copy(TEST_OSZ_PATH, temp, true);
- Assert.IsTrue(File.Exists(temp));
- return temp;
- }
-
private OsuGameBase loadOsu(GameHost host)
{
var osu = new OsuGameBase();
Task.Run(() => host.Run(osu));
waitForOrAssert(() => osu.IsLoaded, @"osu! failed to start in a reasonable amount of time");
- var beatmapFile = createTemporaryBeatmap();
+ var beatmapFile = TestResources.GetTestBeatmapForImport();
var beatmapManager = osu.Dependencies.Get();
beatmapManager.Import(beatmapFile);
diff --git a/osu.Game.Tests/Visual/TestCaseLoaderAnimation.cs b/osu.Game.Tests/Visual/TestCaseLoaderAnimation.cs
index 70ed075101..2088f97580 100644
--- a/osu.Game.Tests/Visual/TestCaseLoaderAnimation.cs
+++ b/osu.Game.Tests/Visual/TestCaseLoaderAnimation.cs
@@ -4,6 +4,7 @@
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes;
+using osu.Framework.Screens;
using osu.Game.Screens;
using osu.Game.Screens.Menu;
using osuTK.Graphics;
@@ -57,7 +58,7 @@ namespace osu.Game.Tests.Visual
public OsuLogo Logo;
private TestScreen screen;
- public bool ScreenLoaded => screen.IsCurrentScreen;
+ public bool ScreenLoaded => screen.IsCurrentScreen();
public TestLoader(double delay)
{
@@ -96,7 +97,7 @@ namespace osu.Game.Tests.Visual
{
public TestScreen()
{
- Child = new Box
+ InternalChild = new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.DarkSlateGray,
@@ -107,7 +108,7 @@ namespace osu.Game.Tests.Visual
protected override void LogoArriving(OsuLogo logo, bool resuming)
{
base.LogoArriving(logo, resuming);
- Child.FadeInFromZero(200);
+ InternalChild.FadeInFromZero(200);
}
}
}
diff --git a/osu.Game.Tests/Visual/TestCaseMultiHeader.cs b/osu.Game.Tests/Visual/TestCaseMultiHeader.cs
index 998cdcbad1..f7802e2d08 100644
--- a/osu.Game.Tests/Visual/TestCaseMultiHeader.cs
+++ b/osu.Game.Tests/Visual/TestCaseMultiHeader.cs
@@ -3,6 +3,7 @@
using NUnit.Framework;
using osu.Framework.Graphics;
+using osu.Framework.Screens;
using osu.Game.Screens;
using osu.Game.Screens.Multi;
@@ -15,15 +16,15 @@ namespace osu.Game.Tests.Visual
{
int index = 0;
- OsuScreen currentScreen = new TestMultiplayerSubScreen(index);
+ ScreenStack screenStack = new ScreenStack(new TestMultiplayerSubScreen(index)) { RelativeSizeAxes = Axes.Both };
Children = new Drawable[]
{
- currentScreen,
- new Header(currentScreen)
+ screenStack,
+ new Header(screenStack)
};
- AddStep("push multi screen", () => currentScreen.Push(currentScreen = new TestMultiplayerSubScreen(++index)));
+ AddStep("push multi screen", () => screenStack.CurrentScreen.Push(new TestMultiplayerSubScreen(++index)));
}
private class TestMultiplayerSubScreen : OsuScreen, IMultiplayerSubScreen
diff --git a/osu.Game.Tests/Visual/TestCaseMultiScreen.cs b/osu.Game.Tests/Visual/TestCaseMultiScreen.cs
index 13419167a7..d83b90d6e1 100644
--- a/osu.Game.Tests/Visual/TestCaseMultiScreen.cs
+++ b/osu.Game.Tests/Visual/TestCaseMultiScreen.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using NUnit.Framework;
+using osu.Framework.Screens;
using osu.Game.Screens.Multi;
using osu.Game.Screens.Multi.Lounge;
using osu.Game.Screens.Multi.Lounge.Components;
diff --git a/osu.Game.Tests/Visual/TestCasePlayerLoader.cs b/osu.Game.Tests/Visual/TestCasePlayerLoader.cs
index fd3d838149..82ce7e125a 100644
--- a/osu.Game.Tests/Visual/TestCasePlayerLoader.cs
+++ b/osu.Game.Tests/Visual/TestCasePlayerLoader.cs
@@ -3,6 +3,7 @@
using System.Threading;
using osu.Framework.Allocation;
+using osu.Framework.Screens;
using osu.Game.Beatmaps;
using osu.Game.Screens.Play;
@@ -26,7 +27,7 @@ namespace osu.Game.Tests.Visual
AddStep("mouse in centre", () => InputManager.MoveMouseTo(loader.ScreenSpaceDrawQuad.Centre));
- AddUntilStep(() => !loader.IsCurrentScreen, "wait for no longer current");
+ AddUntilStep(() => !loader.IsCurrentScreen(), "wait for no longer current");
AddStep("load slow dummy beatmap", () =>
{
@@ -42,7 +43,7 @@ namespace osu.Game.Tests.Visual
Scheduler.AddDelayed(() => slow.Ready = true, 5000);
});
- AddUntilStep(() => !loader.IsCurrentScreen, "wait for no longer current");
+ AddUntilStep(() => !loader.IsCurrentScreen(), "wait for no longer current");
}
protected class SlowLoadPlayer : Player
diff --git a/osu.Game.Tests/Visual/TestCaseScreenBreadcrumbControl.cs b/osu.Game.Tests/Visual/TestCaseScreenBreadcrumbControl.cs
index 0f34e4f10a..7202861833 100644
--- a/osu.Game.Tests/Visual/TestCaseScreenBreadcrumbControl.cs
+++ b/osu.Game.Tests/Visual/TestCaseScreenBreadcrumbControl.cs
@@ -19,16 +19,18 @@ namespace osu.Game.Tests.Visual
public class TestCaseScreenBreadcrumbControl : OsuTestCase
{
private readonly ScreenBreadcrumbControl breadcrumbs;
- private Screen currentScreen, changedScreen;
+ private readonly ScreenStack screenStack;
public TestCaseScreenBreadcrumbControl()
{
- TestScreen startScreen;
OsuSpriteText titleText;
+ IScreen startScreen = new TestScreenOne();
+ screenStack = new ScreenStack(startScreen) { RelativeSizeAxes = Axes.Both };
+
Children = new Drawable[]
{
- currentScreen = startScreen = new TestScreenOne(),
+ screenStack,
new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
@@ -37,7 +39,7 @@ namespace osu.Game.Tests.Visual
Spacing = new Vector2(10),
Children = new Drawable[]
{
- breadcrumbs = new ScreenBreadcrumbControl(startScreen)
+ breadcrumbs = new ScreenBreadcrumbControl(screenStack)
{
RelativeSizeAxes = Axes.X,
},
@@ -46,12 +48,7 @@ namespace osu.Game.Tests.Visual
},
};
- breadcrumbs.Current.ValueChanged += s =>
- {
- titleText.Text = $"Changed to {s.ToString()}";
- changedScreen = s;
- };
-
+ breadcrumbs.Current.ValueChanged += s => titleText.Text = $"Changed to {s.ToString()}";
breadcrumbs.Current.TriggerChange();
waitForCurrent();
@@ -60,18 +57,14 @@ namespace osu.Game.Tests.Visual
pushNext();
waitForCurrent();
- AddStep(@"make start current", () =>
- {
- startScreen.MakeCurrent();
- currentScreen = startScreen;
- });
+ AddStep(@"make start current", () => startScreen.MakeCurrent());
waitForCurrent();
pushNext();
waitForCurrent();
AddAssert(@"only 2 items", () => breadcrumbs.Items.Count() == 2);
- AddStep(@"exit current", () => changedScreen.Exit());
- AddAssert(@"current screen is first", () => startScreen == changedScreen);
+ AddStep(@"exit current", () => screenStack.CurrentScreen.Exit());
+ AddAssert(@"current screen is first", () => startScreen == screenStack.CurrentScreen);
}
[BackgroundDependencyLoader]
@@ -80,8 +73,8 @@ namespace osu.Game.Tests.Visual
breadcrumbs.StripColour = colours.Blue;
}
- private void pushNext() => AddStep(@"push next screen", () => currentScreen = ((TestScreen)currentScreen).PushNext());
- private void waitForCurrent() => AddUntilStep(() => currentScreen.IsCurrentScreen, "current screen");
+ private void pushNext() => AddStep(@"push next screen", () => ((TestScreen)screenStack.CurrentScreen).PushNext());
+ private void waitForCurrent() => AddUntilStep(() => screenStack.CurrentScreen.IsCurrentScreen(), "current screen");
private abstract class TestScreen : OsuScreen
{
@@ -91,14 +84,14 @@ namespace osu.Game.Tests.Visual
public TestScreen PushNext()
{
TestScreen screen = CreateNextScreen();
- Push(screen);
+ this.Push(screen);
return screen;
}
protected TestScreen()
{
- Child = new FillFlowContainer
+ InternalChild = new FillFlowContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
diff --git a/osu.Game.Tests/WaveformTestBeatmap.cs b/osu.Game.Tests/WaveformTestBeatmap.cs
index 72db4b0c17..2028671b0e 100644
--- a/osu.Game.Tests/WaveformTestBeatmap.cs
+++ b/osu.Game.Tests/WaveformTestBeatmap.cs
@@ -8,7 +8,7 @@ using osu.Framework.Graphics.Textures;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Formats;
using osu.Game.IO.Archives;
-using osu.Game.Tests.Beatmaps.IO;
+using osu.Game.Tests.Resources;
namespace osu.Game.Tests
{
@@ -18,12 +18,12 @@ namespace osu.Game.Tests
public class WaveformTestBeatmap : WorkingBeatmap
{
private readonly ZipArchiveReader reader;
- private readonly FileStream stream;
+ private readonly Stream stream;
public WaveformTestBeatmap()
: base(new BeatmapInfo())
{
- stream = File.OpenRead(ImportBeatmapTest.TEST_OSZ_PATH);
+ stream = TestResources.GetTestBeatmapStream();
reader = new ZipArchiveReader(stream);
}
diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs
index 42048692fc..21739f16c2 100644
--- a/osu.Game/Beatmaps/BeatmapManager.cs
+++ b/osu.Game/Beatmaps/BeatmapManager.cs
@@ -163,18 +163,14 @@ namespace osu.Game.Beatmaps
downloadNotification.Progress = progress;
};
- request.Success += data =>
+ request.Success += filename =>
{
downloadNotification.Text = $"Importing {beatmapSetInfo.Metadata.Artist} - {beatmapSetInfo.Metadata.Title}";
Task.Factory.StartNew(() =>
{
- BeatmapSetInfo importedBeatmap;
-
// This gets scheduled back to the update thread, but we want the import to run in the background.
- using (var stream = new MemoryStream(data))
- using (var archive = new ZipArchiveReader(stream, beatmapSetInfo.ToString()))
- importedBeatmap = Import(archive);
+ var importedBeatmap = Import(filename);
downloadNotification.CompletionClickAction = () =>
{
diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs
index 4b6662178f..6bf9e2ff37 100644
--- a/osu.Game/Database/ArchiveModelManager.cs
+++ b/osu.Game/Database/ArchiveModelManager.cs
@@ -150,25 +150,9 @@ namespace osu.Game.Database
{
notification.Text = $"Importing ({++current} of {paths.Length})\n{Path.GetFileName(path)}";
- TModel import;
- using (ArchiveReader reader = getReaderFrom(path))
- imported.Add(import = Import(reader));
+ imported.Add(Import(path));
notification.Progress = (float)current / paths.Length;
-
- // We may or may not want to delete the file depending on where it is stored.
- // e.g. reconstructing/repairing database with items from default storage.
- // Also, not always a single file, i.e. for LegacyFilesystemReader
- // TODO: Add a check to prevent files from storage to be deleted.
- try
- {
- if (import != null && File.Exists(path))
- File.Delete(path);
- }
- catch (Exception e)
- {
- Logger.Error(e, $@"Could not delete original file after import ({Path.GetFileName(path)})");
- }
}
catch (Exception e)
{
@@ -195,6 +179,34 @@ namespace osu.Game.Database
}
}
+ ///
+ /// Import one from the filesystem and delete the file on success.
+ ///
+ /// The archive location on disk.
+ /// The imported model, if successful.
+ public TModel Import(string path)
+ {
+ TModel import;
+ using (ArchiveReader reader = getReaderFrom(path))
+ import = Import(reader);
+
+ // We may or may not want to delete the file depending on where it is stored.
+ // e.g. reconstructing/repairing database with items from default storage.
+ // Also, not always a single file, i.e. for LegacyFilesystemReader
+ // TODO: Add a check to prevent files from storage to be deleted.
+ try
+ {
+ if (import != null && File.Exists(path))
+ File.Delete(path);
+ }
+ catch (Exception e)
+ {
+ Logger.Error(e, $@"Could not delete original file after import ({Path.GetFileName(path)})");
+ }
+
+ return import;
+ }
+
protected virtual void PresentCompletedImport(IEnumerable imported)
{
}
diff --git a/osu.Game/Graphics/Cursor/MenuCursorContainer.cs b/osu.Game/Graphics/Cursor/MenuCursorContainer.cs
index a8870f3cf3..5f9b428dfc 100644
--- a/osu.Game/Graphics/Cursor/MenuCursorContainer.cs
+++ b/osu.Game/Graphics/Cursor/MenuCursorContainer.cs
@@ -50,6 +50,7 @@ namespace osu.Game.Graphics.Cursor
if (!CanShowCursor)
{
currentTarget?.Cursor?.Hide();
+ currentTarget = null;
return;
}
diff --git a/osu.Game/Graphics/UserInterface/ScreenBreadcrumbControl.cs b/osu.Game/Graphics/UserInterface/ScreenBreadcrumbControl.cs
index f7c907c5ed..6e01c69df5 100644
--- a/osu.Game/Graphics/UserInterface/ScreenBreadcrumbControl.cs
+++ b/osu.Game/Graphics/UserInterface/ScreenBreadcrumbControl.cs
@@ -10,45 +10,30 @@ namespace osu.Game.Graphics.UserInterface
///
/// A which follows the active screen (and allows navigation) in a stack.
///
- public class ScreenBreadcrumbControl : BreadcrumbControl
+ public class ScreenBreadcrumbControl : BreadcrumbControl
{
- private Screen last;
-
- public ScreenBreadcrumbControl(Screen initialScreen)
+ public ScreenBreadcrumbControl(ScreenStack stack)
{
- Current.ValueChanged += newScreen =>
- {
- if (last != newScreen && !newScreen.IsCurrentScreen)
- newScreen.MakeCurrent();
- };
+ stack.ScreenPushed += onPushed;
+ stack.ScreenExited += onExited;
- onPushed(initialScreen);
+ onPushed(null, stack.CurrentScreen);
+
+ Current.ValueChanged += newScreen => newScreen.MakeCurrent();
}
- private void screenChanged(Screen newScreen)
+ private void onPushed(IScreen lastScreen, IScreen newScreen)
{
- if (newScreen == null) return;
-
- if (last != null)
- {
- last.Exited -= screenChanged;
- last.ModePushed -= onPushed;
- }
-
- last = newScreen;
-
- newScreen.Exited += screenChanged;
- newScreen.ModePushed += onPushed;
-
+ AddItem(newScreen);
Current.Value = newScreen;
}
- private void onPushed(Screen screen)
+ private void onExited(IScreen lastScreen, IScreen newScreen)
{
- Items.ToList().SkipWhile(i => i != Current.Value).Skip(1).ForEach(RemoveItem);
- AddItem(screen);
+ if (newScreen != null)
+ Current.Value = newScreen;
- screenChanged(screen);
+ Items.ToList().SkipWhile(s => s != Current.Value).Skip(1).ForEach(RemoveItem);
}
}
}
diff --git a/osu.Game/Online/API/APIDownloadRequest.cs b/osu.Game/Online/API/APIDownloadRequest.cs
index b9449b57f2..97b869bccd 100644
--- a/osu.Game/Online/API/APIDownloadRequest.cs
+++ b/osu.Game/Online/API/APIDownloadRequest.cs
@@ -1,15 +1,18 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System.IO;
using osu.Framework.IO.Network;
namespace osu.Game.Online.API
{
public abstract class APIDownloadRequest : APIRequest
{
+ private string filename;
+
protected override WebRequest CreateWebRequest()
{
- var request = new WebRequest(Uri);
+ var request = new FileWebRequest(filename = Path.GetTempFileName(), Uri);
request.DownloadProgress += request_Progress;
return request;
}
@@ -23,11 +26,11 @@ namespace osu.Game.Online.API
private void onSuccess()
{
- Success?.Invoke(WebRequest.ResponseData);
+ Success?.Invoke(filename);
}
public event APIProgressHandler Progress;
- public new event APISuccessHandler Success;
+ public new event APISuccessHandler Success;
}
}
diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs
index d8499f4159..3cc040ecb1 100644
--- a/osu.Game/OsuGame.cs
+++ b/osu.Game/OsuGame.cs
@@ -79,27 +79,23 @@ namespace osu.Game
public virtual Storage GetStorageForStableInstall() => null;
- private Intro intro
- {
- get
- {
- Screen screen = screenStack;
- while (screen != null && !(screen is Intro))
- screen = screen.ChildScreen;
- return screen as Intro;
- }
- }
-
public float ToolbarOffset => Toolbar.Position.Y + Toolbar.DrawHeight;
private IdleTracker idleTracker;
public readonly Bindable OverlayActivationMode = new Bindable();
- private OsuScreen screenStack;
+ private BackgroundScreenStack backgroundStack;
+ private ParallaxContainer backgroundParallax;
+
+ private ScreenStack screenStack;
private VolumeOverlay volume;
private OnScreenDisplay onscreenDisplay;
+ private OsuLogo osuLogo;
+
+ private MainMenu menuScreen;
+ private Intro introScreen;
private Bindable configRuleset;
private readonly Bindable ruleset = new Bindable();
@@ -173,6 +169,8 @@ namespace osu.Game
dependencies.CacheAs(ruleset);
dependencies.CacheAs>(ruleset);
+ dependencies.Cache(osuLogo = new OsuLogo());
+
// bind config int to database RulesetInfo
configRuleset = LocalConfig.GetBindable(OsuSetting.Ruleset);
ruleset.Value = RulesetStore.GetRuleset(configRuleset.Value) ?? RulesetStore.AvailableRulesets.First();
@@ -211,6 +209,12 @@ namespace osu.Game
/// The beatmap to select.
public void PresentBeatmap(BeatmapSetInfo beatmap)
{
+ if (menuScreen == null)
+ {
+ Schedule(() => PresentBeatmap(beatmap));
+ return;
+ }
+
CloseAllOverlays(false);
void setBeatmap()
@@ -233,16 +237,15 @@ namespace osu.Game
}
}
- switch (currentScreen)
+ switch (screenStack.CurrentScreen)
{
case SongSelect _:
break;
default:
// navigate to song select if we are not already there.
- var menu = (MainMenu)intro.ChildScreen;
- menu.MakeCurrent();
- menu.LoadToSolo();
+ menuScreen.MakeCurrent();
+ menuScreen.LoadToSolo();
break;
}
@@ -268,9 +271,7 @@ namespace osu.Game
scoreLoad?.Cancel();
- var menu = intro.ChildScreen;
-
- if (menu == null)
+ if (menuScreen == null)
{
scoreLoad = Schedule(() => LoadScore(score, false));
return;
@@ -291,7 +292,7 @@ namespace osu.Game
return;
}
- if (!currentScreen.AllowExternalScreenChange)
+ if ((screenStack.CurrentScreen as IOsuScreen)?.AllowExternalScreenChange != true)
{
notifications.Post(new SimpleNotification
{
@@ -310,9 +311,9 @@ namespace osu.Game
void loadScore()
{
- if (!menu.IsCurrentScreen)
+ if (!menuScreen.IsCurrentScreen())
{
- menu.MakeCurrent();
+ menuScreen.MakeCurrent();
this.Delay(500).Schedule(loadScore, out scoreLoad);
return;
}
@@ -322,7 +323,7 @@ namespace osu.Game
Beatmap.Value = BeatmapManager.GetWorkingBeatmap(databasedBeatmap);
Beatmap.Value.Mods.Value = databasedScoreInfo.Mods;
- currentScreen.Push(new PlayerLoader(() => new ReplayPlayer(databasedScore)));
+ menuScreen.Push(new PlayerLoader(() => new ReplayPlayer(databasedScore)));
}
}
@@ -336,11 +337,6 @@ namespace osu.Game
{
base.LoadComplete();
- // The next time this is updated is in UpdateAfterChildren, which occurs too late and results
- // in the cursor being shown for a few frames during the intro.
- // This prevents the cursor from showing until we have a screen with CursorVisible = true
- MenuCursorContainer.CanShowCursor = currentScreen?.CursorVisible ?? false;
-
// todo: all archive managers should be able to be looped here.
SkinManager.PostNotification = n => notifications?.Post(n);
SkinManager.GetStableStorage = GetStorageForStableInstall;
@@ -350,6 +346,8 @@ namespace osu.Game
BeatmapManager.PresentBeatmap = PresentBeatmap;
+ Container logoContainer;
+
AddRange(new Drawable[]
{
new VolumeControlReceptor
@@ -361,6 +359,16 @@ namespace osu.Game
screenContainer = new ScalingContainer(ScalingMode.ExcludeOverlays)
{
RelativeSizeAxes = Axes.Both,
+ Children = new Drawable[]
+ {
+ backgroundParallax = new ParallaxContainer
+ {
+ RelativeSizeAxes = Axes.Both,
+ Child = backgroundStack = new BackgroundScreenStack { RelativeSizeAxes = Axes.Both },
+ },
+ screenStack = new ScreenStack { RelativeSizeAxes = Axes.Both },
+ logoContainer = new Container { RelativeSizeAxes = Axes.Both },
+ }
},
overlayContent = new Container
{
@@ -370,12 +378,17 @@ namespace osu.Game
idleTracker = new GameIdleTracker(6000)
});
- loadComponentSingleFile(screenStack = new Loader(), d =>
+ dependencies.Cache(backgroundStack);
+
+ screenStack.ScreenPushed += screenPushed;
+ screenStack.ScreenExited += screenExited;
+
+ loadComponentSingleFile(osuLogo, logoContainer.Add);
+
+ loadComponentSingleFile(new Loader
{
- screenStack.ModePushed += screenAdded;
- screenStack.Exited += screenRemoved;
- screenContainer.Add(screenStack);
- });
+ RelativeSizeAxes = Axes.Both
+ }, screenStack.Push);
loadComponentSingleFile(Toolbar = new Toolbar
{
@@ -383,7 +396,7 @@ namespace osu.Game
OnHome = delegate
{
CloseAllOverlays(false);
- intro?.ChildScreen?.MakeCurrent();
+ menuScreen?.MakeCurrent();
},
}, floatingOverlayContent.Add);
@@ -617,7 +630,7 @@ namespace osu.Game
public bool OnPressed(GlobalAction action)
{
- if (intro == null) return false;
+ if (introScreen == null) return false;
switch (action)
{
@@ -674,19 +687,20 @@ namespace osu.Game
private Container floatingOverlayContent;
- private OsuScreen currentScreen;
private FrameworkConfigManager frameworkConfig;
private ScalingContainer screenContainer;
protected override bool OnExiting()
{
- if (screenStack.ChildScreen == null) return false;
+ if (screenStack.CurrentScreen is Loader)
+ return false;
- if (intro == null) return true;
+ if (introScreen == null)
+ return true;
- if (!intro.DidLoadMenu || intro.ChildScreen != null)
+ if (!introScreen.DidLoadMenu || !(screenStack.CurrentScreen is Intro))
{
- Scheduler.Add(intro.MakeCurrent);
+ Scheduler.Add(introScreen.MakeCurrent);
return true;
}
@@ -711,7 +725,7 @@ namespace osu.Game
// we only want to apply these restrictions when we are inside a screen stack.
// the use case for not applying is in visual/unit tests.
- bool applyBeatmapRulesetRestrictions = !currentScreen?.AllowBeatmapRulesetChange ?? false;
+ bool applyBeatmapRulesetRestrictions = !(screenStack.CurrentScreen as IOsuScreen)?.AllowBeatmapRulesetChange ?? false;
ruleset.Disabled = applyBeatmapRulesetRestrictions;
Beatmap.Disabled = applyBeatmapRulesetRestrictions;
@@ -719,7 +733,7 @@ namespace osu.Game
screenContainer.Padding = new MarginPadding { Top = ToolbarOffset };
overlayContent.Padding = new MarginPadding { Top = ToolbarOffset };
- MenuCursorContainer.CanShowCursor = currentScreen?.CursorVisible ?? false;
+ MenuCursorContainer.CanShowCursor = (screenStack.CurrentScreen as IOsuScreen)?.CursorVisible ?? false;
}
///
@@ -748,24 +762,41 @@ namespace osu.Game
this.ruleset.Disabled = rulesetDisabled;
}
- protected virtual void ScreenChanged(OsuScreen current, Screen newScreen)
+ protected virtual void ScreenChanged(IScreen lastScreen, IScreen newScreen)
{
- currentScreen = (OsuScreen)newScreen;
+ switch (newScreen)
+ {
+ case Intro intro:
+ introScreen = intro;
+ break;
+ case MainMenu menu:
+ menuScreen = menu;
+ break;
+ }
+
+ if (newScreen is IOsuScreen newOsuScreen)
+ {
+ backgroundParallax.ParallaxAmount = ParallaxContainer.DEFAULT_PARALLAX_AMOUNT * newOsuScreen.BackgroundParallaxAmount;
+
+ OverlayActivationMode.Value = newOsuScreen.InitialOverlayActivationMode;
+
+ if (newOsuScreen.HideOverlaysOnEnter)
+ CloseAllOverlays();
+ else
+ Toolbar.State = Visibility.Visible;
+ }
}
- private void screenAdded(Screen newScreen)
+ private void screenPushed(IScreen lastScreen, IScreen newScreen)
{
- ScreenChanged(currentScreen, newScreen);
+ ScreenChanged(lastScreen, newScreen);
Logger.Log($"Screen changed → {newScreen}");
-
- newScreen.ModePushed += screenAdded;
- newScreen.Exited += screenRemoved;
}
- private void screenRemoved(Screen newScreen)
+ private void screenExited(IScreen lastScreen, IScreen newScreen)
{
- ScreenChanged(currentScreen, newScreen);
- Logger.Log($"Screen changed ← {currentScreen}");
+ ScreenChanged(lastScreen, newScreen);
+ Logger.Log($"Screen changed ← {newScreen}");
if (newScreen == null)
Exit();
diff --git a/osu.Game/Overlays/AccountCreation/AccountCreationScreen.cs b/osu.Game/Overlays/AccountCreation/AccountCreationScreen.cs
index 071e1d0ffa..7e2ae405cb 100644
--- a/osu.Game/Overlays/AccountCreation/AccountCreationScreen.cs
+++ b/osu.Game/Overlays/AccountCreation/AccountCreationScreen.cs
@@ -8,22 +8,22 @@ namespace osu.Game.Overlays.AccountCreation
{
public abstract class AccountCreationScreen : Screen
{
- protected override void OnEntering(Screen last)
+ public override void OnEntering(IScreen last)
{
base.OnEntering(last);
- Content.FadeOut().Delay(200).FadeIn(200);
+ this.FadeOut().Delay(200).FadeIn(200);
}
- protected override void OnResuming(Screen last)
+ public override void OnResuming(IScreen last)
{
base.OnResuming(last);
- Content.FadeIn(200);
+ this.FadeIn(200);
}
- protected override void OnSuspending(Screen next)
+ public override void OnSuspending(IScreen next)
{
base.OnSuspending(next);
- Content.FadeOut(200);
+ this.FadeOut(200);
}
}
}
diff --git a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs
index b0d08d3c6c..02925a08e7 100644
--- a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs
+++ b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs
@@ -44,7 +44,7 @@ namespace osu.Game.Overlays.AccountCreation
{
this.api = api;
- Children = new Drawable[]
+ InternalChildren = new Drawable[]
{
new FillFlowContainer
{
@@ -143,7 +143,7 @@ namespace osu.Game.Overlays.AccountCreation
focusNextTextbox();
}
- protected override void OnEntering(Screen last)
+ public override void OnEntering(IScreen last)
{
base.OnEntering(last);
processingOverlay.Hide();
diff --git a/osu.Game/Overlays/AccountCreation/ScreenWarning.cs b/osu.Game/Overlays/AccountCreation/ScreenWarning.cs
index cec0f1a767..3cc84e3562 100644
--- a/osu.Game/Overlays/AccountCreation/ScreenWarning.cs
+++ b/osu.Game/Overlays/AccountCreation/ScreenWarning.cs
@@ -26,12 +26,12 @@ namespace osu.Game.Overlays.AccountCreation
private const string help_centre_url = "/help/wiki/Help_Centre#login";
- protected override void OnEntering(Screen last)
+ public override void OnEntering(IScreen last)
{
if (string.IsNullOrEmpty(api.ProvidedUsername))
{
- Content.FadeOut();
- Push(new ScreenEntry());
+ this.FadeOut();
+ this.Push(new ScreenEntry());
return;
}
@@ -46,7 +46,7 @@ namespace osu.Game.Overlays.AccountCreation
if (string.IsNullOrEmpty(api.ProvidedUsername))
return;
- Children = new Drawable[]
+ InternalChildren = new Drawable[]
{
new Sprite
{
@@ -104,7 +104,7 @@ namespace osu.Game.Overlays.AccountCreation
new DangerousSettingsButton
{
Text = "I understand. This account isn't for me.",
- Action = () => Push(new ScreenEntry())
+ Action = () => this.Push(new ScreenEntry())
},
furtherAssistance = new LinkFlowContainer(cp => { cp.TextSize = 12; })
{
diff --git a/osu.Game/Overlays/AccountCreation/ScreenWelcome.cs b/osu.Game/Overlays/AccountCreation/ScreenWelcome.cs
index da59b294e5..d4b8323394 100644
--- a/osu.Game/Overlays/AccountCreation/ScreenWelcome.cs
+++ b/osu.Game/Overlays/AccountCreation/ScreenWelcome.cs
@@ -4,6 +4,7 @@
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
+using osu.Framework.Screens;
using osu.Game.Graphics.Sprites;
using osu.Game.Overlays.Settings;
using osu.Game.Screens.Menu;
@@ -16,7 +17,7 @@ namespace osu.Game.Overlays.AccountCreation
[BackgroundDependencyLoader]
private void load()
{
- Child = new FillFlowContainer
+ InternalChild = new FillFlowContainer
{
RelativeSizeAxes = Axes.Both,
Direction = FillDirection.Vertical,
@@ -56,7 +57,7 @@ namespace osu.Game.Overlays.AccountCreation
{
Text = "Let's create an account!",
Margin = new MarginPadding { Vertical = 120 },
- Action = () => Push(new ScreenWarning())
+ Action = () => this.Push(new ScreenWarning())
}
}
};
diff --git a/osu.Game/Overlays/AccountCreationOverlay.cs b/osu.Game/Overlays/AccountCreationOverlay.cs
index 718a56a441..dab960db25 100644
--- a/osu.Game/Overlays/AccountCreationOverlay.cs
+++ b/osu.Game/Overlays/AccountCreationOverlay.cs
@@ -6,6 +6,7 @@ using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
+using osu.Framework.Screens;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Online.API;
@@ -82,7 +83,7 @@ namespace osu.Game.Overlays
base.PopIn();
this.FadeIn(transition_time, Easing.OutQuint);
- if (welcomeScreen.ChildScreen != null)
+ if (welcomeScreen.GetChildScreen() != null)
welcomeScreen.MakeCurrent();
}
diff --git a/osu.Game/Screens/BackgroundScreen.cs b/osu.Game/Screens/BackgroundScreen.cs
index d2308ac1c3..bbe162cf7c 100644
--- a/osu.Game/Screens/BackgroundScreen.cs
+++ b/osu.Game/Screens/BackgroundScreen.cs
@@ -2,7 +2,6 @@
// See the LICENCE file in the repository root for full licence text.
using System;
-using System.Threading;
using osu.Framework.Screens;
using osu.Framework.Graphics;
using osu.Framework.Input.Events;
@@ -12,6 +11,12 @@ namespace osu.Game.Screens
{
public abstract class BackgroundScreen : Screen, IEquatable
{
+ protected BackgroundScreen()
+ {
+ Anchor = Anchor.Centre;
+ Origin = Anchor.Centre;
+ }
+
public virtual bool Equals(BackgroundScreen other)
{
return other?.GetType() == GetType();
@@ -26,64 +31,40 @@ namespace osu.Game.Screens
return false;
}
- public override void Push(Screen screen)
- {
- // When trying to push a non-loaded screen, load it asynchronously and re-invoke Push
- // once it's done.
- if (screen.LoadState == LoadState.NotLoaded)
- {
- LoadComponentAsync(screen, d => Push((BackgroundScreen)d));
- return;
- }
-
- // Make sure the in-progress loading is complete before pushing the screen.
- while (screen.LoadState < LoadState.Ready)
- Thread.Sleep(1);
-
- try
- {
- base.Push(screen);
- }
- catch (ScreenAlreadyExitedException)
- {
- // screen may have exited before the push was successful.
- }
- }
-
protected override void Update()
{
base.Update();
- Content.Scale = new Vector2(1 + x_movement_amount / DrawSize.X * 2);
+ Scale = new Vector2(1 + x_movement_amount / DrawSize.X * 2);
}
- protected override void OnEntering(Screen last)
+ public override void OnEntering(IScreen last)
{
- Content.FadeOut();
- Content.MoveToX(x_movement_amount);
+ this.FadeOut();
+ this.MoveToX(x_movement_amount);
- Content.FadeIn(transition_length, Easing.InOutQuart);
- Content.MoveToX(0, transition_length, Easing.InOutQuart);
+ this.FadeIn(transition_length, Easing.InOutQuart);
+ this.MoveToX(0, transition_length, Easing.InOutQuart);
base.OnEntering(last);
}
- protected override void OnSuspending(Screen next)
+ public override void OnSuspending(IScreen next)
{
- Content.MoveToX(-x_movement_amount, transition_length, Easing.InOutQuart);
+ this.MoveToX(-x_movement_amount, transition_length, Easing.InOutQuart);
base.OnSuspending(next);
}
- protected override bool OnExiting(Screen next)
+ public override bool OnExiting(IScreen next)
{
- Content.FadeOut(transition_length, Easing.OutExpo);
- Content.MoveToX(x_movement_amount, transition_length, Easing.OutExpo);
+ this.FadeOut(transition_length, Easing.OutExpo);
+ this.MoveToX(x_movement_amount, transition_length, Easing.OutExpo);
return base.OnExiting(next);
}
- protected override void OnResuming(Screen last)
+ public override void OnResuming(IScreen last)
{
- Content.MoveToX(0, transition_length, Easing.OutExpo);
+ this.MoveToX(0, transition_length, Easing.OutExpo);
base.OnResuming(last);
}
}
diff --git a/osu.Game/Screens/BackgroundScreenStack.cs b/osu.Game/Screens/BackgroundScreenStack.cs
new file mode 100644
index 0000000000..7bf167295c
--- /dev/null
+++ b/osu.Game/Screens/BackgroundScreenStack.cs
@@ -0,0 +1,32 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Collections.Generic;
+using osu.Framework.Graphics;
+using osu.Framework.Screens;
+using osuTK;
+
+namespace osu.Game.Screens
+{
+ public class BackgroundScreenStack : ScreenStack
+ {
+ public BackgroundScreenStack()
+ {
+ Scale = new Vector2(1.06f);
+ RelativeSizeAxes = Axes.Both;
+ }
+
+ //public float ParallaxAmount { set => parallax.ParallaxAmount = ParallaxContainer.DEFAULT_PARALLAX_AMOUNT * value; }
+
+ public new void Push(BackgroundScreen screen)
+ {
+ if (screen == null)
+ return;
+
+ if (EqualityComparer.Default.Equals((BackgroundScreen)CurrentScreen, screen))
+ return;
+
+ base.Push(screen);
+ }
+ }
+}
diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs
index 3313db15e2..8706cc6668 100644
--- a/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs
+++ b/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs
@@ -37,7 +37,7 @@ namespace osu.Game.Screens.Backgrounds
}
b.Depth = newDepth;
- Add(Background = b);
+ AddInternal(Background = b);
Background.BlurSigma = BlurTarget;
}));
});
diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenBlack.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenBlack.cs
index 2584739787..9e2559cc56 100644
--- a/osu.Game/Screens/Backgrounds/BackgroundScreenBlack.cs
+++ b/osu.Game/Screens/Backgrounds/BackgroundScreenBlack.cs
@@ -12,14 +12,14 @@ namespace osu.Game.Screens.Backgrounds
{
public BackgroundScreenBlack()
{
- Child = new Box
+ InternalChild = new Box
{
Colour = Color4.Black,
RelativeSizeAxes = Axes.Both,
};
}
- protected override void OnEntering(Screen last)
+ public override void OnEntering(IScreen last)
{
Show();
}
diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenCustom.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenCustom.cs
index 8792721600..0cb41bc562 100644
--- a/osu.Game/Screens/Backgrounds/BackgroundScreenCustom.cs
+++ b/osu.Game/Screens/Backgrounds/BackgroundScreenCustom.cs
@@ -12,7 +12,7 @@ namespace osu.Game.Screens.Backgrounds
public BackgroundScreenCustom(string textureName)
{
this.textureName = textureName;
- Add(new Background(textureName));
+ AddInternal(new Background(textureName));
}
public override bool Equals(BackgroundScreen other)
diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs
index 9789248660..072da7c66e 100644
--- a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs
+++ b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs
@@ -42,7 +42,7 @@ namespace osu.Game.Screens.Backgrounds
Background?.FadeOut(800, Easing.InOutSine);
Background?.Expire();
- Add(Background = newBackground);
+ AddInternal(Background = newBackground);
currentDisplay++;
}
diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs
index e4ef023a7a..ac5ff504a2 100644
--- a/osu.Game/Screens/Edit/Editor.cs
+++ b/osu.Game/Screens/Edit/Editor.cs
@@ -28,7 +28,7 @@ namespace osu.Game.Screens.Edit
{
protected override BackgroundScreen CreateBackground() => new BackgroundScreenCustom(@"Backgrounds/bg4");
- protected override bool HideOverlaysOnEnter => true;
+ public override bool HideOverlaysOnEnter => true;
public override bool AllowBeatmapRulesetChange => false;
private Box bottomBackground;
@@ -65,7 +65,7 @@ namespace osu.Game.Screens.Edit
SummaryTimeline timeline;
PlaybackControl playback;
- Children = new[]
+ InternalChildren = new[]
{
new Container
{
@@ -96,7 +96,7 @@ namespace osu.Game.Screens.Edit
{
new EditorMenuItem("Export", MenuItemType.Standard, exportBeatmap),
new EditorMenuItemSpacer(),
- new EditorMenuItem("Exit", MenuItemType.Standard, Exit)
+ new EditorMenuItem("Exit", MenuItemType.Standard, this.Exit)
}
}
}
@@ -194,20 +194,20 @@ namespace osu.Game.Screens.Edit
return true;
}
- protected override void OnResuming(Screen last)
+ public override void OnResuming(IScreen last)
{
Beatmap.Value.Track?.Stop();
base.OnResuming(last);
}
- protected override void OnEntering(Screen last)
+ public override void OnEntering(IScreen last)
{
base.OnEntering(last);
Background.FadeColour(Color4.DarkGray, 500);
Beatmap.Value.Track?.Stop();
}
- protected override bool OnExiting(Screen next)
+ public override bool OnExiting(IScreen next)
{
Background.FadeColour(Color4.White, 500);
if (Beatmap.Value.Track != null)
diff --git a/osu.Game/Screens/IOsuScreen.cs b/osu.Game/Screens/IOsuScreen.cs
new file mode 100644
index 0000000000..532d4963a0
--- /dev/null
+++ b/osu.Game/Screens/IOsuScreen.cs
@@ -0,0 +1,39 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Screens;
+using osu.Game.Overlays;
+
+namespace osu.Game.Screens
+{
+ public interface IOsuScreen : IScreen
+ {
+ ///
+ /// Whether the beatmap or ruleset should be allowed to be changed by the user or game.
+ /// Used to mark exclusive areas where this is strongly prohibited, like gameplay.
+ ///
+ bool AllowBeatmapRulesetChange { get; }
+
+ bool AllowExternalScreenChange { get; }
+
+ ///
+ /// Whether this allows the cursor to be displayed.
+ ///
+ bool CursorVisible { get; }
+
+ ///
+ /// Whether all overlays should be hidden when this screen is entered or resumed.
+ ///
+ bool HideOverlaysOnEnter { get; }
+
+ ///
+ /// Whether overlays should be able to be opened once this screen is entered or resumed.
+ ///
+ OverlayActivation InitialOverlayActivationMode { get; }
+
+ ///
+ /// The amount of parallax to be applied while this screen is displayed.
+ ///
+ float BackgroundParallaxAmount { get; }
+ }
+}
diff --git a/osu.Game/Screens/Loader.cs b/osu.Game/Screens/Loader.cs
index 78e80766b2..9703d79442 100644
--- a/osu.Game/Screens/Loader.cs
+++ b/osu.Game/Screens/Loader.cs
@@ -17,9 +17,9 @@ namespace osu.Game.Screens
{
private bool showDisclaimer;
- protected override bool HideOverlaysOnEnter => true;
+ public override bool HideOverlaysOnEnter => true;
- protected override OverlayActivation InitialOverlayActivationMode => OverlayActivation.Disabled;
+ public override OverlayActivation InitialOverlayActivationMode => OverlayActivation.Disabled;
protected override bool AllowBackButton => false;
@@ -55,11 +55,11 @@ namespace osu.Game.Screens
protected virtual ShaderPrecompiler CreateShaderPrecompiler() => new ShaderPrecompiler();
- protected override void OnEntering(Screen last)
+ public override void OnEntering(IScreen last)
{
base.OnEntering(last);
- LoadComponentAsync(precompiler = CreateShaderPrecompiler(), Add);
+ LoadComponentAsync(precompiler = CreateShaderPrecompiler(), AddInternal);
LoadComponentAsync(loadableScreen = CreateLoadableScreen());
checkIfLoaded();
@@ -73,7 +73,7 @@ namespace osu.Game.Screens
return;
}
- Push(loadableScreen);
+ this.Push(loadableScreen);
}
[BackgroundDependencyLoader]
diff --git a/osu.Game/Screens/Menu/Disclaimer.cs b/osu.Game/Screens/Menu/Disclaimer.cs
index ed0ae3309c..c0ff37cc0b 100644
--- a/osu.Game/Screens/Menu/Disclaimer.cs
+++ b/osu.Game/Screens/Menu/Disclaimer.cs
@@ -23,8 +23,8 @@ namespace osu.Game.Screens.Menu
private Color4 iconColour;
private LinkFlowContainer textFlow;
- protected override bool HideOverlaysOnEnter => true;
- protected override OverlayActivation InitialOverlayActivationMode => OverlayActivation.Disabled;
+ public override bool HideOverlaysOnEnter => true;
+ public override OverlayActivation InitialOverlayActivationMode => OverlayActivation.Disabled;
public override bool CursorVisible => false;
@@ -41,7 +41,7 @@ namespace osu.Game.Screens.Menu
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
- Children = new Drawable[]
+ InternalChildren = new Drawable[]
{
icon = new SpriteIcon
{
@@ -116,7 +116,7 @@ namespace osu.Game.Screens.Menu
LoadComponentAsync(intro = new Intro());
}
- protected override void OnEntering(Screen last)
+ public override void OnEntering(IScreen last)
{
base.OnEntering(last);
@@ -130,12 +130,12 @@ namespace osu.Game.Screens.Menu
supporterDrawables.ForEach(d => d.FadeOut().Delay(2000).FadeIn(500));
- Content
+ this
.FadeInFromZero(500)
.Then(5500)
.FadeOut(250)
.ScaleTo(0.9f, 250, Easing.InQuint)
- .Finally(d => Push(intro));
+ .Finally(d => this.Push(intro));
heart.FlashColour(Color4.White, 750, Easing.OutQuint).Loop();
}
diff --git a/osu.Game/Screens/Menu/Intro.cs b/osu.Game/Screens/Menu/Intro.cs
index 93a84ec14d..3a347342d7 100644
--- a/osu.Game/Screens/Menu/Intro.cs
+++ b/osu.Game/Screens/Menu/Intro.cs
@@ -34,8 +34,8 @@ namespace osu.Game.Screens.Menu
private SampleChannel welcome;
private SampleChannel seeya;
- protected override bool HideOverlaysOnEnter => true;
- protected override OverlayActivation InitialOverlayActivationMode => OverlayActivation.Disabled;
+ public override bool HideOverlaysOnEnter => true;
+ public override OverlayActivation InitialOverlayActivationMode => OverlayActivation.Disabled;
public override bool CursorVisible => false;
@@ -111,7 +111,7 @@ namespace osu.Game.Screens.Menu
Scheduler.AddDelayed(delegate
{
DidLoadMenu = true;
- Push(mainMenu);
+ this.Push(mainMenu);
}, delay_step_one);
}, delay_step_two);
}
@@ -145,22 +145,21 @@ namespace osu.Game.Screens.Menu
}
}
- protected override void OnSuspending(Screen next)
+ public override void OnSuspending(IScreen next)
{
- Content.FadeOut(300);
+ this.FadeOut(300);
base.OnSuspending(next);
}
- protected override bool OnExiting(Screen next)
+ public override bool OnExiting(IScreen next)
{
//cancel exiting if we haven't loaded the menu yet.
return !DidLoadMenu;
}
- protected override void OnResuming(Screen last)
+ public override void OnResuming(IScreen last)
{
- if (!(last is MainMenu))
- Content.FadeIn(300);
+ this.FadeIn(300);
double fadeOutTime = EXIT_DELAY;
//we also handle the exit transition.
@@ -169,7 +168,7 @@ namespace osu.Game.Screens.Menu
else
fadeOutTime = 500;
- Scheduler.AddDelayed(Exit, fadeOutTime);
+ Scheduler.AddDelayed(this.Exit, fadeOutTime);
//don't want to fade out completely else we will stop running updates and shit will hit the fan.
Game.FadeTo(0.01f, fadeOutTime);
diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs
index 800bf8990e..04bc80ac87 100644
--- a/osu.Game/Screens/Menu/MainMenu.cs
+++ b/osu.Game/Screens/Menu/MainMenu.cs
@@ -25,28 +25,25 @@ namespace osu.Game.Screens.Menu
{
private readonly ButtonSystem buttons;
- protected override bool HideOverlaysOnEnter => buttons.State == ButtonSystemState.Initial;
+ public override bool HideOverlaysOnEnter => buttons.State == ButtonSystemState.Initial;
protected override bool AllowBackButton => buttons.State != ButtonSystemState.Initial;
public override bool AllowExternalScreenChange => true;
- private readonly BackgroundScreenDefault background;
private Screen songSelect;
private readonly MenuSideFlashes sideFlashes;
- protected override BackgroundScreen CreateBackground() => background;
+ protected override BackgroundScreen CreateBackground() => new BackgroundScreenDefault();
public MainMenu()
{
- background = new BackgroundScreenDefault();
-
- Children = new Drawable[]
+ InternalChildren = new Drawable[]
{
new ExitConfirmOverlay
{
- Action = Exit,
+ Action = this.Exit,
},
new ParallaxContainer
{
@@ -55,12 +52,12 @@ namespace osu.Game.Screens.Menu
{
buttons = new ButtonSystem
{
- OnChart = delegate { Push(new ChartListing()); },
- OnDirect = delegate { Push(new OnlineListing()); },
- OnEdit = delegate { Push(new Editor()); },
+ OnChart = delegate { this.Push(new ChartListing()); },
+ OnDirect = delegate {this.Push(new OnlineListing()); },
+ OnEdit = delegate {this.Push(new Editor()); },
OnSolo = onSolo,
- OnMulti = delegate { Push(new Multiplayer()); },
- OnExit = Exit,
+ OnMulti = delegate {this.Push(new Multiplayer()); },
+ OnExit = this.Exit,
}
}
},
@@ -73,10 +70,10 @@ namespace osu.Game.Screens.Menu
{
case ButtonSystemState.Initial:
case ButtonSystemState.Exit:
- background.FadeColour(Color4.White, 500, Easing.OutSine);
+ Background.FadeColour(Color4.White, 500, Easing.OutSine);
break;
default:
- background.FadeColour(OsuColour.Gray(0.8f), 500, Easing.OutSine);
+ Background.FadeColour(OsuColour.Gray(0.8f), 500, Easing.OutSine);
break;
}
};
@@ -85,8 +82,6 @@ namespace osu.Game.Screens.Menu
[BackgroundDependencyLoader(true)]
private void load(OsuGame game = null)
{
- LoadComponentAsync(background);
-
if (game != null)
{
buttons.OnSettings = game.ToggleSettings;
@@ -104,7 +99,7 @@ namespace osu.Game.Screens.Menu
public void LoadToSolo() => Schedule(onSolo);
- private void onSolo() => Push(consumeSongSelect());
+ private void onSolo() =>this.Push(consumeSongSelect());
private Screen consumeSongSelect()
{
@@ -113,7 +108,7 @@ namespace osu.Game.Screens.Menu
return s;
}
- protected override void OnEntering(Screen last)
+ public override void OnEntering(IScreen last)
{
base.OnEntering(last);
buttons.FadeInFromZero(500);
@@ -148,8 +143,8 @@ namespace osu.Game.Screens.Menu
const float length = 300;
- Content.FadeIn(length, Easing.OutQuint);
- Content.MoveTo(new Vector2(0, 0), length, Easing.OutQuint);
+ this.FadeIn(length, Easing.OutQuint);
+ this.MoveTo(new Vector2(0, 0), length, Easing.OutQuint);
sideFlashes.Delay(length).FadeIn(64, Easing.InQuint);
}
@@ -164,13 +159,13 @@ namespace osu.Game.Screens.Menu
private void beatmap_ValueChanged(WorkingBeatmap newValue)
{
- if (!IsCurrentScreen)
+ if (!this.IsCurrentScreen())
return;
- background.Next();
+ ((BackgroundScreenDefault)Background).Next();
}
- protected override void OnSuspending(Screen next)
+ public override void OnSuspending(IScreen next)
{
base.OnSuspending(next);
@@ -178,26 +173,26 @@ namespace osu.Game.Screens.Menu
buttons.State = ButtonSystemState.EnteringMode;
- Content.FadeOut(length, Easing.InSine);
- Content.MoveTo(new Vector2(-800, 0), length, Easing.InSine);
+ this.FadeOut(length, Easing.InSine);
+ this.MoveTo(new Vector2(-800, 0), length, Easing.InSine);
sideFlashes.FadeOut(64, Easing.OutQuint);
}
- protected override void OnResuming(Screen last)
+ public override void OnResuming(IScreen last)
{
base.OnResuming(last);
- background.Next();
+ ((BackgroundScreenDefault)Background).Next();
//we may have consumed our preloaded instance, so let's make another.
preloadSongSelect();
}
- protected override bool OnExiting(Screen next)
+ public override bool OnExiting(IScreen next)
{
buttons.State = ButtonSystemState.Exit;
- Content.FadeOut(3000);
+ this.FadeOut(3000);
return base.OnExiting(next);
}
@@ -205,7 +200,7 @@ namespace osu.Game.Screens.Menu
{
if (!e.Repeat && e.ControlPressed && e.ShiftPressed && e.Key == Key.D)
{
- Push(new Drawings());
+ this.Push(new Drawings());
return true;
}
diff --git a/osu.Game/Screens/Multi/Header.cs b/osu.Game/Screens/Multi/Header.cs
index 3448a23ac8..687a28b7a6 100644
--- a/osu.Game/Screens/Multi/Header.cs
+++ b/osu.Game/Screens/Multi/Header.cs
@@ -22,7 +22,7 @@ namespace osu.Game.Screens.Multi
private readonly OsuSpriteText screenType;
private readonly HeaderBreadcrumbControl breadcrumbs;
- public Header(Screen initialScreen)
+ public Header(ScreenStack stack)
{
RelativeSizeAxes = Axes.X;
Height = HEIGHT;
@@ -75,7 +75,7 @@ namespace osu.Game.Screens.Multi
},
},
},
- breadcrumbs = new HeaderBreadcrumbControl(initialScreen)
+ breadcrumbs = new HeaderBreadcrumbControl(stack)
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
@@ -103,8 +103,8 @@ namespace osu.Game.Screens.Multi
private class HeaderBreadcrumbControl : ScreenBreadcrumbControl
{
- public HeaderBreadcrumbControl(Screen initialScreen)
- : base(initialScreen)
+ public HeaderBreadcrumbControl(ScreenStack stack)
+ : base(stack)
{
}
diff --git a/osu.Game/Screens/Multi/IMultiplayerSubScreen.cs b/osu.Game/Screens/Multi/IMultiplayerSubScreen.cs
index 542224262e..31ee123f83 100644
--- a/osu.Game/Screens/Multi/IMultiplayerSubScreen.cs
+++ b/osu.Game/Screens/Multi/IMultiplayerSubScreen.cs
@@ -3,8 +3,10 @@
namespace osu.Game.Screens.Multi
{
- public interface IMultiplayerSubScreen
+ public interface IMultiplayerSubScreen : IOsuScreen
{
+ string Title { get; }
+
string ShortTitle { get; }
}
}
diff --git a/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs
index 28ec5d2d1a..a56d2892a4 100644
--- a/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs
+++ b/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs
@@ -2,7 +2,6 @@
// See the LICENCE file in the repository root for full licence text.
using System;
-using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Events;
@@ -17,6 +16,8 @@ namespace osu.Game.Screens.Multi.Lounge
{
public class LoungeSubScreen : MultiplayerSubScreen
{
+ public override string Title => "Lounge";
+
protected readonly FilterControl Filter;
private readonly Container content;
@@ -24,20 +25,13 @@ namespace osu.Game.Screens.Multi.Lounge
private readonly Action pushGameplayScreen;
private readonly ProcessingOverlay processingOverlay;
- [Resolved(CanBeNull = true)]
- private IRoomManager roomManager { get; set; }
-
- public override string Title => "Lounge";
-
- protected override Drawable TransitionContent => content;
-
public LoungeSubScreen(Action pushGameplayScreen)
{
this.pushGameplayScreen = pushGameplayScreen;
RoomInspector inspector;
- Children = new Drawable[]
+ InternalChildren = new Drawable[]
{
Filter = new FilterControl { Depth = -1 },
content = new Container
@@ -81,7 +75,7 @@ namespace osu.Game.Screens.Multi.Lounge
Filter.Search.Current.ValueChanged += s => filterRooms();
Filter.Tabs.Current.ValueChanged += t => filterRooms();
- Filter.Search.Exit += Exit;
+ Filter.Search.Exit += this.Exit;
}
protected override void UpdateAfterChildren()
@@ -91,8 +85,8 @@ namespace osu.Game.Screens.Multi.Lounge
content.Padding = new MarginPadding
{
Top = Filter.DrawHeight,
- Left = SearchableListOverlay.WIDTH_PADDING - DrawableRoom.SELECTION_BORDER_WIDTH + HORIZONTAL_OVERFLOW_PADDING,
- Right = SearchableListOverlay.WIDTH_PADDING + HORIZONTAL_OVERFLOW_PADDING,
+ Left = SearchableListOverlay.WIDTH_PADDING - DrawableRoom.SELECTION_BORDER_WIDTH + OsuScreen.HORIZONTAL_OVERFLOW_PADDING,
+ Right = SearchableListOverlay.WIDTH_PADDING + OsuScreen.HORIZONTAL_OVERFLOW_PADDING,
};
}
@@ -101,20 +95,19 @@ namespace osu.Game.Screens.Multi.Lounge
Filter.Search.TakeFocus();
}
- protected override void OnEntering(Screen last)
+ public override void OnEntering(IScreen last)
{
base.OnEntering(last);
Filter.Search.HoldFocus = true;
}
- protected override bool OnExiting(Screen next)
+ public override bool OnExiting(IScreen next)
{
Filter.Search.HoldFocus = false;
- // no base call; don't animate
- return false;
+ return base.OnExiting(next);
}
- protected override void OnSuspending(Screen next)
+ public override void OnSuspending(IScreen next)
{
base.OnSuspending(next);
Filter.Search.HoldFocus = false;
@@ -123,13 +116,13 @@ namespace osu.Game.Screens.Multi.Lounge
private void filterRooms()
{
rooms.Filter(Filter.CreateCriteria());
- roomManager?.Filter(Filter.CreateCriteria());
+ Manager?.Filter(Filter.CreateCriteria());
}
private void joinRequested(Room room)
{
processingOverlay.Show();
- roomManager?.JoinRoom(room, r =>
+ Manager?.JoinRoom(room, r =>
{
Push(room);
processingOverlay.Hide();
@@ -142,10 +135,10 @@ namespace osu.Game.Screens.Multi.Lounge
public void Push(Room room)
{
// Handles the case where a room is clicked 3 times in quick succession
- if (!IsCurrentScreen)
+ if (!this.IsCurrentScreen())
return;
- Push(new MatchSubScreen(room, s => pushGameplayScreen?.Invoke(s)));
+ this.Push(new MatchSubScreen(room, s => pushGameplayScreen?.Invoke(s)));
}
}
}
diff --git a/osu.Game/Screens/Multi/Match/MatchSubScreen.cs b/osu.Game/Screens/Multi/Match/MatchSubScreen.cs
index 1b0efbdf09..980f321c92 100644
--- a/osu.Game/Screens/Multi/Match/MatchSubScreen.cs
+++ b/osu.Game/Screens/Multi/Match/MatchSubScreen.cs
@@ -21,6 +21,7 @@ namespace osu.Game.Screens.Multi.Match
public class MatchSubScreen : MultiplayerSubScreen
{
public override bool AllowBeatmapRulesetChange => false;
+
public override string Title => room.RoomID.Value == null ? "New room" : room.Name.Value;
public override string ShortTitle => "room";
@@ -36,12 +37,6 @@ namespace osu.Game.Screens.Multi.Match
[Resolved]
private BeatmapManager beatmapManager { get; set; }
- [Resolved(CanBeNull = true)]
- private OsuGame game { get; set; }
-
- [Resolved(CanBeNull = true)]
- private IRoomManager manager { get; set; }
-
public MatchSubScreen(Room room, Action pushGameplayScreen)
{
this.room = room;
@@ -55,7 +50,7 @@ namespace osu.Game.Screens.Multi.Match
GridContainer bottomRow;
MatchSettingsOverlay settings;
- Children = new Drawable[]
+ InternalChildren = new Drawable[]
{
new GridContainer
{
@@ -77,7 +72,7 @@ namespace osu.Game.Screens.Multi.Match
{
Padding = new MarginPadding
{
- Left = 10 + HORIZONTAL_OVERFLOW_PADDING,
+ Left = 10 + OsuScreen.HORIZONTAL_OVERFLOW_PADDING,
Right = 10,
Vertical = 10,
},
@@ -89,7 +84,7 @@ namespace osu.Game.Screens.Multi.Match
Padding = new MarginPadding
{
Left = 10,
- Right = 10 + HORIZONTAL_OVERFLOW_PADDING,
+ Right = 10 + OsuScreen.HORIZONTAL_OVERFLOW_PADDING,
Vertical = 10,
},
RelativeSizeAxes = Axes.Both,
@@ -118,10 +113,9 @@ namespace osu.Game.Screens.Multi.Match
},
};
- header.OnRequestSelectBeatmap = () => Push(new MatchSongSelect
+ header.OnRequestSelectBeatmap = () => this.Push(new MatchSongSelect
{
Selected = addPlaylistItem,
- Padding = new MarginPadding { Horizontal = HORIZONTAL_OVERFLOW_PADDING }
});
header.Tabs.Current.ValueChanged += t =>
@@ -141,7 +135,11 @@ namespace osu.Game.Screens.Multi.Match
}
};
- chat.Exit += Exit;
+ chat.Exit += () =>
+ {
+ if (this.IsCurrentScreen())
+ this.Exit();
+ };
}
[BackgroundDependencyLoader]
@@ -150,9 +148,9 @@ namespace osu.Game.Screens.Multi.Match
beatmapManager.ItemAdded += beatmapAdded;
}
- protected override bool OnExiting(Screen next)
+ public override bool OnExiting(IScreen next)
{
- manager?.PartRoom();
+ Manager?.PartRoom();
return base.OnExiting(next);
}
@@ -169,7 +167,7 @@ namespace osu.Game.Screens.Multi.Match
// Retrieve the corresponding local beatmap, since we can't directly use the playlist's beatmap info
var localBeatmap = beatmap == null ? null : beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == beatmap.OnlineBeatmapID);
- game?.ForcefullySetBeatmap(beatmapManager.GetWorkingBeatmap(localBeatmap));
+ Game?.ForcefullySetBeatmap(beatmapManager.GetWorkingBeatmap(localBeatmap));
}
private void setRuleset(RulesetInfo ruleset)
@@ -177,7 +175,7 @@ namespace osu.Game.Screens.Multi.Match
if (ruleset == null)
return;
- game?.ForcefullySetRuleset(ruleset);
+ Game?.ForcefullySetRuleset(ruleset);
}
private void beatmapAdded(BeatmapSetInfo model, bool existing, bool silent) => Schedule(() =>
@@ -192,7 +190,7 @@ namespace osu.Game.Screens.Multi.Match
var localBeatmap = beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == bindings.CurrentBeatmap.Value.OnlineBeatmapID);
if (localBeatmap != null)
- game?.ForcefullySetBeatmap(beatmapManager.GetWorkingBeatmap(localBeatmap));
+ Game?.ForcefullySetBeatmap(beatmapManager.GetWorkingBeatmap(localBeatmap));
});
private void addPlaylistItem(PlaylistItem item)
@@ -209,11 +207,9 @@ namespace osu.Game.Screens.Multi.Match
{
default:
case GameTypeTimeshift _:
- pushGameplayScreen?.Invoke(new PlayerLoader(() => {
- var player = new TimeshiftPlayer(room, room.Playlist.First().ID);
- player.Exited += _ => leaderboard.RefreshScores();
-
- return player;
+ pushGameplayScreen?.Invoke(new PlayerLoader(() => new TimeshiftPlayer(room, room.Playlist.First().ID)
+ {
+ Exited = () => leaderboard.RefreshScores()
}));
break;
}
diff --git a/osu.Game/Screens/Multi/Multiplayer.cs b/osu.Game/Screens/Multi/Multiplayer.cs
index da15574029..1741ac0b7b 100644
--- a/osu.Game/Screens/Multi/Multiplayer.cs
+++ b/osu.Game/Screens/Multi/Multiplayer.cs
@@ -8,6 +8,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Logging;
using osu.Framework.Screens;
+using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.Containers;
@@ -15,6 +16,7 @@ using osu.Game.Graphics.UserInterface;
using osu.Game.Input;
using osu.Game.Online.API;
using osu.Game.Online.Multiplayer;
+using osu.Game.Overlays;
using osu.Game.Overlays.BeatmapSet.Buttons;
using osu.Game.Screens.Menu;
using osu.Game.Screens.Multi.Lounge;
@@ -24,31 +26,56 @@ using osuTK;
namespace osu.Game.Screens.Multi
{
[Cached]
- public class Multiplayer : OsuScreen, IOnlineComponent
+ public class Multiplayer : CompositeDrawable, IOsuScreen, IOnlineComponent
{
- private readonly MultiplayerWaveContainer waves;
+ public bool AllowBeatmapRulesetChange => (screenStack.CurrentScreen as IMultiplayerSubScreen)?.AllowBeatmapRulesetChange ?? true;
+ public bool AllowExternalScreenChange => (screenStack.CurrentScreen as IMultiplayerSubScreen)?.AllowExternalScreenChange ?? true;
+ public bool CursorVisible => (screenStack.CurrentScreen as IMultiplayerSubScreen)?.AllowExternalScreenChange ?? true;
- public override bool AllowBeatmapRulesetChange => currentSubScreen?.AllowBeatmapRulesetChange ?? base.AllowBeatmapRulesetChange;
+ public bool HideOverlaysOnEnter => false;
+ public OverlayActivation InitialOverlayActivationMode => OverlayActivation.All;
+
+ public float BackgroundParallaxAmount => 1;
+
+ public bool ValidForResume { get; set; } = true;
+ public bool ValidForPush { get; set; } = true;
+
+ public override bool RemoveWhenNotAlive => false;
+
+ private readonly MultiplayerWaveContainer waves;
private readonly OsuButton createButton;
private readonly LoungeSubScreen loungeSubScreen;
-
- private OsuScreen currentSubScreen;
+ private readonly ScreenStack screenStack;
[Cached(Type = typeof(IRoomManager))]
private RoomManager roomManager;
+ [Resolved]
+ private IBindableBeatmap beatmap { get; set; }
+
+ [Resolved]
+ private OsuGameBase game { get; set; }
+
[Resolved]
private APIAccess api { get; set; }
+ [Resolved(CanBeNull = true)]
+ private OsuLogo logo { get; set; }
+
public Multiplayer()
{
- Child = waves = new MultiplayerWaveContainer
+ Anchor = Anchor.Centre;
+ Origin = Anchor.Centre;
+ RelativeSizeAxes = Axes.Both;
+
+ InternalChild = waves = new MultiplayerWaveContainer
{
RelativeSizeAxes = Axes.Both,
};
- Padding = new MarginPadding { Horizontal = -HORIZONTAL_OVERFLOW_PADDING };
+ screenStack = new ScreenStack(loungeSubScreen = new LoungeSubScreen(this.Push)) { RelativeSizeAxes = Axes.Both };
+ Padding = new MarginPadding { Horizontal = -OsuScreen.HORIZONTAL_OVERFLOW_PADDING };
waves.AddRange(new Drawable[]
{
@@ -76,9 +103,9 @@ namespace osu.Game.Screens.Multi
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Top = Header.HEIGHT },
- Child = loungeSubScreen = new LoungeSubScreen(Push),
+ Child = screenStack
},
- new Header(loungeSubScreen),
+ new Header(screenStack),
createButton = new HeaderButton
{
Anchor = Anchor.TopRight,
@@ -88,7 +115,7 @@ namespace osu.Game.Screens.Multi
Margin = new MarginPadding
{
Top = 10,
- Right = 10 + HORIZONTAL_OVERFLOW_PADDING,
+ Right = 10 + OsuScreen.HORIZONTAL_OVERFLOW_PADDING,
},
Text = "Create room",
Action = () => loungeSubScreen.Push(new Room
@@ -99,8 +126,8 @@ namespace osu.Game.Screens.Multi
roomManager = new RoomManager()
});
- screenAdded(loungeSubScreen);
- loungeSubScreen.Exited += _ => Exit();
+ screenStack.ScreenPushed += screenPushed;
+ screenStack.ScreenExited += screenExited;
}
private readonly IBindable isIdle = new BindableBool();
@@ -122,7 +149,7 @@ namespace osu.Game.Screens.Multi
private void updatePollingRate(bool idle)
{
- roomManager.TimeBetweenPolls = !IsCurrentScreen || !(currentSubScreen is LoungeSubScreen) ? 0 : (idle ? 120000 : 15000);
+ roomManager.TimeBetweenPolls = !this.IsCurrentScreen() || !(screenStack.CurrentScreen is LoungeSubScreen) ? 0 : (idle ? 120000 : 15000);
Logger.Log($"Polling adjusted to {roomManager.TimeBetweenPolls}");
}
@@ -135,114 +162,106 @@ namespace osu.Game.Screens.Multi
private void forcefullyExit()
{
// This is temporary since we don't currently have a way to force screens to be exited
- if (IsCurrentScreen)
- Exit();
+ if (this.IsCurrentScreen())
+ this.Exit();
else
{
- MakeCurrent();
+ this.MakeCurrent();
Schedule(forcefullyExit);
}
}
- protected override void OnEntering(Screen last)
+ public void OnEntering(IScreen last)
{
- Content.FadeIn();
+ this.FadeIn();
- base.OnEntering(last);
waves.Show();
}
- protected override bool OnExiting(Screen next)
+ public bool OnExiting(IScreen next)
{
waves.Hide();
- Content.Delay(WaveContainer.DISAPPEAR_DURATION).FadeOut();
+ this.Delay(WaveContainer.DISAPPEAR_DURATION).FadeOut();
cancelLooping();
- loungeSubScreen.MakeCurrent();
+
+ if (screenStack.CurrentScreen != null)
+ loungeSubScreen.MakeCurrent();
+
updatePollingRate(isIdle.Value);
- return base.OnExiting(next);
+ // the wave overlay transition takes longer than expected to run.
+ logo?.AppendAnimatingAction(() => logo.Delay(WaveContainer.DISAPPEAR_DURATION / 2).FadeOut(), false);
+
+ return false;
}
- protected override void OnResuming(Screen last)
+ public void OnResuming(IScreen last)
{
- base.OnResuming(last);
+ this.FadeIn(250);
+ this.ScaleTo(1, 250, Easing.OutSine);
- Content.FadeIn(250);
- Content.ScaleTo(1, 250, Easing.OutSine);
+ logo?.AppendAnimatingAction(() => OsuScreen.ApplyLogoArrivingDefaults(logo), true);
updatePollingRate(isIdle.Value);
}
- protected override void OnSuspending(Screen next)
+ public void OnSuspending(IScreen next)
{
- Content.ScaleTo(1.1f, 250, Easing.InSine);
- Content.FadeOut(250);
+ this.ScaleTo(1.1f, 250, Easing.InSine);
+ this.FadeOut(250);
cancelLooping();
roomManager.TimeBetweenPolls = 0;
-
- base.OnSuspending(next);
}
private void cancelLooping()
{
- var track = Beatmap.Value.Track;
+ var track = beatmap.Value.Track;
if (track != null)
track.Looping = false;
}
- protected override void LogoExiting(OsuLogo logo)
- {
- // the wave overlay transition takes longer than expected to run.
- logo.Delay(WaveContainer.DISAPPEAR_DURATION / 2).FadeOut();
- base.LogoExiting(logo);
- }
-
protected override void Update()
{
base.Update();
- if (!IsCurrentScreen) return;
+ if (!this.IsCurrentScreen()) return;
- if (currentSubScreen is MatchSubScreen)
+ if (screenStack.CurrentScreen is MatchSubScreen)
{
- var track = Beatmap.Value.Track;
+ var track = beatmap.Value.Track;
if (track != null)
{
track.Looping = true;
if (!track.IsRunning)
{
- Game.Audio.AddItemToList(track);
- track.Seek(Beatmap.Value.Metadata.PreviewTime);
+ game.Audio.AddItemToList(track);
+ track.Seek(beatmap.Value.Metadata.PreviewTime);
track.Start();
}
}
createButton.Hide();
}
- else if (currentSubScreen is LoungeSubScreen)
+ else if (screenStack.CurrentScreen is LoungeSubScreen)
createButton.Show();
}
- private void screenAdded(Screen newScreen)
- {
- currentSubScreen = (OsuScreen)newScreen;
- updatePollingRate(isIdle.Value);
+ private void screenPushed(IScreen lastScreen, IScreen newScreen)
+ => updatePollingRate(isIdle.Value);
- newScreen.ModePushed += screenAdded;
- newScreen.Exited += screenRemoved;
- }
-
- private void screenRemoved(Screen newScreen)
+ private void screenExited(IScreen lastScreen, IScreen newScreen)
{
- if (currentSubScreen is MatchSubScreen)
+ if (lastScreen is MatchSubScreen)
cancelLooping();
- currentSubScreen = (OsuScreen)newScreen;
updatePollingRate(isIdle.Value);
+
+ if (screenStack.CurrentScreen == null)
+ this.Exit();
}
protected override void Dispose(bool isDisposing)
diff --git a/osu.Game/Screens/Multi/MultiplayerSubScreen.cs b/osu.Game/Screens/Multi/MultiplayerSubScreen.cs
index 3e33de34fd..ddea4d5dad 100644
--- a/osu.Game/Screens/Multi/MultiplayerSubScreen.cs
+++ b/osu.Game/Screens/Multi/MultiplayerSubScreen.cs
@@ -1,49 +1,95 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using osu.Framework.Allocation;
using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Input.Bindings;
using osu.Framework.Screens;
+using osu.Game.Beatmaps;
using osu.Game.Graphics.Containers;
+using osu.Game.Input.Bindings;
+using osu.Game.Overlays;
namespace osu.Game.Screens.Multi
{
- public abstract class MultiplayerSubScreen : OsuScreen, IMultiplayerSubScreen
+ public abstract class MultiplayerSubScreen : CompositeDrawable, IMultiplayerSubScreen, IKeyBindingHandler
{
- protected virtual Drawable TransitionContent => Content;
+ public virtual bool AllowBeatmapRulesetChange => true;
+ public bool AllowExternalScreenChange => true;
+ public bool CursorVisible => true;
+ public bool HideOverlaysOnEnter => false;
+ public OverlayActivation InitialOverlayActivationMode => OverlayActivation.All;
+
+ public float BackgroundParallaxAmount => 1;
+
+ public bool ValidForResume { get; set; } = true;
+ public bool ValidForPush { get; set; } = true;
+
+ public override bool RemoveWhenNotAlive => false;
+
+ public abstract string Title { get; }
public virtual string ShortTitle => Title;
- protected override void OnEntering(Screen last)
- {
- base.OnEntering(last);
+ [Resolved]
+ protected IBindableBeatmap Beatmap { get; private set; }
- Content.FadeInFromZero(WaveContainer.APPEAR_DURATION, Easing.OutQuint);
- TransitionContent.FadeInFromZero(WaveContainer.APPEAR_DURATION, Easing.OutQuint);
- TransitionContent.MoveToX(200).MoveToX(0, WaveContainer.APPEAR_DURATION, Easing.OutQuint);
+ [Resolved(CanBeNull = true)]
+ protected OsuGame Game { get; private set; }
+
+ [Resolved(CanBeNull = true)]
+ protected IRoomManager Manager { get; private set; }
+
+ protected MultiplayerSubScreen()
+ {
+ Anchor = Anchor.Centre;
+ Origin = Anchor.Centre;
+ RelativeSizeAxes = Axes.Both;
}
- protected override bool OnExiting(Screen next)
+ public virtual void OnEntering(IScreen last)
{
- Content.FadeOut(WaveContainer.DISAPPEAR_DURATION, Easing.OutQuint);
- TransitionContent.MoveToX(200, WaveContainer.DISAPPEAR_DURATION, Easing.OutQuint);
-
- return base.OnExiting(next);
+ this.FadeInFromZero(WaveContainer.APPEAR_DURATION, Easing.OutQuint);
+ this.FadeInFromZero(WaveContainer.APPEAR_DURATION, Easing.OutQuint);
+ this.MoveToX(200).MoveToX(0, WaveContainer.APPEAR_DURATION, Easing.OutQuint);
}
- protected override void OnResuming(Screen last)
+ public virtual bool OnExiting(IScreen next)
{
- base.OnResuming(last);
+ this.FadeOut(WaveContainer.DISAPPEAR_DURATION, Easing.OutQuint);
+ this.MoveToX(200, WaveContainer.DISAPPEAR_DURATION, Easing.OutQuint);
- Content.FadeIn(WaveContainer.APPEAR_DURATION, Easing.OutQuint);
- TransitionContent.MoveToX(0, WaveContainer.APPEAR_DURATION, Easing.OutQuint);
+ return false;
}
- protected override void OnSuspending(Screen next)
+ public virtual void OnResuming(IScreen last)
{
- base.OnSuspending(next);
-
- Content.FadeOut(WaveContainer.DISAPPEAR_DURATION, Easing.OutQuint);
- TransitionContent.MoveToX(-200, WaveContainer.DISAPPEAR_DURATION, Easing.OutQuint);
+ this.FadeIn(WaveContainer.APPEAR_DURATION, Easing.OutQuint);
+ this.MoveToX(0, WaveContainer.APPEAR_DURATION, Easing.OutQuint);
}
+
+ public virtual void OnSuspending(IScreen next)
+ {
+ this.FadeOut(WaveContainer.DISAPPEAR_DURATION, Easing.OutQuint);
+ this.MoveToX(-200, WaveContainer.DISAPPEAR_DURATION, Easing.OutQuint);
+ }
+
+ public virtual bool OnPressed(GlobalAction action)
+ {
+ if (!this.IsCurrentScreen()) return false;
+
+ if (action == GlobalAction.Back)
+ {
+ this.Exit();
+ return true;
+ }
+
+ return false;
+ }
+
+ public bool OnReleased(GlobalAction action) => action == GlobalAction.Back;
+
+ public override string ToString() => Title;
}
}
diff --git a/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs b/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs
index 50a4dedf3c..36cf0f0282 100644
--- a/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs
+++ b/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs
@@ -6,6 +6,7 @@ using System.Diagnostics;
using System.Threading;
using osu.Framework.Allocation;
using osu.Framework.Logging;
+using osu.Framework.Screens;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Online.Multiplayer;
@@ -18,6 +19,8 @@ namespace osu.Game.Screens.Multi.Play
{
public class TimeshiftPlayer : Player
{
+ public Action Exited;
+
private readonly Room room;
private readonly int playlistItemId;
@@ -50,7 +53,7 @@ namespace osu.Game.Screens.Multi.Play
Schedule(() =>
{
ValidForResume = false;
- Exit();
+ this.Exit();
});
};
@@ -60,6 +63,16 @@ namespace osu.Game.Screens.Multi.Play
Thread.Sleep(1000);
}
+ public override bool OnExiting(IScreen next)
+ {
+ if (base.OnExiting(next))
+ return true;
+
+ Exited?.Invoke();
+
+ return false;
+ }
+
protected override ScoreInfo CreateScore()
{
submitScore();
@@ -79,6 +92,13 @@ namespace osu.Game.Screens.Multi.Play
api.Queue(request);
}
+ protected override void Dispose(bool isDisposing)
+ {
+ base.Dispose(isDisposing);
+
+ Exited = null;
+ }
+
protected override Results CreateResults(ScoreInfo score) => new MatchResults(score, room);
}
}
diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs
index 45789d7892..ba5c7b2f0a 100644
--- a/osu.Game/Screens/OsuScreen.cs
+++ b/osu.Game/Screens/OsuScreen.cs
@@ -1,7 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using System;
using Microsoft.EntityFrameworkCore.Internal;
using osu.Framework.Allocation;
using osu.Framework.Audio;
@@ -11,17 +10,14 @@ using osu.Framework.Graphics;
using osu.Framework.Input.Bindings;
using osu.Framework.Screens;
using osu.Game.Beatmaps;
-using osu.Game.Graphics.Containers;
using osu.Game.Input.Bindings;
using osu.Game.Rulesets;
using osu.Game.Screens.Menu;
-using osuTK;
using osu.Game.Overlays;
-using osu.Framework.Graphics.Containers;
namespace osu.Game.Screens
{
- public abstract class OsuScreen : Screen, IKeyBindingHandler, IHasDescription
+ public abstract class OsuScreen : Screen, IOsuScreen, IKeyBindingHandler, IHasDescription
{
///
/// The amount of negative padding that should be applied to game background content which touches both the left and right sides of the screen.
@@ -29,8 +25,6 @@ namespace osu.Game.Screens
///
public const float HORIZONTAL_OVERFLOW_PADDING = 50;
- public BackgroundScreen Background { get; private set; }
-
///
/// A user-facing title for this screen.
///
@@ -42,80 +36,62 @@ namespace osu.Game.Screens
public virtual bool AllowExternalScreenChange => false;
- ///
- /// Override to create a BackgroundMode for the current screen.
- /// Note that the instance created may not be the used instance if it matches the BackgroundMode equality clause.
- ///
- protected virtual BackgroundScreen CreateBackground() => null;
-
- private Action updateOverlayStates;
-
///
/// Whether all overlays should be hidden when this screen is entered or resumed.
///
- protected virtual bool HideOverlaysOnEnter => false;
-
- protected readonly Bindable OverlayActivationMode = new Bindable();
+ public virtual bool HideOverlaysOnEnter => false;
///
/// Whether overlays should be able to be opened once this screen is entered or resumed.
///
- protected virtual OverlayActivation InitialOverlayActivationMode => OverlayActivation.All;
+ public virtual OverlayActivation InitialOverlayActivationMode => OverlayActivation.All;
- ///
- /// Whether this allows the cursor to be displayed.
- ///
public virtual bool CursorVisible => true;
protected new OsuGameBase Game => base.Game as OsuGameBase;
- private OsuLogo logo;
-
- ///
- /// Whether the beatmap or ruleset should be allowed to be changed by the user or game.
- /// Used to mark exclusive areas where this is strongly prohibited, like gameplay.
- ///
public virtual bool AllowBeatmapRulesetChange => true;
protected readonly Bindable Beatmap = new Bindable();
- protected virtual float BackgroundParallaxAmount => 1;
-
- private ParallaxContainer backgroundParallaxContainer;
+ public virtual float BackgroundParallaxAmount => 1;
protected readonly Bindable Ruleset = new Bindable();
private SampleChannel sampleExit;
+ protected BackgroundScreen Background => backgroundStack?.CurrentScreen as BackgroundScreen;
+
+ private BackgroundScreen localBackground;
+
+ [Resolved(canBeNull: true)]
+ private BackgroundScreenStack backgroundStack { get; set; }
+
+ [Resolved(canBeNull: true)]
+ private OsuLogo logo { get; set; }
+
+ protected OsuScreen()
+ {
+ Anchor = Anchor.Centre;
+ Origin = Anchor.Centre;
+ }
+
[BackgroundDependencyLoader(true)]
private void load(BindableBeatmap beatmap, OsuGame osu, AudioManager audio, Bindable ruleset)
{
Beatmap.BindTo(beatmap);
Ruleset.BindTo(ruleset);
- if (osu != null)
- {
- OverlayActivationMode.BindTo(osu.OverlayActivationMode);
-
- updateOverlayStates = () =>
- {
- if (HideOverlaysOnEnter)
- osu.CloseAllOverlays();
- else
- osu.Toolbar.State = Visibility.Visible;
- };
- }
-
sampleExit = audio.Sample.Get(@"UI/screen-back");
}
public virtual bool OnPressed(GlobalAction action)
{
- if (!IsCurrentScreen) return false;
+ if (!this.IsCurrentScreen()) return false;
if (action == GlobalAction.Back && AllowBackButton)
{
- Exit();
+ this.Exit();
return true;
}
@@ -124,7 +100,7 @@ namespace osu.Game.Screens
public bool OnReleased(GlobalAction action) => action == GlobalAction.Back && AllowBackButton;
- protected override void OnResuming(Screen last)
+ public override void OnResuming(IScreen last)
{
sampleExit?.Play();
applyArrivingDefaults(true);
@@ -132,71 +108,32 @@ namespace osu.Game.Screens
base.OnResuming(last);
}
- protected override void OnSuspending(Screen next)
+ public override void OnSuspending(IScreen next)
{
base.OnSuspending(next);
onSuspendingLogo();
}
- protected override void OnEntering(Screen last)
+ public override void OnEntering(IScreen last)
{
- OsuScreen lastOsu = last as OsuScreen;
-
- BackgroundScreen bg = CreateBackground();
-
- if (lastOsu?.Background != null)
- {
- backgroundParallaxContainer = lastOsu.backgroundParallaxContainer;
-
- if (bg == null || lastOsu.Background.Equals(bg))
- //we can keep the previous mode's background.
- Background = lastOsu.Background;
- else
- {
- lastOsu.Background.Push(Background = bg);
- }
- }
- else if (bg != null)
- {
- // this makes up for the fact our padding changes when the global toolbar is visible.
- bg.Scale = new Vector2(1.06f);
-
- AddInternal(backgroundParallaxContainer = new ParallaxContainer
- {
- Depth = float.MaxValue,
- Children = new[]
- {
- Background = bg
- }
- });
- }
-
- if ((logo = lastOsu?.logo) == null)
- LoadComponentAsync(logo = new OsuLogo { Alpha = 0 }, AddInternal);
-
applyArrivingDefaults(false);
+ backgroundStack?.Push(localBackground = CreateBackground());
+
base.OnEntering(last);
}
- protected override bool OnExiting(Screen next)
+ public override bool OnExiting(IScreen next)
{
if (ValidForResume && logo != null)
onExitingLogo();
- OsuScreen nextOsu = next as OsuScreen;
-
- if (Background != null && !Background.Equals(nextOsu?.Background))
- {
- Background.Exit();
-
- //We need to use MakeCurrent in case we are jumping up multiple game screens.
- nextOsu?.Background?.MakeCurrent();
- }
-
if (base.OnExiting(next))
return true;
+ if (localBackground != null && backgroundStack?.CurrentScreen == localBackground)
+ backgroundStack?.Exit();
+
Beatmap.UnbindAll();
return false;
}
@@ -205,6 +142,24 @@ namespace osu.Game.Screens
/// Fired when this screen was entered or resumed and the logo state is required to be adjusted.
///
protected virtual void LogoArriving(OsuLogo logo, bool resuming)
+ {
+ ApplyLogoArrivingDefaults(logo);
+ }
+
+ private void applyArrivingDefaults(bool isResuming)
+ {
+ logo?.AppendAnimatingAction(() =>
+ {
+ if (this.IsCurrentScreen()) LogoArriving(logo, isResuming);
+ }, true);
+ }
+
+ ///
+ /// Applies default animations to an arriving logo.
+ /// Todo: This should not exist.
+ ///
+ /// The logo to apply animations to.
+ public static void ApplyLogoArrivingDefaults(OsuLogo logo)
{
logo.Action = null;
logo.FadeOut(300, Easing.OutQuint);
@@ -216,24 +171,9 @@ namespace osu.Game.Screens
logo.Ripple = true;
}
- private void applyArrivingDefaults(bool isResuming)
- {
- logo.AppendAnimatingAction(() =>
- {
- if (IsCurrentScreen) LogoArriving(logo, isResuming);
- }, true);
-
- if (backgroundParallaxContainer != null)
- backgroundParallaxContainer.ParallaxAmount = ParallaxContainer.DEFAULT_PARALLAX_AMOUNT * BackgroundParallaxAmount;
-
- OverlayActivationMode.Value = InitialOverlayActivationMode;
-
- updateOverlayStates?.Invoke();
- }
-
private void onExitingLogo()
{
- logo.AppendAnimatingAction(() => { LogoExiting(logo); }, false);
+ logo?.AppendAnimatingAction(() => LogoExiting(logo), false);
}
///
@@ -245,7 +185,7 @@ namespace osu.Game.Screens
private void onSuspendingLogo()
{
- logo.AppendAnimatingAction(() => { LogoSuspending(logo); }, false);
+ logo?.AppendAnimatingAction(() => LogoSuspending(logo), false);
}
///
@@ -254,5 +194,11 @@ namespace osu.Game.Screens
protected virtual void LogoSuspending(OsuLogo logo)
{
}
+
+ ///
+ /// Override to create a BackgroundMode for the current screen.
+ /// Note that the instance created may not be the used instance if it matches the BackgroundMode equality clause.
+ ///
+ protected virtual BackgroundScreen CreateBackground() => null;
}
}
diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs
index 54644b8d9c..71b7b77e5d 100644
--- a/osu.Game/Screens/Play/Player.cs
+++ b/osu.Game/Screens/Play/Player.cs
@@ -40,11 +40,11 @@ namespace osu.Game.Screens.Play
{
protected override bool AllowBackButton => false; // handled by HoldForMenuButton
- protected override float BackgroundParallaxAmount => 0.1f;
+ public override float BackgroundParallaxAmount => 0.1f;
- protected override bool HideOverlaysOnEnter => true;
+ public override bool HideOverlaysOnEnter => true;
- protected override OverlayActivation InitialOverlayActivationMode => OverlayActivation.UserTriggered;
+ public override OverlayActivation InitialOverlayActivationMode => OverlayActivation.UserTriggered;
public Action RestartRequested;
@@ -166,7 +166,7 @@ namespace osu.Game.Screens.Play
if (!ScoreProcessor.Mode.Disabled)
config.BindWith(OsuSetting.ScoreDisplayMode, ScoreProcessor.Mode);
- Children = new Drawable[]
+ InternalChildren = new Drawable[]
{
pauseContainer = new PauseContainer(offsetClock, adjustableClock)
{
@@ -225,7 +225,7 @@ namespace osu.Game.Screens.Play
{
Action = () =>
{
- if (!IsCurrentScreen) return;
+ if (!this.IsCurrentScreen()) return;
fadeOut(true);
Restart();
@@ -260,18 +260,18 @@ namespace osu.Game.Screens.Play
private void performUserRequestedExit()
{
- if (!IsCurrentScreen) return;
- Exit();
+ if (!this.IsCurrentScreen()) return;
+ this.Exit();
}
public void Restart()
{
- if (!IsCurrentScreen) return;
+ if (!this.IsCurrentScreen()) return;
sampleRestart?.Play();
ValidForResume = false;
RestartRequested?.Invoke();
- Exit();
+ this.Exit();
}
private ScheduledDelegate onCompletionEvent;
@@ -290,13 +290,13 @@ namespace osu.Game.Screens.Play
{
onCompletionEvent = Schedule(delegate
{
- if (!IsCurrentScreen) return;
+ if (!this.IsCurrentScreen()) return;
var score = CreateScore();
if (RulesetContainer.ReplayScore == null)
scoreManager.Import(score, true);
- Push(CreateResults(score));
+ this.Push(CreateResults(score));
onCompletionEvent = null;
});
@@ -331,15 +331,15 @@ namespace osu.Game.Screens.Play
return true;
}
- protected override void OnEntering(Screen last)
+ public override void OnEntering(IScreen last)
{
base.OnEntering(last);
if (!LoadedBeatmapSuccessfully)
return;
- Content.Alpha = 0;
- Content
+ Alpha = 0;
+ this
.ScaleTo(0.7f)
.ScaleTo(1, 750, Easing.OutQuint)
.Delay(250)
@@ -368,13 +368,13 @@ namespace osu.Game.Screens.Play
pauseContainer.FadeIn(750, Easing.OutQuint);
}
- protected override void OnSuspending(Screen next)
+ public override void OnSuspending(IScreen next)
{
fadeOut();
base.OnSuspending(next);
}
- protected override bool OnExiting(Screen next)
+ public override bool OnExiting(IScreen next)
{
if (onCompletionEvent != null)
{
@@ -401,7 +401,7 @@ namespace osu.Game.Screens.Play
private void fadeOut(bool instant = false)
{
float fadeOutDuration = instant ? 0 : 250;
- Content.FadeOut(fadeOutDuration);
+ this.FadeOut(fadeOutDuration);
Background?.FadeColour(Color4.White, fadeOutDuration, Easing.OutQuint);
}
@@ -425,7 +425,7 @@ namespace osu.Game.Screens.Play
protected override void UpdateBackgroundElements()
{
- if (!IsCurrentScreen) return;
+ if (!this.IsCurrentScreen()) return;
base.UpdateBackgroundElements();
diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs
index be3fdc8d14..58e59604dd 100644
--- a/osu.Game/Screens/Play/PlayerLoader.cs
+++ b/osu.Game/Screens/Play/PlayerLoader.cs
@@ -30,10 +30,12 @@ namespace osu.Game.Screens.Play
private Player player;
+ private Container content;
+
private BeatmapMetadataDisplay info;
private bool hideOverlays;
- protected override bool HideOverlaysOnEnter => hideOverlays;
+ public override bool HideOverlaysOnEnter => hideOverlays;
private Task loadTask;
@@ -51,34 +53,42 @@ namespace osu.Game.Screens.Play
[BackgroundDependencyLoader]
private void load()
{
- Add(info = new BeatmapMetadataDisplay(Beatmap.Value)
+ InternalChild = content = new Container
{
- Alpha = 0,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
- });
-
- Add(new FillFlowContainer
- {
- Anchor = Anchor.TopRight,
- Origin = Anchor.TopRight,
- AutoSizeAxes = Axes.Both,
- Direction = FillDirection.Vertical,
- Spacing = new Vector2(0, 20),
- Margin = new MarginPadding(25),
- Children = new PlayerSettingsGroup[]
+ RelativeSizeAxes = Axes.Both,
+ Children = new Drawable[]
{
- visualSettings = new VisualSettings(),
- new InputSettings()
+ info = new BeatmapMetadataDisplay(Beatmap.Value)
+ {
+ Alpha = 0,
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ },
+ new FillFlowContainer
+ {
+ Anchor = Anchor.TopRight,
+ Origin = Anchor.TopRight,
+ AutoSizeAxes = Axes.Both,
+ Direction = FillDirection.Vertical,
+ Spacing = new Vector2(0, 20),
+ Margin = new MarginPadding(25),
+ Children = new PlayerSettingsGroup[]
+ {
+ visualSettings = new VisualSettings(),
+ new InputSettings()
+ }
+ }
}
- });
+ };
loadNewPlayer();
}
private void playerLoaded(Player player) => info.Loading = false;
- protected override void OnResuming(Screen last)
+ public override void OnResuming(IScreen last)
{
base.OnResuming(last);
@@ -105,21 +115,21 @@ namespace osu.Game.Screens.Play
private void contentIn()
{
- Content.ScaleTo(1, 650, Easing.OutQuint);
- Content.FadeInFromZero(400);
+ content.ScaleTo(1, 650, Easing.OutQuint);
+ content.FadeInFromZero(400);
}
private void contentOut()
{
- Content.ScaleTo(0.7f, 300, Easing.InQuint);
- Content.FadeOut(250);
+ content.ScaleTo(0.7f, 300, Easing.InQuint);
+ content.FadeOut(250);
}
- protected override void OnEntering(Screen last)
+ public override void OnEntering(IScreen last)
{
base.OnEntering(last);
- Content.ScaleTo(0.7f);
+ content.ScaleTo(0.7f);
contentIn();
@@ -154,11 +164,12 @@ namespace osu.Game.Screens.Play
protected override void OnHoverLost(HoverLostEvent e)
{
- if (GetContainingInputManager().HoveredDrawables.Contains(visualSettings))
+ if (GetContainingInputManager()?.HoveredDrawables.Contains(visualSettings) == true)
{
// show user setting preview
UpdateBackgroundElements();
}
+
base.OnHoverLost(e);
}
@@ -170,7 +181,7 @@ namespace osu.Game.Screens.Play
private void pushWhenLoaded()
{
- if (!IsCurrentScreen) return;
+ if (!this.IsCurrentScreen()) return;
try
{
@@ -191,7 +202,7 @@ namespace osu.Game.Screens.Play
this.Delay(250).Schedule(() =>
{
- if (!IsCurrentScreen) return;
+ if (!this.IsCurrentScreen()) return;
loadTask = null;
@@ -200,9 +211,9 @@ namespace osu.Game.Screens.Play
ValidForResume = false;
if (player.LoadedBeatmapSuccessfully)
- Push(player);
+ this.Push(player);
else
- Exit();
+ this.Exit();
});
}, 500);
}
@@ -218,15 +229,15 @@ namespace osu.Game.Screens.Play
pushDebounce = null;
}
- protected override void OnSuspending(Screen next)
+ public override void OnSuspending(IScreen next)
{
base.OnSuspending(next);
cancelLoad();
}
- protected override bool OnExiting(Screen next)
+ public override bool OnExiting(IScreen next)
{
- Content.ScaleTo(0.7f, 150, Easing.InQuint);
+ content.ScaleTo(0.7f, 150, Easing.InQuint);
this.FadeOut(150);
cancelLoad();
diff --git a/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs b/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs
index 1c127dbdef..93ec7347c8 100644
--- a/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs
+++ b/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs
@@ -16,7 +16,7 @@ namespace osu.Game.Screens.Play
{
protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap.Value);
- protected new BackgroundScreenBeatmap Background => (BackgroundScreenBeatmap)base.Background;
+ protected new BackgroundScreenBeatmap Background => base.Background as BackgroundScreenBeatmap;
public override bool AllowBeatmapRulesetChange => false;
@@ -40,7 +40,7 @@ namespace osu.Game.Screens.Play
ShowStoryboard = config.GetBindable(OsuSetting.ShowStoryboard);
}
- protected override void OnEntering(Screen last)
+ public override void OnEntering(IScreen last)
{
base.OnEntering(last);
DimLevel.ValueChanged += _ => UpdateBackgroundElements();
@@ -49,7 +49,7 @@ namespace osu.Game.Screens.Play
InitializeBackgroundElements();
}
- protected override void OnResuming(Screen last)
+ public override void OnResuming(IScreen last)
{
base.OnResuming(last);
InitializeBackgroundElements();
@@ -66,7 +66,7 @@ namespace osu.Game.Screens.Play
///
protected virtual void UpdateBackgroundElements()
{
- if (!IsCurrentScreen) return;
+ if (!this.IsCurrentScreen()) return;
Background?.FadeColour(OsuColour.Gray(BackgroundOpacity), BACKGROUND_FADE_DURATION, Easing.OutQuint);
Background?.BlurTo(new Vector2((float)BlurLevel.Value * 25), BACKGROUND_FADE_DURATION, Easing.OutQuint);
diff --git a/osu.Game/Screens/Ranking/Results.cs b/osu.Game/Screens/Ranking/Results.cs
index d17a19a7ce..31863cea9b 100644
--- a/osu.Game/Screens/Ranking/Results.cs
+++ b/osu.Game/Screens/Ranking/Results.cs
@@ -55,7 +55,7 @@ namespace osu.Game.Screens.Ranking
private IEnumerable allCircles => new Drawable[] { circleOuterBackground, circleInner, circleOuter };
- protected override void OnEntering(Screen last)
+ public override void OnEntering(IScreen last)
{
base.OnEntering(last);
(Background as BackgroundScreenBeatmap)?.BlurTo(background_blur, 2500, Easing.OutQuint);
@@ -98,7 +98,7 @@ namespace osu.Game.Screens.Ranking
}
}
- protected override bool OnExiting(Screen next)
+ public override bool OnExiting(IScreen next)
{
allCircles.ForEach(c =>
{
@@ -107,7 +107,7 @@ namespace osu.Game.Screens.Ranking
Background.ScaleTo(1f, transition_time / 4, Easing.OutQuint);
- Content.FadeOut(transition_time / 4);
+ this.FadeOut(transition_time / 4);
return base.OnExiting(next);
}
@@ -115,7 +115,7 @@ namespace osu.Game.Screens.Ranking
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
- Children = new Drawable[]
+ InternalChildren = new Drawable[]
{
new AspectContainer
{
@@ -260,7 +260,7 @@ namespace osu.Game.Screens.Ranking
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
- Action = Exit
+ Action = this.Exit
},
};
diff --git a/osu.Game/Screens/ScreenWhiteBox.cs b/osu.Game/Screens/ScreenWhiteBox.cs
index a513015d93..d250416b29 100644
--- a/osu.Game/Screens/ScreenWhiteBox.cs
+++ b/osu.Game/Screens/ScreenWhiteBox.cs
@@ -30,7 +30,7 @@ namespace osu.Game.Screens
protected override BackgroundScreen CreateBackground() => new BackgroundScreenCustom(@"Backgrounds/bg2");
- protected override void OnEntering(Screen last)
+ public override void OnEntering(IScreen last)
{
base.OnEntering(last);
@@ -38,51 +38,51 @@ namespace osu.Game.Screens
if (last != null)
popButton.Alpha = 1;
- Content.Alpha = 0;
+ Alpha = 0;
textContainer.Position = new Vector2(DrawSize.X / 16, 0);
boxContainer.ScaleTo(0.2f);
boxContainer.RotateTo(-20);
- using (Content.BeginDelayedSequence(300, true))
+ using (BeginDelayedSequence(300, true))
{
boxContainer.ScaleTo(1, transition_time, Easing.OutElastic);
boxContainer.RotateTo(0, transition_time / 2, Easing.OutQuint);
textContainer.MoveTo(Vector2.Zero, transition_time, Easing.OutExpo);
- Content.FadeIn(transition_time, Easing.OutExpo);
+ this.FadeIn(transition_time, Easing.OutExpo);
}
}
- protected override bool OnExiting(Screen next)
+ public override bool OnExiting(IScreen next)
{
textContainer.MoveTo(new Vector2(DrawSize.X / 16, 0), transition_time, Easing.OutExpo);
- Content.FadeOut(transition_time, Easing.OutExpo);
+ this.FadeOut(transition_time, Easing.OutExpo);
return base.OnExiting(next);
}
- protected override void OnSuspending(Screen next)
+ public override void OnSuspending(IScreen next)
{
base.OnSuspending(next);
textContainer.MoveTo(new Vector2(-(DrawSize.X / 16), 0), transition_time, Easing.OutExpo);
- Content.FadeOut(transition_time, Easing.OutExpo);
+ this.FadeOut(transition_time, Easing.OutExpo);
}
- protected override void OnResuming(Screen last)
+ public override void OnResuming(IScreen last)
{
base.OnResuming(last);
textContainer.MoveTo(Vector2.Zero, transition_time, Easing.OutExpo);
- Content.FadeIn(transition_time, Easing.OutExpo);
+ this.FadeIn(transition_time, Easing.OutExpo);
}
public ScreenWhiteBox()
{
FillFlowContainer childModeButtons;
- Children = new Drawable[]
+ InternalChildren = new Drawable[]
{
boxContainer = new Container
{
@@ -148,7 +148,7 @@ namespace osu.Game.Screens
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Alpha = 0,
- Action = Exit
+ Action = this.Exit
},
childModeButtons = new FillFlowContainer
{
@@ -171,7 +171,7 @@ namespace osu.Game.Screens
HoverColour = getColourFor(t).Lighten(0.2f),
Action = delegate
{
- Push(Activator.CreateInstance(t) as Screen);
+ this.Push(Activator.CreateInstance(t) as Screen);
}
});
}
diff --git a/osu.Game/Screens/Select/EditSongSelect.cs b/osu.Game/Screens/Select/EditSongSelect.cs
index 30b5115770..bdf5f905fe 100644
--- a/osu.Game/Screens/Select/EditSongSelect.cs
+++ b/osu.Game/Screens/Select/EditSongSelect.cs
@@ -1,6 +1,8 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using osu.Framework.Screens;
+
namespace osu.Game.Screens.Select
{
public class EditSongSelect : SongSelect
@@ -9,7 +11,7 @@ namespace osu.Game.Screens.Select
protected override bool OnStart()
{
- Exit();
+ this.Exit();
return true;
}
}
diff --git a/osu.Game/Screens/Select/MatchSongSelect.cs b/osu.Game/Screens/Select/MatchSongSelect.cs
index 5435b2291e..298e936c1c 100644
--- a/osu.Game/Screens/Select/MatchSongSelect.cs
+++ b/osu.Game/Screens/Select/MatchSongSelect.cs
@@ -3,6 +3,8 @@
using System;
using Humanizer;
+using osu.Framework.Graphics;
+using osu.Framework.Screens;
using osu.Game.Online.Multiplayer;
using osu.Game.Screens.Multi;
@@ -15,6 +17,11 @@ namespace osu.Game.Screens.Select
public string ShortTitle => "song selection";
public override string Title => ShortTitle.Humanize();
+ public MatchSongSelect()
+ {
+ Padding = new MarginPadding { Horizontal = HORIZONTAL_OVERFLOW_PADDING };
+ }
+
protected override bool OnStart()
{
var item = new PlaylistItem
@@ -28,8 +35,8 @@ namespace osu.Game.Screens.Select
Selected?.Invoke(item);
- if (IsCurrentScreen)
- Exit();
+ if (this.IsCurrentScreen())
+ this.Exit();
return true;
}
diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs
index 14f3ce6633..982a44a8d3 100644
--- a/osu.Game/Screens/Select/PlaySongSelect.cs
+++ b/osu.Game/Screens/Select/PlaySongSelect.cs
@@ -25,7 +25,7 @@ namespace osu.Game.Screens.Select
}, Key.Number3);
}
- protected override void OnResuming(Screen last)
+ public override void OnResuming(IScreen last)
{
player = null;
@@ -64,7 +64,7 @@ namespace osu.Game.Screens.Select
LoadComponentAsync(player = new PlayerLoader(() => new Player()), l =>
{
- if (IsCurrentScreen) Push(player);
+ if (this.IsCurrentScreen())this.Push(player);
});
return true;
diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs
index e30b5914be..d800cea736 100644
--- a/osu.Game/Screens/Select/SongSelect.cs
+++ b/osu.Game/Screens/Select/SongSelect.cs
@@ -88,7 +88,7 @@ namespace osu.Game.Screens.Select
const float carousel_width = 640;
const float filter_height = 100;
- AddRange(new Drawable[]
+ AddRangeInternal(new Drawable[]
{
new ParallaxContainer
{
@@ -123,16 +123,6 @@ namespace osu.Game.Screens.Select
Padding = new MarginPadding { Top = 10, Right = 5 },
}
},
- beatmapInfoWedge = new BeatmapInfoWedge
- {
- Size = wedged_container_size,
- RelativeSizeAxes = Axes.X,
- Margin = new MarginPadding
- {
- Top = left_area_padding,
- Right = left_area_padding,
- },
- },
new Container
{
RelativeSizeAxes = Axes.Both,
@@ -166,13 +156,23 @@ namespace osu.Game.Screens.Select
Background = { Width = 2 },
Exit = () =>
{
- if (IsCurrentScreen)
- Exit();
+ if (this.IsCurrentScreen())
+ this.Exit();
},
},
}
},
},
+ beatmapInfoWedge = new BeatmapInfoWedge
+ {
+ Size = wedged_container_size,
+ RelativeSizeAxes = Axes.X,
+ Margin = new MarginPadding
+ {
+ Top = left_area_padding,
+ Right = left_area_padding,
+ },
+ },
new ResetScrollContainer(() => Carousel.ScrollToSelected())
{
RelativeSizeAxes = Axes.Y,
@@ -182,7 +182,7 @@ namespace osu.Game.Screens.Select
if (ShowFooter)
{
- Add(FooterPanels = new Container
+ AddInternal(FooterPanels = new Container
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
@@ -193,7 +193,7 @@ namespace osu.Game.Screens.Select
Bottom = Footer.HEIGHT,
},
});
- Add(Footer = new Footer
+ AddInternal(Footer = new Footer
{
OnBack = ExitFromBack,
});
@@ -210,7 +210,7 @@ namespace osu.Game.Screens.Select
});
}
- BeatmapDetails.Leaderboard.ScoreSelected += s => Push(new SoloResults(s));
+ BeatmapDetails.Leaderboard.ScoreSelected += s =>this.Push(new SoloResults(s));
}
[BackgroundDependencyLoader(true)]
@@ -281,13 +281,13 @@ namespace osu.Game.Screens.Select
return;
}
- Exit();
+ this.Exit();
}
public void Edit(BeatmapInfo beatmap = null)
{
Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap ?? beatmapNoDebounce);
- Push(new Editor());
+ this.Push(new Editor());
}
///
@@ -331,7 +331,7 @@ namespace osu.Game.Screens.Select
{
if (beatmap is DummyWorkingBeatmap) return;
- if (IsCurrentScreen && !Carousel.SelectBeatmap(beatmap?.BeatmapInfo, false))
+ if (this.IsCurrentScreen() && !Carousel.SelectBeatmap(beatmap?.BeatmapInfo, false))
// If selecting new beatmap without bypassing filters failed, there's possibly a ruleset mismatch
if (beatmap?.BeatmapInfo?.Ruleset != null && beatmap.BeatmapInfo.Ruleset != Ruleset.Value)
{
@@ -411,7 +411,7 @@ namespace osu.Game.Screens.Select
}
}
- if (IsCurrentScreen) ensurePlayingSelected(preview);
+ if (this.IsCurrentScreen()) ensurePlayingSelected(preview);
UpdateBeatmap(Beatmap.Value);
}
@@ -431,11 +431,11 @@ namespace osu.Game.Screens.Select
Carousel.SelectNextRandom();
}
- protected override void OnEntering(Screen last)
+ public override void OnEntering(IScreen last)
{
base.OnEntering(last);
- Content.FadeInFromZero(250);
+ this.FadeInFromZero(250);
FilterControl.Activate();
}
@@ -476,7 +476,7 @@ namespace osu.Game.Screens.Select
logo.FadeOut(logo_transition / 2, Easing.Out);
}
- protected override void OnResuming(Screen last)
+ public override void OnResuming(IScreen last)
{
BeatmapDetails.Leaderboard.RefreshScores();
@@ -490,26 +490,26 @@ namespace osu.Game.Screens.Select
base.OnResuming(last);
- Content.FadeIn(250);
+ this.FadeIn(250);
- Content.ScaleTo(1, 250, Easing.OutSine);
+ this.ScaleTo(1, 250, Easing.OutSine);
FilterControl.Activate();
}
- protected override void OnSuspending(Screen next)
+ public override void OnSuspending(IScreen next)
{
ModSelect.Hide();
- Content.ScaleTo(1.1f, 250, Easing.InSine);
+ this.ScaleTo(1.1f, 250, Easing.InSine);
- Content.FadeOut(250);
+ this.FadeOut(250);
FilterControl.Deactivate();
base.OnSuspending(next);
}
- protected override bool OnExiting(Screen next)
+ public override bool OnExiting(IScreen next)
{
if (ModSelect.State == Visibility.Visible)
{
@@ -521,7 +521,7 @@ namespace osu.Game.Screens.Select
beatmapInfoWedge.State = Visibility.Hidden;
- Content.FadeOut(100);
+ this.FadeOut(100);
FilterControl.Deactivate();
@@ -627,7 +627,7 @@ namespace osu.Game.Screens.Select
public override bool OnPressed(GlobalAction action)
{
- if (!IsCurrentScreen) return false;
+ if (!this.IsCurrentScreen()) return false;
switch (action)
{
diff --git a/osu.Game/Screens/Tournament/Drawings.cs b/osu.Game/Screens/Tournament/Drawings.cs
index dae53be8fe..43b194d8d0 100644
--- a/osu.Game/Screens/Tournament/Drawings.cs
+++ b/osu.Game/Screens/Tournament/Drawings.cs
@@ -22,6 +22,7 @@ using osuTK;
using osuTK.Graphics;
using osu.Framework.IO.Stores;
using osu.Framework.Graphics.Shapes;
+using osu.Framework.Screens;
namespace osu.Game.Screens.Tournament
{
@@ -29,7 +30,7 @@ namespace osu.Game.Screens.Tournament
{
private const string results_filename = "drawings_results.txt";
- protected override bool HideOverlaysOnEnter => true;
+ public override bool HideOverlaysOnEnter => true;
protected override BackgroundScreen CreateBackground() => new BackgroundScreenDefault();
@@ -70,13 +71,13 @@ namespace osu.Game.Screens.Tournament
if (!TeamList.Teams.Any())
{
- Exit();
+ this.Exit();
return;
}
drawingsConfig = new DrawingsConfigManager(storage);
- Children = new Drawable[]
+ InternalChildren = new Drawable[]
{
new Box
{
diff --git a/osu.Game/Tests/Visual/ScreenTestCase.cs b/osu.Game/Tests/Visual/ScreenTestCase.cs
index df4af0e470..79c57ad9f4 100644
--- a/osu.Game/Tests/Visual/ScreenTestCase.cs
+++ b/osu.Game/Tests/Visual/ScreenTestCase.cs
@@ -1,6 +1,8 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
using osu.Framework.Screens;
using osu.Game.Screens;
@@ -11,38 +13,25 @@ namespace osu.Game.Tests.Visual
///
public abstract class ScreenTestCase : OsuTestCase
{
- private readonly TestOsuScreen baseScreen;
+ private readonly ScreenStack stack;
+
+ [Cached]
+ private BackgroundScreenStack backgroundStack;
protected ScreenTestCase()
{
- Add(baseScreen = new TestOsuScreen());
+ Children = new Drawable[]
+ {
+ backgroundStack = new BackgroundScreenStack { RelativeSizeAxes = Axes.Both },
+ stack = new ScreenStack { RelativeSizeAxes = Axes.Both }
+ };
}
- protected void LoadScreen(OsuScreen screen) => baseScreen.LoadScreen(screen);
-
- public class TestOsuScreen : OsuScreen
+ protected void LoadScreen(OsuScreen screen)
{
- private OsuScreen nextScreen;
-
- public void LoadScreen(OsuScreen screen) => Schedule(() =>
- {
- nextScreen = screen;
-
- if (IsCurrentScreen)
- {
- Push(screen);
- nextScreen = null;
- }
- else
- MakeCurrent();
- });
-
- protected override void OnResuming(Screen last)
- {
- base.OnResuming(last);
- if (nextScreen != null)
- LoadScreen(nextScreen);
- }
+ if (stack.CurrentScreen != null)
+ stack.Exit();
+ stack.Push(screen);
}
}
}
diff --git a/osu.Game/Tests/Visual/TestCasePlayer.cs b/osu.Game/Tests/Visual/TestCasePlayer.cs
index 008573cb8a..a926a06295 100644
--- a/osu.Game/Tests/Visual/TestCasePlayer.cs
+++ b/osu.Game/Tests/Visual/TestCasePlayer.cs
@@ -6,6 +6,7 @@ using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Lists;
+using osu.Framework.Screens;
using osu.Game.Beatmaps;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index 669c7a6d8d..596190fcf7 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -10,15 +10,13 @@
-
-
-
-
+
+
diff --git a/osu.TestProject.props b/osu.TestProject.props
index 456ecfd468..a5c70f4edc 100644
--- a/osu.TestProject.props
+++ b/osu.TestProject.props
@@ -8,7 +8,6 @@
-
diff --git a/osu.iOS.props b/osu.iOS.props
index adc07d6bb8..e00c4fcf78 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -104,8 +104,9 @@
-
-
+
+
+
diff --git a/osu.iOS.sln b/osu.iOS.sln
index fe9741d767..21d02d33ab 100644
--- a/osu.iOS.sln
+++ b/osu.iOS.sln
@@ -5,8 +5,6 @@ VisualStudioVersion = 15.0.27004.2006
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game", "osu.Game\osu.Game.csproj", "{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Game.Resources", "osu-resources\osu.Game.Resources\osu.Game.Resources.csproj", "{D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}"
-EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Rulesets.Osu", "osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj", "{C92A607B-1FDD-4954-9F92-03FF547D9080}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Rulesets.Catch", "osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj", "{58F6C80C-1253-4A0E-A465-B8C85EBEADF3}"
diff --git a/osu.iOS/osu.iOS.csproj b/osu.iOS/osu.iOS.csproj
index fda26ddc94..9c69dd40ba 100644
--- a/osu.iOS/osu.iOS.csproj
+++ b/osu.iOS/osu.iOS.csproj
@@ -57,10 +57,6 @@
{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}
osu.Game
-
- {D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}
- osu.Game.Resources
-
{58F6C80C-1253-4A0E-A465-B8C85EBEADF3}
osu.Game.Rulesets.Catch
diff --git a/osu.sln b/osu.sln
index 0737a9fbd8..3c38309d86 100644
--- a/osu.sln
+++ b/osu.sln
@@ -5,8 +5,6 @@ VisualStudioVersion = 15.0.27004.2006
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game", "osu.Game\osu.Game.csproj", "{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Game.Resources", "osu-resources\osu.Game.Resources\osu.Game.Resources.csproj", "{D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}"
-EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Rulesets.Osu", "osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj", "{C92A607B-1FDD-4954-9F92-03FF547D9080}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Rulesets.Catch", "osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj", "{58F6C80C-1253-4A0E-A465-B8C85EBEADF3}"
@@ -31,10 +29,6 @@ Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
- Debug|iPhoneSimulator = Debug|iPhoneSimulator
- Release|iPhone = Release|iPhone
- Release|iPhoneSimulator = Release|iPhoneSimulator
- Debug|iPhone = Debug|iPhone
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU