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

Merge remote-tracking branch 'upstream/master' into android

This commit is contained in:
tangalbert919 2019-01-31 11:19:03 -06:00
commit 52110e5dc0
90 changed files with 1320 additions and 1118 deletions

3
.gitmodules vendored
View File

@ -1,3 +0,0 @@
[submodule "osu-resources"]
path = osu-resources
url = https://github.com/ppy/osu-resources

View File

@ -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**: Clone the repository **including submodules**:
```shell ```shell
git clone --recurse-submodules https://github.com/ppy/osu git clone https://github.com/ppy/osu
cd 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: To update the source code to the latest commit, run the following command inside the `osu` directory:
```shell ```shell
git pull --recurse-submodules git pull
``` ```
## Building ## 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 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
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. 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.

@ -1 +0,0 @@
Subproject commit 677897728f4332fa1200e0280ca02c4b987c6c47

View File

@ -16,7 +16,6 @@ using osu.Desktop.Updater;
using osu.Framework; using osu.Framework;
using osu.Framework.Platform.Windows; using osu.Framework.Platform.Windows;
using osu.Framework.Screens; using osu.Framework.Screens;
using osu.Game.Screens;
using osu.Game.Screens.Menu; using osu.Game.Screens.Menu;
namespace osu.Desktop 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) switch (newScreen)
{ {
case Intro _: case Intro _:

View File

@ -22,7 +22,6 @@
<ProjectReference Include="..\osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj" /> <ProjectReference Include="..\osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj" />
<ProjectReference Include="..\osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj" /> <ProjectReference Include="..\osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj" />
<ProjectReference Include="..\osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj" /> <ProjectReference Include="..\osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj" />
<ProjectReference Include="..\osu-resources\osu.Game.Resources\osu.Game.Resources.csproj" />
<PackageReference Include="Microsoft.Win32.Registry" Version="4.5.0" /> <PackageReference Include="Microsoft.Win32.Registry" Version="4.5.0" />
</ItemGroup> </ItemGroup>
<ItemGroup Label="Package References"> <ItemGroup Label="Package References">

View File

@ -39,10 +39,6 @@
<Project>{58F6C80C-1253-4A0E-A465-B8C85EBEADF3}</Project> <Project>{58F6C80C-1253-4A0E-A465-B8C85EBEADF3}</Project>
<Name>osu.Game.Rulesets.Catch</Name> <Name>osu.Game.Rulesets.Catch</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\osu-resources\osu.Game.Resources\osu.Game.Resources.csproj">
<Project>{D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}</Project>
<Name>osu.Game.Resources</Name>
</ProjectReference>
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" /> <Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
<Import Project="..\packages\NETStandard.Library.2.0.0\build\netstandard2.0\NETStandard.Library.targets" Condition="Exists('..\packages\NETStandard.Library.2.0.0\build\netstandard2.0\NETStandard.Library.targets')" /> <Import Project="..\packages\NETStandard.Library.2.0.0\build\netstandard2.0\NETStandard.Library.targets" Condition="Exists('..\packages\NETStandard.Library.2.0.0\build\netstandard2.0\NETStandard.Library.targets')" />

View File

@ -21,6 +21,7 @@ namespace osu.Game.Rulesets.Catch.Tests
[TestCase("basic")] [TestCase("basic")]
[TestCase("spinner")] [TestCase("spinner")]
[TestCase("spinner-and-circles")] [TestCase("spinner-and-circles")]
[TestCase("slider")]
public new void Test(string name) public new void Test(string name)
{ {
base.Test(name); base.Test(name);

View File

@ -55,6 +55,13 @@ namespace osu.Game.Rulesets.Catch.Objects
var minDistanceFromEnd = Velocity * 0.01; var minDistanceFromEnd = Velocity * 0.01;
var tickSamples = Samples.Select(s => new SampleInfo
{
Bank = s.Bank,
Name = @"slidertick",
Volume = s.Volume
}).ToList();
AddNested(new Fruit AddNested(new Fruit
{ {
Samples = Samples, Samples = Samples,
@ -62,15 +69,22 @@ namespace osu.Game.Rulesets.Catch.Objects
X = X X = X
}); });
double lastDropletTime = StartTime; double lastTickTime = StartTime;
for (int span = 0; span < this.SpanCount(); span++) for (int span = 0; span < this.SpanCount(); span++)
{ {
var spanStartTime = StartTime + span * spanDuration; var spanStartTime = StartTime + span * spanDuration;
var reversed = span % 2 == 1; 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 timeProgress = d / length;
var distanceProgress = reversed ? 1 - timeProgress : timeProgress; var distanceProgress = reversed ? 1 - timeProgress : timeProgress;
@ -79,47 +93,42 @@ namespace osu.Game.Rulesets.Catch.Objects
if (LegacyLastTickOffset != null) if (LegacyLastTickOffset != null)
{ {
// If we're the last tick, apply the legacy offset // 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); time = Math.Max(StartTime + Duration / 2, time - LegacyLastTickOffset.Value);
} }
double tinyTickInterval = time - lastDropletTime; int tinyTickCount = 1;
while (tinyTickInterval > 100) double tinyTickInterval = time - lastTickTime;
tinyTickInterval /= 2; while (tinyTickInterval > 100 && tinyTickCount < 10000)
for (double t = lastDropletTime + tinyTickInterval; t < time; t += tinyTickInterval)
{ {
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; double progress = reversed ? 1 - (t - spanStartTime) / spanDuration : (t - spanStartTime) / spanDuration;
AddNested(new TinyDroplet AddNested(new TinyDroplet
{ {
StartTime = t, StartTime = t,
X = X + Path.PositionAt(progress).X / CatchPlayfield.BASE_WIDTH, X = X + Path.PositionAt(progress).X / CatchPlayfield.BASE_WIDTH,
Samples = new List<SampleInfo>(Samples.Select(s => new SampleInfo Samples = tickSamples
{
Bank = s.Bank,
Name = @"slidertick",
Volume = s.Volume
}))
}); });
} }
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,
StartTime = time, Samples = tickSamples
X = X + Path.PositionAt(distanceProgress).X / CatchPlayfield.BASE_WIDTH, });
Samples = new List<SampleInfo>(Samples.Select(s => new SampleInfo
{
Bank = s.Bank,
Name = @"slidertick",
Volume = s.Volume
}))
});
}
lastDropletTime = time;
} }
AddNested(new Fruit AddNested(new Fruit

View File

@ -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}]}]}

View File

@ -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

View File

@ -39,10 +39,6 @@
<Project>{48F4582B-7687-4621-9CBE-5C24197CB536}</Project> <Project>{48F4582B-7687-4621-9CBE-5C24197CB536}</Project>
<Name>osu.Game.Rulesets.Mania</Name> <Name>osu.Game.Rulesets.Mania</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\osu-resources\osu.Game.Resources\osu.Game.Resources.csproj">
<Project>{D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}</Project>
<Name>osu.Game.Resources</Name>
</ProjectReference>
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" /> <Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
<Import Project="..\packages\NETStandard.Library.2.0.0\build\netstandard2.0\NETStandard.Library.targets" Condition="Exists('..\packages\NETStandard.Library.2.0.0\build\netstandard2.0\NETStandard.Library.targets')" /> <Import Project="..\packages\NETStandard.Library.2.0.0\build\netstandard2.0\NETStandard.Library.targets" Condition="Exists('..\packages\NETStandard.Library.2.0.0\build\netstandard2.0\NETStandard.Library.targets')" />

View File

@ -39,10 +39,6 @@
<Project>{C92A607B-1FDD-4954-9F92-03FF547D9080}</Project> <Project>{C92A607B-1FDD-4954-9F92-03FF547D9080}</Project>
<Name>osu.Game.Rulesets.Osu</Name> <Name>osu.Game.Rulesets.Osu</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\osu-resources\osu.Game.Resources\osu.Game.Resources.csproj">
<Project>{D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}</Project>
<Name>osu.Game.Resources</Name>
</ProjectReference>
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" /> <Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
<Import Project="..\packages\NETStandard.Library.2.0.0\build\netstandard2.0\NETStandard.Library.targets" Condition="Exists('..\packages\NETStandard.Library.2.0.0\build\netstandard2.0\NETStandard.Library.targets')" /> <Import Project="..\packages\NETStandard.Library.2.0.0\build\netstandard2.0\NETStandard.Library.targets" Condition="Exists('..\packages\NETStandard.Library.2.0.0\build\netstandard2.0\NETStandard.Library.targets')" />

View File

@ -88,7 +88,12 @@ namespace osu.Game.Rulesets.Osu.Difficulty
private double computeAimValue() 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 // Longer maps are worth more
double lengthBonus = 0.95f + 0.4f * Math.Min(1.0f, totalHits / 2000.0f) + double lengthBonus = 0.95f + 0.4f * Math.Min(1.0f, totalHits / 2000.0f) +

View File

@ -0,0 +1,16 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
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;
}
}

View File

@ -82,6 +82,9 @@ namespace osu.Game.Rulesets.Osu
if (mods.HasFlag(LegacyMods.Target)) if (mods.HasFlag(LegacyMods.Target))
yield return new OsuModTarget(); yield return new OsuModTarget();
if (mods.HasFlag(LegacyMods.TouchDevice))
yield return new OsuModTouchDevice();
} }
public override IEnumerable<Mod> GetModsFor(ModType type) public override IEnumerable<Mod> GetModsFor(ModType type)

View File

@ -39,10 +39,6 @@
<Project>{F167E17A-7DE6-4AF5-B920-A5112296C695}</Project> <Project>{F167E17A-7DE6-4AF5-B920-A5112296C695}</Project>
<Name>osu.Game.Rulesets.Taiko</Name> <Name>osu.Game.Rulesets.Taiko</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\osu-resources\osu.Game.Resources\osu.Game.Resources.csproj">
<Project>{D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}</Project>
<Name>osu.Game.Resources</Name>
</ProjectReference>
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" /> <Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
<Import Project="..\packages\NETStandard.Library.2.0.0\build\netstandard2.0\NETStandard.Library.targets" Condition="Exists('..\packages\NETStandard.Library.2.0.0\build\netstandard2.0\NETStandard.Library.targets')" /> <Import Project="..\packages\NETStandard.Library.2.0.0\build\netstandard2.0\NETStandard.Library.targets" Condition="Exists('..\packages\NETStandard.Library.2.0.0\build\netstandard2.0\NETStandard.Library.targets')" />

View File

@ -51,10 +51,6 @@
<Project>{F167E17A-7DE6-4AF5-B920-A5112296C695}</Project> <Project>{F167E17A-7DE6-4AF5-B920-A5112296C695}</Project>
<Name>osu.Game.Rulesets.Taiko</Name> <Name>osu.Game.Rulesets.Taiko</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\osu-resources\osu.Game.Resources\osu.Game.Resources.csproj">
<Project>{D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}</Project>
<Name>osu.Game.Resources</Name>
</ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup Label="Package References"> <ItemGroup Label="Package References">
<PackageReference Include="DeepEqual" Version="2.0.0" /> <PackageReference Include="DeepEqual" Version="2.0.0" />

View File

@ -27,7 +27,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
[Test] [Test]
public void TestDecodeBeatmapVersion() 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)) using (var stream = new StreamReader(resStream))
{ {
var decoder = Decoder.GetDecoder<Beatmap>(stream); var decoder = Decoder.GetDecoder<Beatmap>(stream);
@ -47,7 +47,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeBeatmapGeneral() public void TestDecodeBeatmapGeneral()
{ {
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false }; 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)) using (var stream = new StreamReader(resStream))
{ {
var beatmap = decoder.Decode(stream); var beatmap = decoder.Decode(stream);
@ -70,7 +70,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeBeatmapEditor() public void TestDecodeBeatmapEditor()
{ {
var decoder = new LegacyBeatmapDecoder(); 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)) using (var stream = new StreamReader(resStream))
{ {
var beatmapInfo = decoder.Decode(stream).BeatmapInfo; var beatmapInfo = decoder.Decode(stream).BeatmapInfo;
@ -95,7 +95,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeBeatmapMetadata() public void TestDecodeBeatmapMetadata()
{ {
var decoder = new LegacyBeatmapDecoder(); 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)) using (var stream = new StreamReader(resStream))
{ {
var beatmap = decoder.Decode(stream); var beatmap = decoder.Decode(stream);
@ -119,7 +119,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeBeatmapDifficulty() public void TestDecodeBeatmapDifficulty()
{ {
var decoder = new LegacyBeatmapDecoder(); 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)) using (var stream = new StreamReader(resStream))
{ {
var difficulty = decoder.Decode(stream).BeatmapInfo.BaseDifficulty; var difficulty = decoder.Decode(stream).BeatmapInfo.BaseDifficulty;
@ -137,7 +137,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeBeatmapEvents() public void TestDecodeBeatmapEvents()
{ {
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false }; 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)) using (var stream = new StreamReader(resStream))
{ {
var beatmap = decoder.Decode(stream); var beatmap = decoder.Decode(stream);
@ -155,7 +155,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeBeatmapTimingPoints() public void TestDecodeBeatmapTimingPoints()
{ {
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false }; 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)) using (var stream = new StreamReader(resStream))
{ {
var beatmap = decoder.Decode(stream); var beatmap = decoder.Decode(stream);
@ -190,7 +190,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeBeatmapColours() public void TestDecodeBeatmapColours()
{ {
var decoder = new LegacySkinDecoder(); 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)) using (var stream = new StreamReader(resStream))
{ {
var comboColors = decoder.Decode(stream).ComboColours; var comboColors = decoder.Decode(stream).ComboColours;
@ -215,7 +215,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeBeatmapComboOffsetsOsu() public void TestDecodeBeatmapComboOffsetsOsu()
{ {
var decoder = new LegacyBeatmapDecoder(); 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)) using (var stream = new StreamReader(resStream))
{ {
var beatmap = decoder.Decode(stream); var beatmap = decoder.Decode(stream);
@ -237,7 +237,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeBeatmapComboOffsetsCatch() public void TestDecodeBeatmapComboOffsetsCatch()
{ {
var decoder = new LegacyBeatmapDecoder(); 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)) using (var stream = new StreamReader(resStream))
{ {
var beatmap = decoder.Decode(stream); var beatmap = decoder.Decode(stream);
@ -259,7 +259,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeBeatmapHitObjects() public void TestDecodeBeatmapHitObjects()
{ {
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false }; 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)) using (var stream = new StreamReader(resStream))
{ {
var hitObjects = decoder.Decode(stream).HitObjects; var hitObjects = decoder.Decode(stream).HitObjects;
@ -286,7 +286,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeControlPointCustomSampleBank() public void TestDecodeControlPointCustomSampleBank()
{ {
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false }; 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)) using (var stream = new StreamReader(resStream))
{ {
var hitObjects = decoder.Decode(stream).HitObjects; var hitObjects = decoder.Decode(stream).HitObjects;
@ -307,7 +307,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeHitObjectCustomSampleBank() public void TestDecodeHitObjectCustomSampleBank()
{ {
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false }; 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)) using (var stream = new StreamReader(resStream))
{ {
var hitObjects = decoder.Decode(stream).HitObjects; var hitObjects = decoder.Decode(stream).HitObjects;
@ -324,7 +324,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeHitObjectFileSamples() public void TestDecodeHitObjectFileSamples()
{ {
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false }; 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)) using (var stream = new StreamReader(resStream))
{ {
var hitObjects = decoder.Decode(stream).HitObjects; var hitObjects = decoder.Decode(stream).HitObjects;
@ -342,7 +342,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeSliderSamples() public void TestDecodeSliderSamples()
{ {
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false }; 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)) using (var stream = new StreamReader(resStream))
{ {
var hitObjects = decoder.Decode(stream).HitObjects; var hitObjects = decoder.Decode(stream).HitObjects;
@ -385,7 +385,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeHitObjectNullAdditionBank() public void TestDecodeHitObjectNullAdditionBank()
{ {
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false }; 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)) using (var stream = new StreamReader(resStream))
{ {
var hitObjects = decoder.Decode(stream).HitObjects; var hitObjects = decoder.Decode(stream).HitObjects;

View File

@ -19,7 +19,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeStoryboardEvents() public void TestDecodeStoryboardEvents()
{ {
var decoder = new LegacyStoryboardDecoder(); 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)) using (var stream = new StreamReader(resStream))
{ {
var storyboard = decoder.Decode(stream); var storyboard = decoder.Decode(stream);
@ -91,7 +91,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeVariableWithSuffix() public void TestDecodeVariableWithSuffix()
{ {
var decoder = new LegacyStoryboardDecoder(); 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)) using (var stream = new StreamReader(resStream))
{ {
var storyboard = decoder.Decode(stream); var storyboard = decoder.Decode(stream);

View File

@ -146,7 +146,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
/// <returns>The <see cref="Beatmap"/> after being decoded by an <see cref="LegacyBeatmapDecoder"/>.</returns> /// <returns>The <see cref="Beatmap"/> after being decoded by an <see cref="LegacyBeatmapDecoder"/>.</returns>
private Beatmap decode(string filename, out Beatmap jsonDecoded) 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)) using (var sr = new StreamReader(stream))
{ {
var legacyDecoded = new LegacyBeatmapDecoder { ApplyOffsets = false }.Decode(sr); var legacyDecoded = new LegacyBeatmapDecoder { ApplyOffsets = false }.Decode(sr);

View File

@ -12,6 +12,7 @@ using osu.Framework.Platform;
using osu.Game.IPC; using osu.Game.IPC;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Tests.Resources;
using SharpCompress.Archives.Zip; using SharpCompress.Archives.Zip;
namespace osu.Game.Tests.Beatmaps.IO namespace osu.Game.Tests.Beatmaps.IO
@ -19,8 +20,6 @@ namespace osu.Game.Tests.Beatmaps.IO
[TestFixture] [TestFixture]
public class ImportBeatmapTest public class ImportBeatmapTest
{ {
public const string TEST_OSZ_PATH = @"../../../../osu-resources/osu.Game.Resources/Beatmaps/241526 Soleily - Renatus.osz";
[Test] [Test]
public void TestImportWhenClosed() public void TestImportWhenClosed()
{ {
@ -114,7 +113,7 @@ namespace osu.Game.Tests.Beatmaps.IO
Assert.AreEqual(0, fireCount -= 2); Assert.AreEqual(0, fireCount -= 2);
var breakTemp = createTemporaryBeatmap(); var breakTemp = TestResources.GetTestBeatmapForImport();
MemoryStream brokenOsu = new MemoryStream(new byte[] { 1, 3, 3, 7 }); MemoryStream brokenOsu = new MemoryStream(new byte[] { 1, 3, 3, 7 });
MemoryStream brokenOsz = new MemoryStream(File.ReadAllBytes(breakTemp)); MemoryStream brokenOsz = new MemoryStream(File.ReadAllBytes(breakTemp));
@ -223,7 +222,7 @@ namespace osu.Game.Tests.Beatmaps.IO
var osu = loadOsu(host); var osu = loadOsu(host);
var temp = createTemporaryBeatmap(); var temp = TestResources.GetTestBeatmapForImport();
var importer = new ArchiveImportIPCChannel(client); var importer = new ArchiveImportIPCChannel(client);
if (!importer.ImportAsync(temp).Wait(10000)) if (!importer.ImportAsync(temp).Wait(10000))
@ -248,7 +247,7 @@ namespace osu.Game.Tests.Beatmaps.IO
try try
{ {
var osu = loadOsu(host); var osu = loadOsu(host);
var temp = createTemporaryBeatmap(); var temp = TestResources.GetTestBeatmapForImport();
using (File.OpenRead(temp)) using (File.OpenRead(temp))
osu.Dependencies.Get<BeatmapManager>().Import(temp); osu.Dependencies.Get<BeatmapManager>().Import(temp);
ensureLoaded(osu); 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) public static BeatmapSetInfo LoadOszIntoOsu(OsuGameBase osu, string path = null)
{ {
var temp = path ?? createTemporaryBeatmap(); var temp = path ?? TestResources.GetTestBeatmapForImport();
var manager = osu.Dependencies.Get<BeatmapManager>(); var manager = osu.Dependencies.Get<BeatmapManager>();

View File

@ -17,7 +17,7 @@ namespace osu.Game.Tests.Beatmaps.IO
[Test] [Test]
public void TestReadBeatmaps() public void TestReadBeatmaps()
{ {
using (var osz = Resource.OpenResource("Beatmaps.241526 Soleily - Renatus.osz")) using (var osz = TestResources.GetTestBeatmapStream())
{ {
var reader = new ZipArchiveReader(osz); var reader = new ZipArchiveReader(osz);
string[] expected = string[] expected =
@ -44,7 +44,7 @@ namespace osu.Game.Tests.Beatmaps.IO
[Test] [Test]
public void TestReadMetadata() public void TestReadMetadata()
{ {
using (var osz = Resource.OpenResource("Beatmaps.241526 Soleily - Renatus.osz")) using (var osz = TestResources.GetTestBeatmapStream())
{ {
var reader = new ZipArchiveReader(osz); var reader = new ZipArchiveReader(osz);
@ -72,7 +72,7 @@ namespace osu.Game.Tests.Beatmaps.IO
[Test] [Test]
public void TestReadFile() public void TestReadFile()
{ {
using (var osz = Resource.OpenResource("Beatmaps.241526 Soleily - Renatus.osz")) using (var osz = TestResources.GetTestBeatmapStream())
{ {
var reader = new ZipArchiveReader(osz); var reader = new ZipArchiveReader(osz);
using (var stream = new StreamReader( using (var stream = new StreamReader(

View File

@ -1,20 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
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}");
}
}
}

View File

@ -0,0 +1,28 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
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;
}
}
}

View File

@ -3,7 +3,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -16,14 +15,13 @@ using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring; using osu.Game.Scoring;
using osu.Game.Tests.Resources;
using osu.Game.Users; using osu.Game.Users;
namespace osu.Game.Tests.Scores.IO namespace osu.Game.Tests.Scores.IO
{ {
public class ImportScoreTest public class ImportScoreTest
{ {
public const string TEST_OSZ_PATH = @"../../../../osu-resources/osu.Game.Resources/Beatmaps/241526 Soleily - Renatus.osz";
[Test] [Test]
public void TestBasicImport() public void TestBasicImport()
{ {
@ -132,21 +130,13 @@ namespace osu.Game.Tests.Scores.IO
return scoreManager.GetAllUsableScores().First(); 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) private OsuGameBase loadOsu(GameHost host)
{ {
var osu = new OsuGameBase(); var osu = new OsuGameBase();
Task.Run(() => host.Run(osu)); Task.Run(() => host.Run(osu));
waitForOrAssert(() => osu.IsLoaded, @"osu! failed to start in a reasonable amount of time"); 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>(); var beatmapManager = osu.Dependencies.Get<BeatmapManager>();
beatmapManager.Import(beatmapFile); beatmapManager.Import(beatmapFile);

View File

@ -4,6 +4,7 @@
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Screens;
using osu.Game.Screens; using osu.Game.Screens;
using osu.Game.Screens.Menu; using osu.Game.Screens.Menu;
using osuTK.Graphics; using osuTK.Graphics;
@ -57,7 +58,7 @@ namespace osu.Game.Tests.Visual
public OsuLogo Logo; public OsuLogo Logo;
private TestScreen screen; private TestScreen screen;
public bool ScreenLoaded => screen.IsCurrentScreen; public bool ScreenLoaded => screen.IsCurrentScreen();
public TestLoader(double delay) public TestLoader(double delay)
{ {
@ -96,7 +97,7 @@ namespace osu.Game.Tests.Visual
{ {
public TestScreen() public TestScreen()
{ {
Child = new Box InternalChild = new Box
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = Color4.DarkSlateGray, Colour = Color4.DarkSlateGray,
@ -107,7 +108,7 @@ namespace osu.Game.Tests.Visual
protected override void LogoArriving(OsuLogo logo, bool resuming) protected override void LogoArriving(OsuLogo logo, bool resuming)
{ {
base.LogoArriving(logo, resuming); base.LogoArriving(logo, resuming);
Child.FadeInFromZero(200); InternalChild.FadeInFromZero(200);
} }
} }
} }

View File

@ -3,6 +3,7 @@
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Screens;
using osu.Game.Screens; using osu.Game.Screens;
using osu.Game.Screens.Multi; using osu.Game.Screens.Multi;
@ -15,15 +16,15 @@ namespace osu.Game.Tests.Visual
{ {
int index = 0; int index = 0;
OsuScreen currentScreen = new TestMultiplayerSubScreen(index); ScreenStack screenStack = new ScreenStack(new TestMultiplayerSubScreen(index)) { RelativeSizeAxes = Axes.Both };
Children = new Drawable[] Children = new Drawable[]
{ {
currentScreen, screenStack,
new Header(currentScreen) 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 private class TestMultiplayerSubScreen : OsuScreen, IMultiplayerSubScreen

View File

@ -4,6 +4,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Screens;
using osu.Game.Screens.Multi; using osu.Game.Screens.Multi;
using osu.Game.Screens.Multi.Lounge; using osu.Game.Screens.Multi.Lounge;
using osu.Game.Screens.Multi.Lounge.Components; using osu.Game.Screens.Multi.Lounge.Components;

View File

@ -3,6 +3,7 @@
using System.Threading; using System.Threading;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Screens;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
@ -26,7 +27,7 @@ namespace osu.Game.Tests.Visual
AddStep("mouse in centre", () => InputManager.MoveMouseTo(loader.ScreenSpaceDrawQuad.Centre)); 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", () => AddStep("load slow dummy beatmap", () =>
{ {
@ -42,7 +43,7 @@ namespace osu.Game.Tests.Visual
Scheduler.AddDelayed(() => slow.Ready = true, 5000); 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 protected class SlowLoadPlayer : Player

View File

@ -19,16 +19,18 @@ namespace osu.Game.Tests.Visual
public class TestCaseScreenBreadcrumbControl : OsuTestCase public class TestCaseScreenBreadcrumbControl : OsuTestCase
{ {
private readonly ScreenBreadcrumbControl breadcrumbs; private readonly ScreenBreadcrumbControl breadcrumbs;
private Screen currentScreen, changedScreen; private readonly ScreenStack screenStack;
public TestCaseScreenBreadcrumbControl() public TestCaseScreenBreadcrumbControl()
{ {
TestScreen startScreen;
OsuSpriteText titleText; OsuSpriteText titleText;
IScreen startScreen = new TestScreenOne();
screenStack = new ScreenStack(startScreen) { RelativeSizeAxes = Axes.Both };
Children = new Drawable[] Children = new Drawable[]
{ {
currentScreen = startScreen = new TestScreenOne(), screenStack,
new FillFlowContainer new FillFlowContainer
{ {
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
@ -37,7 +39,7 @@ namespace osu.Game.Tests.Visual
Spacing = new Vector2(10), Spacing = new Vector2(10),
Children = new Drawable[] Children = new Drawable[]
{ {
breadcrumbs = new ScreenBreadcrumbControl(startScreen) breadcrumbs = new ScreenBreadcrumbControl(screenStack)
{ {
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
}, },
@ -46,12 +48,7 @@ namespace osu.Game.Tests.Visual
}, },
}; };
breadcrumbs.Current.ValueChanged += s => breadcrumbs.Current.ValueChanged += s => titleText.Text = $"Changed to {s.ToString()}";
{
titleText.Text = $"Changed to {s.ToString()}";
changedScreen = s;
};
breadcrumbs.Current.TriggerChange(); breadcrumbs.Current.TriggerChange();
waitForCurrent(); waitForCurrent();
@ -60,18 +57,14 @@ namespace osu.Game.Tests.Visual
pushNext(); pushNext();
waitForCurrent(); waitForCurrent();
AddStep(@"make start current", () => AddStep(@"make start current", () => startScreen.MakeCurrent());
{
startScreen.MakeCurrent();
currentScreen = startScreen;
});
waitForCurrent(); waitForCurrent();
pushNext(); pushNext();
waitForCurrent(); waitForCurrent();
AddAssert(@"only 2 items", () => breadcrumbs.Items.Count() == 2); AddAssert(@"only 2 items", () => breadcrumbs.Items.Count() == 2);
AddStep(@"exit current", () => changedScreen.Exit()); AddStep(@"exit current", () => screenStack.CurrentScreen.Exit());
AddAssert(@"current screen is first", () => startScreen == changedScreen); AddAssert(@"current screen is first", () => startScreen == screenStack.CurrentScreen);
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
@ -80,8 +73,8 @@ namespace osu.Game.Tests.Visual
breadcrumbs.StripColour = colours.Blue; breadcrumbs.StripColour = colours.Blue;
} }
private void pushNext() => AddStep(@"push next screen", () => currentScreen = ((TestScreen)currentScreen).PushNext()); private void pushNext() => AddStep(@"push next screen", () => ((TestScreen)screenStack.CurrentScreen).PushNext());
private void waitForCurrent() => AddUntilStep(() => currentScreen.IsCurrentScreen, "current screen"); private void waitForCurrent() => AddUntilStep(() => screenStack.CurrentScreen.IsCurrentScreen(), "current screen");
private abstract class TestScreen : OsuScreen private abstract class TestScreen : OsuScreen
{ {
@ -91,14 +84,14 @@ namespace osu.Game.Tests.Visual
public TestScreen PushNext() public TestScreen PushNext()
{ {
TestScreen screen = CreateNextScreen(); TestScreen screen = CreateNextScreen();
Push(screen); this.Push(screen);
return screen; return screen;
} }
protected TestScreen() protected TestScreen()
{ {
Child = new FillFlowContainer InternalChild = new FillFlowContainer
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,

View File

@ -8,7 +8,7 @@ using osu.Framework.Graphics.Textures;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Formats; using osu.Game.Beatmaps.Formats;
using osu.Game.IO.Archives; using osu.Game.IO.Archives;
using osu.Game.Tests.Beatmaps.IO; using osu.Game.Tests.Resources;
namespace osu.Game.Tests namespace osu.Game.Tests
{ {
@ -18,12 +18,12 @@ namespace osu.Game.Tests
public class WaveformTestBeatmap : WorkingBeatmap public class WaveformTestBeatmap : WorkingBeatmap
{ {
private readonly ZipArchiveReader reader; private readonly ZipArchiveReader reader;
private readonly FileStream stream; private readonly Stream stream;
public WaveformTestBeatmap() public WaveformTestBeatmap()
: base(new BeatmapInfo()) : base(new BeatmapInfo())
{ {
stream = File.OpenRead(ImportBeatmapTest.TEST_OSZ_PATH); stream = TestResources.GetTestBeatmapStream();
reader = new ZipArchiveReader(stream); reader = new ZipArchiveReader(stream);
} }

View File

@ -1,112 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Game.Online.API.Requests;
namespace osu.Game.Beatmaps.Drawables
{
/// <summary>
/// A component to allow downloading of a beatmap set. Automatically handles state syncing between other instances.
/// </summary>
public class BeatmapSetDownloader : Component
{
private readonly BeatmapSetInfo set;
private readonly bool noVideo;
private BeatmapManager beatmaps;
/// <summary>
/// Holds the current download state of the beatmap, whether is has already been downloaded, is in progress, or is not downloaded.
/// </summary>
public readonly Bindable<DownloadStatus> DownloadState = new Bindable<DownloadStatus>();
public BeatmapSetDownloader(BeatmapSetInfo set, bool noVideo = false)
{
this.set = set;
this.noVideo = noVideo;
}
[BackgroundDependencyLoader]
private void load(BeatmapManager beatmaps)
{
this.beatmaps = beatmaps;
beatmaps.ItemAdded += setAdded;
beatmaps.ItemRemoved += setRemoved;
beatmaps.BeatmapDownloadBegan += downloadBegan;
beatmaps.BeatmapDownloadFailed += downloadFailed;
// initial value
if (set.OnlineBeatmapSetID != null && beatmaps.QueryBeatmapSets(s => s.OnlineBeatmapSetID == set.OnlineBeatmapSetID && !s.DeletePending).Any())
DownloadState.Value = DownloadStatus.Downloaded;
else if (beatmaps.GetExistingDownload(set) != null)
DownloadState.Value = DownloadStatus.Downloading;
else
DownloadState.Value = DownloadStatus.NotDownloaded;
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
if (beatmaps != null)
{
beatmaps.ItemAdded -= setAdded;
beatmaps.ItemRemoved -= setRemoved;
beatmaps.BeatmapDownloadBegan -= downloadBegan;
beatmaps.BeatmapDownloadFailed -= downloadFailed;
}
}
/// <summary>
/// Begin downloading the associated beatmap set.
/// </summary>
/// <returns>True if downloading began. False if an existing download is active or completed.</returns>
public void Download()
{
if (DownloadState.Value > DownloadStatus.NotDownloaded)
return;
if (beatmaps.Download(set, noVideo))
{
// Only change state if download can happen
DownloadState.Value = DownloadStatus.Downloading;
}
}
private void setAdded(BeatmapSetInfo s, bool existing, bool silent) => Schedule(() =>
{
if (s.OnlineBeatmapSetID == set.OnlineBeatmapSetID)
DownloadState.Value = DownloadStatus.Downloaded;
});
private void setRemoved(BeatmapSetInfo s) => Schedule(() =>
{
if (s.OnlineBeatmapSetID == set.OnlineBeatmapSetID)
DownloadState.Value = DownloadStatus.NotDownloaded;
});
private void downloadBegan(DownloadBeatmapSetRequest d)
{
if (d.BeatmapSet.OnlineBeatmapSetID == set.OnlineBeatmapSetID)
DownloadState.Value = DownloadStatus.Downloading;
}
private void downloadFailed(DownloadBeatmapSetRequest d)
{
if (d.BeatmapSet.OnlineBeatmapSetID == set.OnlineBeatmapSetID)
DownloadState.Value = DownloadStatus.NotDownloaded;
}
public enum DownloadStatus
{
NotDownloaded,
Downloading,
Downloaded,
}
}
}

View File

@ -50,6 +50,7 @@ namespace osu.Game.Graphics.Cursor
if (!CanShowCursor) if (!CanShowCursor)
{ {
currentTarget?.Cursor?.Hide(); currentTarget?.Cursor?.Hide();
currentTarget = null;
return; return;
} }

View File

@ -10,45 +10,30 @@ namespace osu.Game.Graphics.UserInterface
/// <summary> /// <summary>
/// A <see cref="BreadcrumbControl"/> which follows the active screen (and allows navigation) in a <see cref="Screen"/> stack. /// A <see cref="BreadcrumbControl"/> which follows the active screen (and allows navigation) in a <see cref="Screen"/> stack.
/// </summary> /// </summary>
public class ScreenBreadcrumbControl : BreadcrumbControl<Screen> public class ScreenBreadcrumbControl : BreadcrumbControl<IScreen>
{ {
private Screen last; public ScreenBreadcrumbControl(ScreenStack stack)
public ScreenBreadcrumbControl(Screen initialScreen)
{ {
Current.ValueChanged += newScreen => stack.ScreenPushed += onPushed;
{ stack.ScreenExited += onExited;
if (last != newScreen && !newScreen.IsCurrentScreen)
newScreen.MakeCurrent();
};
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; AddItem(newScreen);
if (last != null)
{
last.Exited -= screenChanged;
last.ModePushed -= onPushed;
}
last = newScreen;
newScreen.Exited += screenChanged;
newScreen.ModePushed += onPushed;
Current.Value = 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); if (newScreen != null)
AddItem(screen); Current.Value = newScreen;
screenChanged(screen); Items.ToList().SkipWhile(s => s != Current.Value).Skip(1).ForEach(RemoveItem);
} }
} }
} }

View File

@ -355,11 +355,7 @@ namespace osu.Game.Online.API
State = APIState.Offline; State = APIState.Offline;
} }
private static User createGuestUser() => new User private static User createGuestUser() => new GuestUser();
{
Username = @"Guest",
Id = 1,
};
protected override void Dispose(bool isDisposing) protected override void Dispose(bool isDisposing)
{ {
@ -370,6 +366,15 @@ namespace osu.Game.Online.API
} }
} }
internal class GuestUser : User
{
public GuestUser()
{
Username = @"Guest";
Id = 1;
}
}
public enum APIState public enum APIState
{ {
/// <summary> /// <summary>

View File

@ -17,7 +17,7 @@ namespace osu.Game.Online.API
return request; return request;
} }
private void request_Progress(long current, long total) => API.Schedule(() => Progress?.Invoke(current, total)); private void request_Progress(long current, long total) => API.Schedule(() => Progressed?.Invoke(current, total));
protected APIDownloadRequest() protected APIDownloadRequest()
{ {
@ -29,7 +29,7 @@ namespace osu.Game.Online.API
Success?.Invoke(filename); Success?.Invoke(filename);
} }
public event APIProgressHandler Progress; public event APIProgressHandler Progressed;
public new event APISuccessHandler<string> Success; public new event APISuccessHandler<string> Success;
} }

View File

@ -10,7 +10,9 @@ namespace osu.Game.Online.API.Requests
{ {
public readonly BeatmapSetInfo BeatmapSet; public readonly BeatmapSetInfo BeatmapSet;
public Action<float> DownloadProgressed; public float Progress;
public event Action<float> DownloadProgressed;
private readonly bool noVideo; private readonly bool noVideo;
@ -19,7 +21,7 @@ namespace osu.Game.Online.API.Requests
this.noVideo = noVideo; this.noVideo = noVideo;
BeatmapSet = set; BeatmapSet = set;
Progress += (current, total) => DownloadProgressed?.Invoke((float) current / total); Progressed += (current, total) => DownloadProgressed?.Invoke(Progress = (float)current / total);
} }
protected override string Target => $@"beatmapsets/{BeatmapSet.OnlineBeatmapSetID}/download{(noVideo ? "?noVideo=1" : "")}"; protected override string Target => $@"beatmapsets/{BeatmapSet.OnlineBeatmapSetID}/download{(noVideo ? "?noVideo=1" : "")}";

View File

@ -79,27 +79,23 @@ namespace osu.Game
public virtual Storage GetStorageForStableInstall() => null; 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; public float ToolbarOffset => Toolbar.Position.Y + Toolbar.DrawHeight;
private IdleTracker idleTracker; private IdleTracker idleTracker;
public readonly Bindable<OverlayActivation> OverlayActivationMode = new Bindable<OverlayActivation>(); public readonly Bindable<OverlayActivation> OverlayActivationMode = new Bindable<OverlayActivation>();
private OsuScreen screenStack; private BackgroundScreenStack backgroundStack;
private ParallaxContainer backgroundParallax;
private ScreenStack screenStack;
private VolumeOverlay volume; private VolumeOverlay volume;
private OnScreenDisplay onscreenDisplay; private OnScreenDisplay onscreenDisplay;
private OsuLogo osuLogo;
private MainMenu menuScreen;
private Intro introScreen;
private Bindable<int> configRuleset; private Bindable<int> configRuleset;
private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>(); private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>();
@ -173,6 +169,8 @@ namespace osu.Game
dependencies.CacheAs(ruleset); dependencies.CacheAs(ruleset);
dependencies.CacheAs<IBindable<RulesetInfo>>(ruleset); dependencies.CacheAs<IBindable<RulesetInfo>>(ruleset);
dependencies.Cache(osuLogo = new OsuLogo { Alpha = 0 });
// bind config int to database RulesetInfo // bind config int to database RulesetInfo
configRuleset = LocalConfig.GetBindable<int>(OsuSetting.Ruleset); configRuleset = LocalConfig.GetBindable<int>(OsuSetting.Ruleset);
ruleset.Value = RulesetStore.GetRuleset(configRuleset.Value) ?? RulesetStore.AvailableRulesets.First(); ruleset.Value = RulesetStore.GetRuleset(configRuleset.Value) ?? RulesetStore.AvailableRulesets.First();
@ -211,6 +209,12 @@ namespace osu.Game
/// <param name="beatmap">The beatmap to select.</param> /// <param name="beatmap">The beatmap to select.</param>
public void PresentBeatmap(BeatmapSetInfo beatmap) public void PresentBeatmap(BeatmapSetInfo beatmap)
{ {
if (menuScreen == null)
{
Schedule(() => PresentBeatmap(beatmap));
return;
}
CloseAllOverlays(false); CloseAllOverlays(false);
void setBeatmap() void setBeatmap()
@ -233,16 +237,15 @@ namespace osu.Game
} }
} }
switch (currentScreen) switch (screenStack.CurrentScreen)
{ {
case SongSelect _: case SongSelect _:
break; break;
default: default:
// navigate to song select if we are not already there. // navigate to song select if we are not already there.
var menu = (MainMenu)intro.ChildScreen;
menu.MakeCurrent(); menuScreen.MakeCurrent();
menu.LoadToSolo(); menuScreen.LoadToSolo();
break; break;
} }
@ -268,9 +271,7 @@ namespace osu.Game
scoreLoad?.Cancel(); scoreLoad?.Cancel();
var menu = intro.ChildScreen; if (menuScreen == null)
if (menu == null)
{ {
scoreLoad = Schedule(() => LoadScore(score, false)); scoreLoad = Schedule(() => LoadScore(score, false));
return; return;
@ -291,7 +292,7 @@ namespace osu.Game
return; return;
} }
if (!currentScreen.AllowExternalScreenChange) if ((screenStack.CurrentScreen as IOsuScreen)?.AllowExternalScreenChange != true)
{ {
notifications.Post(new SimpleNotification notifications.Post(new SimpleNotification
{ {
@ -310,9 +311,9 @@ namespace osu.Game
void loadScore() void loadScore()
{ {
if (!menu.IsCurrentScreen) if (!menuScreen.IsCurrentScreen())
{ {
menu.MakeCurrent(); menuScreen.MakeCurrent();
this.Delay(500).Schedule(loadScore, out scoreLoad); this.Delay(500).Schedule(loadScore, out scoreLoad);
return; return;
} }
@ -322,7 +323,7 @@ namespace osu.Game
Beatmap.Value = BeatmapManager.GetWorkingBeatmap(databasedBeatmap); Beatmap.Value = BeatmapManager.GetWorkingBeatmap(databasedBeatmap);
Beatmap.Value.Mods.Value = databasedScoreInfo.Mods; 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(); 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. // todo: all archive managers should be able to be looped here.
SkinManager.PostNotification = n => notifications?.Post(n); SkinManager.PostNotification = n => notifications?.Post(n);
SkinManager.GetStableStorage = GetStorageForStableInstall; SkinManager.GetStableStorage = GetStorageForStableInstall;
@ -350,6 +346,8 @@ namespace osu.Game
BeatmapManager.PresentBeatmap = PresentBeatmap; BeatmapManager.PresentBeatmap = PresentBeatmap;
Container logoContainer;
AddRange(new Drawable[] AddRange(new Drawable[]
{ {
new VolumeControlReceptor new VolumeControlReceptor
@ -361,6 +359,16 @@ namespace osu.Game
screenContainer = new ScalingContainer(ScalingMode.ExcludeOverlays) screenContainer = new ScalingContainer(ScalingMode.ExcludeOverlays)
{ {
RelativeSizeAxes = Axes.Both, 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 overlayContent = new Container
{ {
@ -370,12 +378,17 @@ namespace osu.Game
idleTracker = new GameIdleTracker(6000) 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; RelativeSizeAxes = Axes.Both
screenStack.Exited += screenRemoved; }, screenStack.Push);
screenContainer.Add(screenStack);
});
loadComponentSingleFile(Toolbar = new Toolbar loadComponentSingleFile(Toolbar = new Toolbar
{ {
@ -383,7 +396,7 @@ namespace osu.Game
OnHome = delegate OnHome = delegate
{ {
CloseAllOverlays(false); CloseAllOverlays(false);
intro?.ChildScreen?.MakeCurrent(); menuScreen?.MakeCurrent();
}, },
}, floatingOverlayContent.Add); }, floatingOverlayContent.Add);
@ -617,7 +630,7 @@ namespace osu.Game
public bool OnPressed(GlobalAction action) public bool OnPressed(GlobalAction action)
{ {
if (intro == null) return false; if (introScreen == null) return false;
switch (action) switch (action)
{ {
@ -674,19 +687,20 @@ namespace osu.Game
private Container floatingOverlayContent; private Container floatingOverlayContent;
private OsuScreen currentScreen;
private FrameworkConfigManager frameworkConfig; private FrameworkConfigManager frameworkConfig;
private ScalingContainer screenContainer; private ScalingContainer screenContainer;
protected override bool OnExiting() 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; return true;
} }
@ -711,7 +725,7 @@ namespace osu.Game
// we only want to apply these restrictions when we are inside a screen stack. // 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. // 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; ruleset.Disabled = applyBeatmapRulesetRestrictions;
Beatmap.Disabled = applyBeatmapRulesetRestrictions; Beatmap.Disabled = applyBeatmapRulesetRestrictions;
@ -719,7 +733,7 @@ namespace osu.Game
screenContainer.Padding = new MarginPadding { Top = ToolbarOffset }; screenContainer.Padding = new MarginPadding { Top = ToolbarOffset };
overlayContent.Padding = new MarginPadding { Top = ToolbarOffset }; overlayContent.Padding = new MarginPadding { Top = ToolbarOffset };
MenuCursorContainer.CanShowCursor = currentScreen?.CursorVisible ?? false; MenuCursorContainer.CanShowCursor = (screenStack.CurrentScreen as IOsuScreen)?.CursorVisible ?? false;
} }
/// <summary> /// <summary>
@ -748,24 +762,41 @@ namespace osu.Game
this.ruleset.Disabled = rulesetDisabled; 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}"); 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); ScreenChanged(lastScreen, newScreen);
Logger.Log($"Screen changed ← {currentScreen}"); Logger.Log($"Screen changed ← {newScreen}");
if (newScreen == null) if (newScreen == null)
Exit(); Exit();

View File

@ -8,22 +8,22 @@ namespace osu.Game.Overlays.AccountCreation
{ {
public abstract class AccountCreationScreen : Screen public abstract class AccountCreationScreen : Screen
{ {
protected override void OnEntering(Screen last) public override void OnEntering(IScreen last)
{ {
base.OnEntering(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); base.OnResuming(last);
Content.FadeIn(200); this.FadeIn(200);
} }
protected override void OnSuspending(Screen next) public override void OnSuspending(IScreen next)
{ {
base.OnSuspending(next); base.OnSuspending(next);
Content.FadeOut(200); this.FadeOut(200);
} }
} }
} }

View File

@ -10,6 +10,7 @@ using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.MathUtils; using osu.Framework.MathUtils;
using osu.Framework.Platform;
using osu.Framework.Screens; using osu.Framework.Screens;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
@ -38,13 +39,15 @@ namespace osu.Game.Overlays.AccountCreation
private OsuTextBox[] textboxes; private OsuTextBox[] textboxes;
private ProcessingOverlay processingOverlay; private ProcessingOverlay processingOverlay;
private GameHost host;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuColour colours, APIAccess api) private void load(OsuColour colours, APIAccess api, GameHost host)
{ {
this.api = api; this.api = api;
this.host = host;
Children = new Drawable[] InternalChildren = new Drawable[]
{ {
new FillFlowContainer new FillFlowContainer
{ {
@ -139,11 +142,11 @@ namespace osu.Game.Overlays.AccountCreation
{ {
base.Update(); base.Update();
if (!textboxes.Any(t => t.HasFocus)) if (host?.OnScreenKeyboardOverlapsGameWindow != true && !textboxes.Any(t => t.HasFocus))
focusNextTextbox(); focusNextTextbox();
} }
protected override void OnEntering(Screen last) public override void OnEntering(IScreen last)
{ {
base.OnEntering(last); base.OnEntering(last);
processingOverlay.Hide(); processingOverlay.Hide();

View File

@ -26,12 +26,12 @@ namespace osu.Game.Overlays.AccountCreation
private const string help_centre_url = "/help/wiki/Help_Centre#login"; 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)) if (string.IsNullOrEmpty(api.ProvidedUsername))
{ {
Content.FadeOut(); this.FadeOut();
Push(new ScreenEntry()); this.Push(new ScreenEntry());
return; return;
} }
@ -46,7 +46,7 @@ namespace osu.Game.Overlays.AccountCreation
if (string.IsNullOrEmpty(api.ProvidedUsername)) if (string.IsNullOrEmpty(api.ProvidedUsername))
return; return;
Children = new Drawable[] InternalChildren = new Drawable[]
{ {
new Sprite new Sprite
{ {
@ -104,7 +104,7 @@ namespace osu.Game.Overlays.AccountCreation
new DangerousSettingsButton new DangerousSettingsButton
{ {
Text = "I understand. This account isn't for me.", 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; }) furtherAssistance = new LinkFlowContainer(cp => { cp.TextSize = 12; })
{ {

View File

@ -4,6 +4,7 @@
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Screens;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Overlays.Settings; using osu.Game.Overlays.Settings;
using osu.Game.Screens.Menu; using osu.Game.Screens.Menu;
@ -16,7 +17,7 @@ namespace osu.Game.Overlays.AccountCreation
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
Child = new FillFlowContainer InternalChild = new FillFlowContainer
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Direction = FillDirection.Vertical, Direction = FillDirection.Vertical,
@ -56,7 +57,7 @@ namespace osu.Game.Overlays.AccountCreation
{ {
Text = "Let's create an account!", Text = "Let's create an account!",
Margin = new MarginPadding { Vertical = 120 }, Margin = new MarginPadding { Vertical = 120 },
Action = () => Push(new ScreenWarning()) Action = () => this.Push(new ScreenWarning())
} }
} }
}; };

View File

@ -6,6 +6,7 @@ using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Screens;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Online.API; using osu.Game.Online.API;
@ -82,7 +83,7 @@ namespace osu.Game.Overlays
base.PopIn(); base.PopIn();
this.FadeIn(transition_time, Easing.OutQuint); this.FadeIn(transition_time, Easing.OutQuint);
if (welcomeScreen.ChildScreen != null) if (welcomeScreen.GetChildScreen() != null)
welcomeScreen.MakeCurrent(); welcomeScreen.MakeCurrent();
} }

View File

@ -7,42 +7,138 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Cursor;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Online.API; using osu.Game.Online.API;
using osu.Game.Overlays.Direct;
using osu.Game.Users; using osu.Game.Users;
using osuTK; using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
namespace osu.Game.Overlays.BeatmapSet.Buttons namespace osu.Game.Overlays.BeatmapSet.Buttons
{ {
public class DownloadButton : HeaderButton, IHasTooltip public class DownloadButton : DownloadTrackingComposite, IHasTooltip
{ {
public string TooltipText => "Download this beatmap"; private readonly bool noVideo;
public string TooltipText => button.Enabled ? "Download this beatmap" : "Login to download";
private readonly IBindable<User> localUser = new Bindable<User>(); private readonly IBindable<User> localUser = new Bindable<User>();
public DownloadButton(BeatmapSetInfo set, bool noVideo = false) private ShakeContainer shakeContainer;
{ private HeaderButton button;
Width = 120;
BeatmapSetDownloader downloader; public DownloadButton(BeatmapSetInfo beatmapSet, bool noVideo = false)
Add(new Container : base(beatmapSet)
{
this.noVideo = noVideo;
Width = 120;
RelativeSizeAxes = Axes.Y;
}
[BackgroundDependencyLoader]
private void load(APIAccess api, BeatmapManager beatmaps)
{
FillFlowContainer textSprites;
AddRangeInternal(new Drawable[]
{ {
Depth = -1, shakeContainer = new ShakeContainer
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Horizontal = 10 },
Children = new Drawable[]
{ {
downloader = new BeatmapSetDownloader(set, noVideo), Depth = -1,
new FillFlowContainer RelativeSizeAxes = Axes.Both,
Masking = true,
CornerRadius = 5,
Children = new Drawable[]
{ {
Anchor = Anchor.CentreLeft, button = new HeaderButton { RelativeSizeAxes = Axes.Both },
Origin = Anchor.CentreLeft, new Container
AutoSizeAxes = Axes.Both, {
Direction = FillDirection.Vertical, // cannot nest inside here due to the structure of button (putting things in its own content).
Children = new[] // requires framework fix.
Padding = new MarginPadding { Horizontal = 10 },
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
textSprites = new FillFlowContainer
{
Depth = -1,
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
AutoSizeAxes = Axes.Both,
AutoSizeDuration = 500,
AutoSizeEasing = Easing.OutQuint,
Direction = FillDirection.Vertical,
},
new SpriteIcon
{
Depth = -1,
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
Icon = FontAwesome.fa_download,
Size = new Vector2(16),
Margin = new MarginPadding { Right = 5 },
},
}
},
new DownloadProgressBar(BeatmapSet)
{
Depth = -2,
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
},
},
},
});
button.Action = () =>
{
if (State.Value != DownloadState.NotDownloaded)
{
shakeContainer.Shake();
return;
}
beatmaps.Download(BeatmapSet, noVideo);
};
localUser.BindTo(api.LocalUser);
localUser.BindValueChanged(userChanged, true);
button.Enabled.BindValueChanged(enabledChanged, true);
State.BindValueChanged(state =>
{
switch (state)
{
case DownloadState.Downloading:
textSprites.Children = new Drawable[]
{
new OsuSpriteText
{
Text = "Downloading...",
TextSize = 13,
Font = @"Exo2.0-Bold",
},
};
break;
case DownloadState.Downloaded:
textSprites.Children = new Drawable[]
{
new OsuSpriteText
{
Text = "Importing...",
TextSize = 13,
Font = @"Exo2.0-Bold",
},
};
break;
case DownloadState.LocallyAvailable:
this.FadeOut(200);
break;
case DownloadState.NotDownloaded:
textSprites.Children = new Drawable[]
{ {
new OsuSpriteText new OsuSpriteText
{ {
@ -52,57 +148,18 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
}, },
new OsuSpriteText new OsuSpriteText
{ {
Text = set.OnlineInfo.HasVideo && noVideo ? "without Video" : string.Empty, Text = BeatmapSet.Value.OnlineInfo.HasVideo && noVideo ? "without Video" : string.Empty,
TextSize = 11, TextSize = 11,
Font = @"Exo2.0-Bold", Font = @"Exo2.0-Bold",
}, },
}, };
},
new SpriteIcon
{
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
Icon = FontAwesome.fa_download,
Size = new Vector2(16),
Margin = new MarginPadding { Right = 5 },
},
},
});
Action = () =>
{
if (downloader.DownloadState.Value == BeatmapSetDownloader.DownloadStatus.Downloading)
{
Content.MoveToX(-5, 50, Easing.OutSine).Then()
.MoveToX(5, 100, Easing.InOutSine).Then()
.MoveToX(-5, 100, Easing.InOutSine).Then()
.MoveToX(0, 50, Easing.InSine);
return;
}
downloader.Download();
};
downloader.DownloadState.ValueChanged += state =>
{
switch (state)
{
case BeatmapSetDownloader.DownloadStatus.Downloaded:
this.FadeOut(200);
break;
case BeatmapSetDownloader.DownloadStatus.NotDownloaded:
this.FadeIn(200); this.FadeIn(200);
break; break;
} }
}; }, true);
} }
[BackgroundDependencyLoader] private void userChanged(User user) => button.Enabled.Value = !(user is GuestUser);
private void load(APIAccess api)
{
localUser.BindTo(api.LocalUser);
Enabled.BindValueChanged(enabledChanged, true);
}
private void enabledChanged(bool enabled) => this.FadeColour(enabled ? Color4.White : Color4.Gray, 200, Easing.OutQuint); private void enabledChanged(bool enabled) => this.FadeColour(enabled ? Color4.White : Color4.Gray, 200, Easing.OutQuint);
} }

View File

@ -13,12 +13,14 @@ using osu.Game.Graphics;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Overlays.BeatmapSet.Buttons; using osu.Game.Overlays.BeatmapSet.Buttons;
using osu.Game.Overlays.Direct;
using osuTK; using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
using DownloadButton = osu.Game.Overlays.BeatmapSet.Buttons.DownloadButton;
namespace osu.Game.Overlays.BeatmapSet namespace osu.Game.Overlays.BeatmapSet
{ {
public class Header : Container public class Header : DownloadTrackingComposite
{ {
private const float transition_duration = 200; private const float transition_duration = 200;
private const float tabs_height = 50; private const float tabs_height = 50;
@ -28,76 +30,23 @@ namespace osu.Game.Overlays.BeatmapSet
private readonly Box tabsBg; private readonly Box tabsBg;
private readonly UpdateableBeatmapSetCover cover; private readonly UpdateableBeatmapSetCover cover;
private readonly OsuSpriteText title, artist; private readonly OsuSpriteText title, artist;
private readonly Container noVideoButtons;
private readonly FillFlowContainer videoButtons;
private readonly AuthorInfo author; private readonly AuthorInfo author;
private readonly Container downloadButtonsContainer; private readonly FillFlowContainer downloadButtonsContainer;
private readonly BeatmapSetOnlineStatusPill onlineStatusPill; private readonly BeatmapSetOnlineStatusPill onlineStatusPill;
public Details Details; public Details Details;
public readonly BeatmapPicker Picker; public readonly BeatmapPicker Picker;
private BeatmapSetInfo beatmapSet;
private readonly FavouriteButton favouriteButton; private readonly FavouriteButton favouriteButton;
public BeatmapSetInfo BeatmapSet
{
get { return beatmapSet; }
set
{
if (value == beatmapSet) return;
beatmapSet = value;
Picker.BeatmapSet = author.BeatmapSet = Details.BeatmapSet = BeatmapSet;
updateDisplay();
}
}
private void updateDisplay()
{
title.Text = BeatmapSet?.Metadata.Title ?? string.Empty;
artist.Text = BeatmapSet?.Metadata.Artist ?? string.Empty;
onlineStatusPill.Status = BeatmapSet?.OnlineInfo.Status ?? BeatmapSetOnlineStatus.None;
cover.BeatmapSet = BeatmapSet;
if (BeatmapSet != null)
{
downloadButtonsContainer.FadeIn(transition_duration);
favouriteButton.FadeIn(transition_duration);
if (BeatmapSet.OnlineInfo.HasVideo)
{
videoButtons.Children = new[]
{
new DownloadButton(BeatmapSet),
new DownloadButton(BeatmapSet, true),
};
videoButtons.FadeIn(transition_duration);
noVideoButtons.FadeOut(transition_duration);
}
else
{
noVideoButtons.Child = new DownloadButton(BeatmapSet);
noVideoButtons.FadeIn(transition_duration);
videoButtons.FadeOut(transition_duration);
}
}
else
{
downloadButtonsContainer.FadeOut(transition_duration);
favouriteButton.FadeOut(transition_duration);
}
}
public Header() public Header()
{ {
ExternalLinkButton externalLink; ExternalLinkButton externalLink;
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
Height = 400; Height = 400;
Masking = true; Masking = true;
EdgeEffect = new EdgeEffectParameters EdgeEffect = new EdgeEffectParameters
{ {
Colour = Color4.Black.Opacity(0.25f), Colour = Color4.Black.Opacity(0.25f),
@ -105,7 +54,8 @@ namespace osu.Game.Overlays.BeatmapSet
Radius = 3, Radius = 3,
Offset = new Vector2(0f, 1f), Offset = new Vector2(0f, 1f),
}; };
Children = new Drawable[]
InternalChildren = new Drawable[]
{ {
new Container new Container
{ {
@ -196,24 +146,11 @@ namespace osu.Game.Overlays.BeatmapSet
Children = new Drawable[] Children = new Drawable[]
{ {
favouriteButton = new FavouriteButton(), favouriteButton = new FavouriteButton(),
downloadButtonsContainer = new Container downloadButtonsContainer = new FillFlowContainer
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Left = buttons_height + buttons_spacing }, Padding = new MarginPadding { Left = buttons_height + buttons_spacing },
Children = new Drawable[] Spacing = new Vector2(buttons_spacing),
{
noVideoButtons = new Container
{
RelativeSizeAxes = Axes.Both,
Alpha = 0f,
},
videoButtons = new FillFlowContainer
{
RelativeSizeAxes = Axes.Both,
Spacing = new Vector2(buttons_spacing),
Alpha = 0f,
},
},
}, },
}, },
}, },
@ -245,14 +182,64 @@ namespace osu.Game.Overlays.BeatmapSet
}; };
Picker.Beatmap.ValueChanged += b => Details.Beatmap = b; Picker.Beatmap.ValueChanged += b => Details.Beatmap = b;
Picker.Beatmap.ValueChanged += b => externalLink.Link = $@"https://osu.ppy.sh/beatmapsets/{BeatmapSet?.OnlineBeatmapSetID}#{b?.Ruleset.ShortName}/{b?.OnlineBeatmapID}"; Picker.Beatmap.ValueChanged += b => externalLink.Link = $@"https://osu.ppy.sh/beatmapsets/{BeatmapSet.Value?.OnlineBeatmapSetID}#{b?.Ruleset.ShortName}/{b?.OnlineBeatmapID}";
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuColour colours) private void load(OsuColour colours)
{ {
tabsBg.Colour = colours.Gray3; tabsBg.Colour = colours.Gray3;
updateDisplay();
State.BindValueChanged(_ => updateDownloadButtons());
BeatmapSet.BindValueChanged(beatmapSet =>
{
Picker.BeatmapSet = author.BeatmapSet = Details.BeatmapSet = beatmapSet;
title.Text = beatmapSet?.Metadata.Title ?? string.Empty;
artist.Text = beatmapSet?.Metadata.Artist ?? string.Empty;
onlineStatusPill.Status = beatmapSet?.OnlineInfo.Status ?? BeatmapSetOnlineStatus.None;
cover.BeatmapSet = beatmapSet;
if (beatmapSet != null)
{
downloadButtonsContainer.FadeIn(transition_duration);
favouriteButton.FadeIn(transition_duration);
}
else
{
downloadButtonsContainer.FadeOut(transition_duration);
favouriteButton.FadeOut(transition_duration);
}
updateDownloadButtons();
}, true);
}
private void updateDownloadButtons()
{
if (BeatmapSet.Value == null) return;
switch (State.Value)
{
case DownloadState.LocallyAvailable:
// temporary for UX until new design is implemented.
downloadButtonsContainer.Child = new osu.Game.Overlays.Direct.DownloadButton(BeatmapSet)
{
Width = 50,
RelativeSizeAxes = Axes.Y
};
break;
case DownloadState.Downloading:
case DownloadState.Downloaded:
// temporary to avoid showing two buttons for maps with novideo. will be fixed in new beatmap overlay design.
downloadButtonsContainer.Child = new DownloadButton(BeatmapSet);
break;
default:
downloadButtonsContainer.Child = new DownloadButton(BeatmapSet);
if (BeatmapSet.Value.OnlineInfo.HasVideo)
downloadButtonsContainer.Add(new DownloadButton(BeatmapSet, true));
break;
}
} }
} }
} }

View File

@ -46,7 +46,7 @@ namespace osu.Game.Overlays
if (value == beatmapSet) if (value == beatmapSet)
return; return;
header.BeatmapSet = info.BeatmapSet = beatmapSet = value; header.BeatmapSet.Value = info.BeatmapSet = beatmapSet = value;
} }
} }
@ -140,7 +140,7 @@ namespace osu.Game.Overlays
req.Success += res => req.Success += res =>
{ {
BeatmapSet = res.ToBeatmapSet(rulesets); BeatmapSet = res.ToBeatmapSet(rulesets);
header.Picker.Beatmap.Value = header.BeatmapSet.Beatmaps.First(b => b.OnlineBeatmapID == beatmapId); header.Picker.Beatmap.Value = header.BeatmapSet.Value.Beatmaps.First(b => b.OnlineBeatmapID == beatmapId);
}; };
api.Queue(req); api.Queue(req);
Show(); Show();

View File

@ -16,8 +16,6 @@ using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables; using osu.Game.Beatmaps.Drawables;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API.Requests;
using osuTK; using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
@ -31,8 +29,6 @@ namespace osu.Game.Overlays.Direct
private Container content; private Container content;
private ProgressBar progressBar;
private BeatmapManager beatmaps;
private BeatmapSetOverlay beatmapSetOverlay; private BeatmapSetOverlay beatmapSetOverlay;
public PreviewTrack Preview => PlayButton.Preview; public PreviewTrack Preview => PlayButton.Preview;
@ -65,14 +61,10 @@ namespace osu.Game.Overlays.Direct
Colour = Color4.Black.Opacity(0.3f), Colour = Color4.Black.Opacity(0.3f),
}; };
private OsuColour colours;
[BackgroundDependencyLoader(permitNulls: true)] [BackgroundDependencyLoader(permitNulls: true)]
private void load(BeatmapManager beatmaps, OsuColour colours, BeatmapSetOverlay beatmapSetOverlay) private void load(BeatmapManager beatmaps, OsuColour colours, BeatmapSetOverlay beatmapSetOverlay)
{ {
this.beatmaps = beatmaps;
this.beatmapSetOverlay = beatmapSetOverlay; this.beatmapSetOverlay = beatmapSetOverlay;
this.colours = colours;
AddInternal(content = new Container AddInternal(content = new Container
{ {
@ -82,33 +74,14 @@ namespace osu.Game.Overlays.Direct
Children = new[] Children = new[]
{ {
CreateBackground(), CreateBackground(),
progressBar = new ProgressBar new DownloadProgressBar(SetInfo)
{ {
Anchor = Anchor.BottomLeft, Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft, Origin = Anchor.BottomLeft,
Height = 0,
Alpha = 0,
BackgroundColour = Color4.Black.Opacity(0.7f),
FillColour = colours.Blue,
Depth = -1, Depth = -1,
}, },
} }
}); });
var downloadRequest = beatmaps.GetExistingDownload(SetInfo);
if (downloadRequest != null)
attachDownload(downloadRequest);
beatmaps.BeatmapDownloadBegan += attachDownload;
beatmaps.ItemAdded += setAdded;
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
beatmaps.BeatmapDownloadBegan -= attachDownload;
beatmaps.ItemAdded -= setAdded;
} }
protected override void Update() protected override void Update()
@ -149,37 +122,6 @@ namespace osu.Game.Overlays.Direct
protected void ShowInformation() => beatmapSetOverlay?.ShowBeatmapSet(SetInfo); protected void ShowInformation() => beatmapSetOverlay?.ShowBeatmapSet(SetInfo);
private void attachDownload(DownloadBeatmapSetRequest request)
{
if (request.BeatmapSet.OnlineBeatmapSetID != SetInfo.OnlineBeatmapSetID)
return;
progressBar.FadeIn(400, Easing.OutQuint);
progressBar.ResizeHeightTo(4, 400, Easing.OutQuint);
progressBar.Current.Value = 0;
request.Failure += e =>
{
progressBar.Current.Value = 0;
progressBar.FadeOut(500);
};
request.DownloadProgressed += progress => Schedule(() => progressBar.Current.Value = progress);
request.Success += data =>
{
progressBar.Current.Value = 1;
progressBar.FillColour = colours.Yellow;
};
}
private void setAdded(BeatmapSetInfo s, bool existing, bool silent) => Schedule(() =>
{
if (s.OnlineBeatmapSetID == SetInfo.OnlineBeatmapSetID)
progressBar.FadeOut(500);
});
protected override void LoadComplete() protected override void LoadComplete()
{ {
base.LoadComplete(); base.LoadComplete();

View File

@ -5,103 +5,114 @@ using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osuTK; using osuTK;
namespace osu.Game.Overlays.Direct namespace osu.Game.Overlays.Direct
{ {
public class DownloadButton : OsuAnimatedButton public class DownloadButton : DownloadTrackingComposite
{ {
private readonly BeatmapSetInfo beatmapSet; private readonly bool noVideo;
private readonly SpriteIcon icon; private readonly SpriteIcon icon;
private readonly SpriteIcon checkmark; private readonly SpriteIcon checkmark;
private readonly BeatmapSetDownloader downloader;
private readonly Box background; private readonly Box background;
private OsuColour colours; private OsuColour colours;
public DownloadButton(BeatmapSetInfo beatmapSet, bool noVideo = false) private readonly ShakeContainer shakeContainer;
{
this.beatmapSet = beatmapSet;
AddRange(new Drawable[] private readonly OsuAnimatedButton button;
public DownloadButton(BeatmapSetInfo beatmapSet, bool noVideo = false)
: base(beatmapSet)
{
this.noVideo = noVideo;
InternalChild = shakeContainer = new ShakeContainer
{ {
downloader = new BeatmapSetDownloader(beatmapSet, noVideo), RelativeSizeAxes = Axes.Both,
background = new Box Child = button = new OsuAnimatedButton
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Depth = float.MaxValue Children = new Drawable[]
}, {
icon = new SpriteIcon background = new Box
{ {
Anchor = Anchor.Centre, RelativeSizeAxes = Axes.Both,
Origin = Anchor.Centre, Depth = float.MaxValue
Size = new Vector2(13), },
Icon = FontAwesome.fa_download, icon = new SpriteIcon
}, {
checkmark = new SpriteIcon Anchor = Anchor.Centre,
{ Origin = Anchor.Centre,
Anchor = Anchor.Centre, Size = new Vector2(13),
Origin = Anchor.Centre, Icon = FontAwesome.fa_download,
X = 8, },
Size = Vector2.Zero, checkmark = new SpriteIcon
Icon = FontAwesome.fa_check, {
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
X = 8,
Size = Vector2.Zero,
Icon = FontAwesome.fa_check,
}
}
} }
}); };
} }
protected override void LoadComplete() protected override void LoadComplete()
{ {
base.LoadComplete(); base.LoadComplete();
downloader.DownloadState.BindValueChanged(updateState, true);
State.BindValueChanged(updateState, true);
FinishTransforms(true); FinishTransforms(true);
} }
[BackgroundDependencyLoader(permitNulls: true)] [BackgroundDependencyLoader(permitNulls: true)]
private void load(OsuColour colours, OsuGame game) private void load(OsuColour colours, OsuGame game, BeatmapManager beatmaps)
{ {
this.colours = colours; this.colours = colours;
Action = () => button.Action = () =>
{ {
switch (downloader.DownloadState.Value) switch (State.Value)
{ {
case BeatmapSetDownloader.DownloadStatus.Downloading: case DownloadState.Downloading:
// todo: replace with ShakeContainer after https://github.com/ppy/osu/pull/2909 is merged. case DownloadState.Downloaded:
Content.MoveToX(-5, 50, Easing.OutSine).Then() shakeContainer.Shake();
.MoveToX(5, 100, Easing.InOutSine).Then()
.MoveToX(-5, 100, Easing.InOutSine).Then()
.MoveToX(0, 50, Easing.InSine);
break; break;
case BeatmapSetDownloader.DownloadStatus.Downloaded: case DownloadState.LocallyAvailable:
game.PresentBeatmap(beatmapSet); game.PresentBeatmap(BeatmapSet);
break; break;
default: default:
downloader.Download(); beatmaps.Download(BeatmapSet, noVideo);
break; break;
} }
}; };
} }
private void updateState(BeatmapSetDownloader.DownloadStatus state) private void updateState(DownloadState state)
{ {
switch (state) switch (state)
{ {
case BeatmapSetDownloader.DownloadStatus.NotDownloaded: case DownloadState.NotDownloaded:
background.FadeColour(colours.Gray4, 500, Easing.InOutExpo); background.FadeColour(colours.Gray4, 500, Easing.InOutExpo);
icon.MoveToX(0, 500, Easing.InOutExpo); icon.MoveToX(0, 500, Easing.InOutExpo);
checkmark.ScaleTo(Vector2.Zero, 500, Easing.InOutExpo); checkmark.ScaleTo(Vector2.Zero, 500, Easing.InOutExpo);
break; break;
case BeatmapSetDownloader.DownloadStatus.Downloading: case DownloadState.Downloading:
background.FadeColour(colours.Blue, 500, Easing.InOutExpo); background.FadeColour(colours.Blue, 500, Easing.InOutExpo);
icon.MoveToX(0, 500, Easing.InOutExpo); icon.MoveToX(0, 500, Easing.InOutExpo);
checkmark.ScaleTo(Vector2.Zero, 500, Easing.InOutExpo); checkmark.ScaleTo(Vector2.Zero, 500, Easing.InOutExpo);
break; break;
case DownloadState.Downloaded:
case BeatmapSetDownloader.DownloadStatus.Downloaded: background.FadeColour(colours.Yellow, 500, Easing.InOutExpo);
break;
case DownloadState.LocallyAvailable:
background.FadeColour(colours.Green, 500, Easing.InOutExpo); background.FadeColour(colours.Green, 500, Easing.InOutExpo);
icon.MoveToX(-8, 500, Easing.InOutExpo); icon.MoveToX(-8, 500, Easing.InOutExpo);
checkmark.ScaleTo(new Vector2(13), 500, Easing.InOutExpo); checkmark.ScaleTo(new Vector2(13), 500, Easing.InOutExpo);

View File

@ -0,0 +1,64 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
using osuTK.Graphics;
namespace osu.Game.Overlays.Direct
{
public class DownloadProgressBar : DownloadTrackingComposite
{
private readonly ProgressBar progressBar;
public DownloadProgressBar(BeatmapSetInfo beatmapSet)
: base(beatmapSet)
{
AddInternal(progressBar = new ProgressBar
{
Height = 0,
Alpha = 0,
});
AutoSizeAxes = Axes.Y;
RelativeSizeAxes = Axes.X;
}
[BackgroundDependencyLoader(true)]
private void load(OsuColour colours)
{
progressBar.FillColour = colours.Blue;
progressBar.BackgroundColour = Color4.Black.Opacity(0.7f);
progressBar.Current = Progress;
State.BindValueChanged(state =>
{
switch (state)
{
case DownloadState.NotDownloaded:
progressBar.Current.Value = 0;
progressBar.FadeOut(500);
break;
case DownloadState.Downloading:
progressBar.FadeIn(400, Easing.OutQuint);
progressBar.ResizeHeightTo(4, 400, Easing.OutQuint);
break;
case DownloadState.Downloaded:
progressBar.FadeIn(400, Easing.OutQuint);
progressBar.ResizeHeightTo(4, 400, Easing.OutQuint);
progressBar.Current.Value = 1;
progressBar.FillColour = colours.Yellow;
break;
case DownloadState.LocallyAvailable:
progressBar.FadeOut(500);
break;
}
}, true);
}
}
}

View File

@ -0,0 +1,13 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
namespace osu.Game.Overlays.Direct
{
public enum DownloadState
{
NotDownloaded,
Downloading,
Downloaded,
LocallyAvailable
}
}

View File

@ -0,0 +1,131 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using Microsoft.EntityFrameworkCore.Internal;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps;
using osu.Game.Online.API.Requests;
namespace osu.Game.Overlays.Direct
{
public abstract class DownloadTrackingComposite : CompositeDrawable
{
public readonly Bindable<BeatmapSetInfo> BeatmapSet = new Bindable<BeatmapSetInfo>();
private BeatmapManager beatmaps;
/// <summary>
/// Holds the current download state of the beatmap, whether is has already been downloaded, is in progress, or is not downloaded.
/// </summary>
protected readonly Bindable<DownloadState> State = new Bindable<DownloadState>();
protected readonly Bindable<double> Progress = new Bindable<double>();
protected DownloadTrackingComposite(BeatmapSetInfo beatmapSet = null)
{
BeatmapSet.Value = beatmapSet;
}
[BackgroundDependencyLoader(true)]
private void load(BeatmapManager beatmaps)
{
this.beatmaps = beatmaps;
BeatmapSet.BindValueChanged(set =>
{
if (set == null)
attachDownload(null);
else if (beatmaps.QueryBeatmapSets(s => s.OnlineBeatmapSetID == set.OnlineBeatmapSetID).Any())
State.Value = DownloadState.LocallyAvailable;
else
attachDownload(beatmaps.GetExistingDownload(set));
}, true);
beatmaps.BeatmapDownloadBegan += download =>
{
if (download.BeatmapSet.OnlineBeatmapSetID == BeatmapSet.Value?.OnlineBeatmapSetID)
attachDownload(download);
};
beatmaps.ItemAdded += setAdded;
}
#region Disposal
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
beatmaps.BeatmapDownloadBegan -= attachDownload;
beatmaps.ItemAdded -= setAdded;
State.UnbindAll();
attachDownload(null);
}
#endregion
private DownloadBeatmapSetRequest attachedRequest;
private void attachDownload(DownloadBeatmapSetRequest request)
{
if (attachedRequest != null)
{
attachedRequest.Failure -= onRequestFailure;
attachedRequest.DownloadProgressed -= onRequestProgress;
attachedRequest.Success -= onRequestSuccess;
}
attachedRequest = request;
if (attachedRequest != null)
{
if (attachedRequest.Progress == 1)
{
State.Value = DownloadState.Downloaded;
Progress.Value = 1;
}
else
{
State.Value = DownloadState.Downloading;
Progress.Value = attachedRequest.Progress;
attachedRequest.Failure += onRequestFailure;
attachedRequest.DownloadProgressed += onRequestProgress;
attachedRequest.Success += onRequestSuccess;
}
}
else
{
State.Value = DownloadState.NotDownloaded;
}
}
private void onRequestSuccess(string data)
{
Schedule(() => State.Value = DownloadState.Downloaded);
}
private void onRequestProgress(float progress)
{
Schedule(() => Progress.Value = progress);
}
private void onRequestFailure(Exception e)
{
Schedule(() => attachDownload(null));
}
private void setAdded(BeatmapSetInfo s, bool existing, bool silent)
{
if (s.OnlineBeatmapSetID != BeatmapSet.Value?.OnlineBeatmapSetID)
return;
Schedule(() => State.Value = DownloadState.LocallyAvailable);
}
}
}

View File

@ -2,7 +2,6 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System; using System;
using System.Threading;
using osu.Framework.Screens; using osu.Framework.Screens;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
@ -12,6 +11,12 @@ namespace osu.Game.Screens
{ {
public abstract class BackgroundScreen : Screen, IEquatable<BackgroundScreen> public abstract class BackgroundScreen : Screen, IEquatable<BackgroundScreen>
{ {
protected BackgroundScreen()
{
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
}
public virtual bool Equals(BackgroundScreen other) public virtual bool Equals(BackgroundScreen other)
{ {
return other?.GetType() == GetType(); return other?.GetType() == GetType();
@ -26,64 +31,40 @@ namespace osu.Game.Screens
return false; 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() protected override void Update()
{ {
base.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(); this.FadeOut();
Content.MoveToX(x_movement_amount); this.MoveToX(x_movement_amount);
Content.FadeIn(transition_length, Easing.InOutQuart); this.FadeIn(transition_length, Easing.InOutQuart);
Content.MoveToX(0, transition_length, Easing.InOutQuart); this.MoveToX(0, transition_length, Easing.InOutQuart);
base.OnEntering(last); 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); base.OnSuspending(next);
} }
protected override bool OnExiting(Screen next) public override bool OnExiting(IScreen next)
{ {
Content.FadeOut(transition_length, Easing.OutExpo); this.FadeOut(transition_length, Easing.OutExpo);
Content.MoveToX(x_movement_amount, transition_length, Easing.OutExpo); this.MoveToX(x_movement_amount, transition_length, Easing.OutExpo);
return base.OnExiting(next); 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); base.OnResuming(last);
} }
} }

View File

@ -0,0 +1,32 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
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<BackgroundScreen>.Default.Equals((BackgroundScreen)CurrentScreen, screen))
return;
base.Push(screen);
}
}
}

View File

@ -37,7 +37,7 @@ namespace osu.Game.Screens.Backgrounds
} }
b.Depth = newDepth; b.Depth = newDepth;
Add(Background = b); AddInternal(Background = b);
Background.BlurSigma = BlurTarget; Background.BlurSigma = BlurTarget;
})); }));
}); });

View File

@ -12,14 +12,14 @@ namespace osu.Game.Screens.Backgrounds
{ {
public BackgroundScreenBlack() public BackgroundScreenBlack()
{ {
Child = new Box InternalChild = new Box
{ {
Colour = Color4.Black, Colour = Color4.Black,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
}; };
} }
protected override void OnEntering(Screen last) public override void OnEntering(IScreen last)
{ {
Show(); Show();
} }

View File

@ -12,7 +12,7 @@ namespace osu.Game.Screens.Backgrounds
public BackgroundScreenCustom(string textureName) public BackgroundScreenCustom(string textureName)
{ {
this.textureName = textureName; this.textureName = textureName;
Add(new Background(textureName)); AddInternal(new Background(textureName));
} }
public override bool Equals(BackgroundScreen other) public override bool Equals(BackgroundScreen other)

View File

@ -42,7 +42,7 @@ namespace osu.Game.Screens.Backgrounds
Background?.FadeOut(800, Easing.InOutSine); Background?.FadeOut(800, Easing.InOutSine);
Background?.Expire(); Background?.Expire();
Add(Background = newBackground); AddInternal(Background = newBackground);
currentDisplay++; currentDisplay++;
} }

View File

@ -28,7 +28,7 @@ namespace osu.Game.Screens.Edit
{ {
protected override BackgroundScreen CreateBackground() => new BackgroundScreenCustom(@"Backgrounds/bg4"); protected override BackgroundScreen CreateBackground() => new BackgroundScreenCustom(@"Backgrounds/bg4");
protected override bool HideOverlaysOnEnter => true; public override bool HideOverlaysOnEnter => true;
public override bool AllowBeatmapRulesetChange => false; public override bool AllowBeatmapRulesetChange => false;
private Box bottomBackground; private Box bottomBackground;
@ -65,7 +65,7 @@ namespace osu.Game.Screens.Edit
SummaryTimeline timeline; SummaryTimeline timeline;
PlaybackControl playback; PlaybackControl playback;
Children = new[] InternalChildren = new[]
{ {
new Container new Container
{ {
@ -96,7 +96,7 @@ namespace osu.Game.Screens.Edit
{ {
new EditorMenuItem("Export", MenuItemType.Standard, exportBeatmap), new EditorMenuItem("Export", MenuItemType.Standard, exportBeatmap),
new EditorMenuItemSpacer(), 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; return true;
} }
protected override void OnResuming(Screen last) public override void OnResuming(IScreen last)
{ {
Beatmap.Value.Track?.Stop(); Beatmap.Value.Track?.Stop();
base.OnResuming(last); base.OnResuming(last);
} }
protected override void OnEntering(Screen last) public override void OnEntering(IScreen last)
{ {
base.OnEntering(last); base.OnEntering(last);
Background.FadeColour(Color4.DarkGray, 500); Background.FadeColour(Color4.DarkGray, 500);
Beatmap.Value.Track?.Stop(); Beatmap.Value.Track?.Stop();
} }
protected override bool OnExiting(Screen next) public override bool OnExiting(IScreen next)
{ {
Background.FadeColour(Color4.White, 500); Background.FadeColour(Color4.White, 500);
if (Beatmap.Value.Track != null) if (Beatmap.Value.Track != null)

View File

@ -0,0 +1,39 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Screens;
using osu.Game.Overlays;
namespace osu.Game.Screens
{
public interface IOsuScreen : IScreen
{
/// <summary>
/// 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.
/// </summary>
bool AllowBeatmapRulesetChange { get; }
bool AllowExternalScreenChange { get; }
/// <summary>
/// Whether this <see cref="OsuScreen"/> allows the cursor to be displayed.
/// </summary>
bool CursorVisible { get; }
/// <summary>
/// Whether all overlays should be hidden when this screen is entered or resumed.
/// </summary>
bool HideOverlaysOnEnter { get; }
/// <summary>
/// Whether overlays should be able to be opened once this screen is entered or resumed.
/// </summary>
OverlayActivation InitialOverlayActivationMode { get; }
/// <summary>
/// The amount of parallax to be applied while this screen is displayed.
/// </summary>
float BackgroundParallaxAmount { get; }
}
}

View File

@ -17,9 +17,9 @@ namespace osu.Game.Screens
{ {
private bool showDisclaimer; 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; protected override bool AllowBackButton => false;
@ -55,11 +55,11 @@ namespace osu.Game.Screens
protected virtual ShaderPrecompiler CreateShaderPrecompiler() => new ShaderPrecompiler(); protected virtual ShaderPrecompiler CreateShaderPrecompiler() => new ShaderPrecompiler();
protected override void OnEntering(Screen last) public override void OnEntering(IScreen last)
{ {
base.OnEntering(last); base.OnEntering(last);
LoadComponentAsync(precompiler = CreateShaderPrecompiler(), Add); LoadComponentAsync(precompiler = CreateShaderPrecompiler(), AddInternal);
LoadComponentAsync(loadableScreen = CreateLoadableScreen()); LoadComponentAsync(loadableScreen = CreateLoadableScreen());
checkIfLoaded(); checkIfLoaded();
@ -73,7 +73,7 @@ namespace osu.Game.Screens
return; return;
} }
Push(loadableScreen); this.Push(loadableScreen);
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]

View File

@ -23,8 +23,8 @@ namespace osu.Game.Screens.Menu
private Color4 iconColour; private Color4 iconColour;
private LinkFlowContainer textFlow; private LinkFlowContainer textFlow;
protected override bool HideOverlaysOnEnter => true; public override bool HideOverlaysOnEnter => true;
protected override OverlayActivation InitialOverlayActivationMode => OverlayActivation.Disabled; public override OverlayActivation InitialOverlayActivationMode => OverlayActivation.Disabled;
public override bool CursorVisible => false; public override bool CursorVisible => false;
@ -41,7 +41,7 @@ namespace osu.Game.Screens.Menu
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuColour colours) private void load(OsuColour colours)
{ {
Children = new Drawable[] InternalChildren = new Drawable[]
{ {
icon = new SpriteIcon icon = new SpriteIcon
{ {
@ -116,7 +116,7 @@ namespace osu.Game.Screens.Menu
LoadComponentAsync(intro = new Intro()); LoadComponentAsync(intro = new Intro());
} }
protected override void OnEntering(Screen last) public override void OnEntering(IScreen last)
{ {
base.OnEntering(last); base.OnEntering(last);
@ -130,12 +130,12 @@ namespace osu.Game.Screens.Menu
supporterDrawables.ForEach(d => d.FadeOut().Delay(2000).FadeIn(500)); supporterDrawables.ForEach(d => d.FadeOut().Delay(2000).FadeIn(500));
Content this
.FadeInFromZero(500) .FadeInFromZero(500)
.Then(5500) .Then(5500)
.FadeOut(250) .FadeOut(250)
.ScaleTo(0.9f, 250, Easing.InQuint) .ScaleTo(0.9f, 250, Easing.InQuint)
.Finally(d => Push(intro)); .Finally(d => this.Push(intro));
heart.FlashColour(Color4.White, 750, Easing.OutQuint).Loop(); heart.FlashColour(Color4.White, 750, Easing.OutQuint).Loop();
} }

View File

@ -34,8 +34,8 @@ namespace osu.Game.Screens.Menu
private SampleChannel welcome; private SampleChannel welcome;
private SampleChannel seeya; private SampleChannel seeya;
protected override bool HideOverlaysOnEnter => true; public override bool HideOverlaysOnEnter => true;
protected override OverlayActivation InitialOverlayActivationMode => OverlayActivation.Disabled; public override OverlayActivation InitialOverlayActivationMode => OverlayActivation.Disabled;
public override bool CursorVisible => false; public override bool CursorVisible => false;
@ -111,7 +111,7 @@ namespace osu.Game.Screens.Menu
Scheduler.AddDelayed(delegate Scheduler.AddDelayed(delegate
{ {
DidLoadMenu = true; DidLoadMenu = true;
Push(mainMenu); this.Push(mainMenu);
}, delay_step_one); }, delay_step_one);
}, delay_step_two); }, 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); 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. //cancel exiting if we haven't loaded the menu yet.
return !DidLoadMenu; return !DidLoadMenu;
} }
protected override void OnResuming(Screen last) public override void OnResuming(IScreen last)
{ {
if (!(last is MainMenu)) this.FadeIn(300);
Content.FadeIn(300);
double fadeOutTime = EXIT_DELAY; double fadeOutTime = EXIT_DELAY;
//we also handle the exit transition. //we also handle the exit transition.
@ -169,7 +168,7 @@ namespace osu.Game.Screens.Menu
else else
fadeOutTime = 500; 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. //don't want to fade out completely else we will stop running updates and shit will hit the fan.
Game.FadeTo(0.01f, fadeOutTime); Game.FadeTo(0.01f, fadeOutTime);

View File

@ -25,28 +25,25 @@ namespace osu.Game.Screens.Menu
{ {
private readonly ButtonSystem buttons; 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; protected override bool AllowBackButton => buttons.State != ButtonSystemState.Initial;
public override bool AllowExternalScreenChange => true; public override bool AllowExternalScreenChange => true;
private readonly BackgroundScreenDefault background;
private Screen songSelect; private Screen songSelect;
private readonly MenuSideFlashes sideFlashes; private readonly MenuSideFlashes sideFlashes;
protected override BackgroundScreen CreateBackground() => background; protected override BackgroundScreen CreateBackground() => new BackgroundScreenDefault();
public MainMenu() public MainMenu()
{ {
background = new BackgroundScreenDefault(); InternalChildren = new Drawable[]
Children = new Drawable[]
{ {
new ExitConfirmOverlay new ExitConfirmOverlay
{ {
Action = Exit, Action = this.Exit,
}, },
new ParallaxContainer new ParallaxContainer
{ {
@ -55,12 +52,12 @@ namespace osu.Game.Screens.Menu
{ {
buttons = new ButtonSystem buttons = new ButtonSystem
{ {
OnChart = delegate { Push(new ChartListing()); }, OnChart = delegate { this.Push(new ChartListing()); },
OnDirect = delegate { Push(new OnlineListing()); }, OnDirect = delegate {this.Push(new OnlineListing()); },
OnEdit = delegate { Push(new Editor()); }, OnEdit = delegate {this.Push(new Editor()); },
OnSolo = onSolo, OnSolo = onSolo,
OnMulti = delegate { Push(new Multiplayer()); }, OnMulti = delegate {this.Push(new Multiplayer()); },
OnExit = Exit, OnExit = this.Exit,
} }
} }
}, },
@ -73,10 +70,10 @@ namespace osu.Game.Screens.Menu
{ {
case ButtonSystemState.Initial: case ButtonSystemState.Initial:
case ButtonSystemState.Exit: case ButtonSystemState.Exit:
background.FadeColour(Color4.White, 500, Easing.OutSine); Background.FadeColour(Color4.White, 500, Easing.OutSine);
break; break;
default: default:
background.FadeColour(OsuColour.Gray(0.8f), 500, Easing.OutSine); Background.FadeColour(OsuColour.Gray(0.8f), 500, Easing.OutSine);
break; break;
} }
}; };
@ -85,8 +82,6 @@ namespace osu.Game.Screens.Menu
[BackgroundDependencyLoader(true)] [BackgroundDependencyLoader(true)]
private void load(OsuGame game = null) private void load(OsuGame game = null)
{ {
LoadComponentAsync(background);
if (game != null) if (game != null)
{ {
buttons.OnSettings = game.ToggleSettings; buttons.OnSettings = game.ToggleSettings;
@ -104,7 +99,7 @@ namespace osu.Game.Screens.Menu
public void LoadToSolo() => Schedule(onSolo); public void LoadToSolo() => Schedule(onSolo);
private void onSolo() => Push(consumeSongSelect()); private void onSolo() =>this.Push(consumeSongSelect());
private Screen consumeSongSelect() private Screen consumeSongSelect()
{ {
@ -113,7 +108,7 @@ namespace osu.Game.Screens.Menu
return s; return s;
} }
protected override void OnEntering(Screen last) public override void OnEntering(IScreen last)
{ {
base.OnEntering(last); base.OnEntering(last);
buttons.FadeInFromZero(500); buttons.FadeInFromZero(500);
@ -148,8 +143,8 @@ namespace osu.Game.Screens.Menu
const float length = 300; const float length = 300;
Content.FadeIn(length, Easing.OutQuint); this.FadeIn(length, Easing.OutQuint);
Content.MoveTo(new Vector2(0, 0), length, Easing.OutQuint); this.MoveTo(new Vector2(0, 0), length, Easing.OutQuint);
sideFlashes.Delay(length).FadeIn(64, Easing.InQuint); sideFlashes.Delay(length).FadeIn(64, Easing.InQuint);
} }
@ -164,13 +159,13 @@ namespace osu.Game.Screens.Menu
private void beatmap_ValueChanged(WorkingBeatmap newValue) private void beatmap_ValueChanged(WorkingBeatmap newValue)
{ {
if (!IsCurrentScreen) if (!this.IsCurrentScreen())
return; return;
background.Next(); ((BackgroundScreenDefault)Background).Next();
} }
protected override void OnSuspending(Screen next) public override void OnSuspending(IScreen next)
{ {
base.OnSuspending(next); base.OnSuspending(next);
@ -178,26 +173,26 @@ namespace osu.Game.Screens.Menu
buttons.State = ButtonSystemState.EnteringMode; buttons.State = ButtonSystemState.EnteringMode;
Content.FadeOut(length, Easing.InSine); this.FadeOut(length, Easing.InSine);
Content.MoveTo(new Vector2(-800, 0), length, Easing.InSine); this.MoveTo(new Vector2(-800, 0), length, Easing.InSine);
sideFlashes.FadeOut(64, Easing.OutQuint); sideFlashes.FadeOut(64, Easing.OutQuint);
} }
protected override void OnResuming(Screen last) public override void OnResuming(IScreen last)
{ {
base.OnResuming(last); base.OnResuming(last);
background.Next(); ((BackgroundScreenDefault)Background).Next();
//we may have consumed our preloaded instance, so let's make another. //we may have consumed our preloaded instance, so let's make another.
preloadSongSelect(); preloadSongSelect();
} }
protected override bool OnExiting(Screen next) public override bool OnExiting(IScreen next)
{ {
buttons.State = ButtonSystemState.Exit; buttons.State = ButtonSystemState.Exit;
Content.FadeOut(3000); this.FadeOut(3000);
return base.OnExiting(next); return base.OnExiting(next);
} }
@ -205,7 +200,7 @@ namespace osu.Game.Screens.Menu
{ {
if (!e.Repeat && e.ControlPressed && e.ShiftPressed && e.Key == Key.D) if (!e.Repeat && e.ControlPressed && e.ShiftPressed && e.Key == Key.D)
{ {
Push(new Drawings()); this.Push(new Drawings());
return true; return true;
} }

View File

@ -22,7 +22,7 @@ namespace osu.Game.Screens.Multi
private readonly OsuSpriteText screenType; private readonly OsuSpriteText screenType;
private readonly HeaderBreadcrumbControl breadcrumbs; private readonly HeaderBreadcrumbControl breadcrumbs;
public Header(Screen initialScreen) public Header(ScreenStack stack)
{ {
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
Height = HEIGHT; Height = HEIGHT;
@ -75,7 +75,7 @@ namespace osu.Game.Screens.Multi
}, },
}, },
}, },
breadcrumbs = new HeaderBreadcrumbControl(initialScreen) breadcrumbs = new HeaderBreadcrumbControl(stack)
{ {
Anchor = Anchor.BottomLeft, Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft, Origin = Anchor.BottomLeft,
@ -103,8 +103,8 @@ namespace osu.Game.Screens.Multi
private class HeaderBreadcrumbControl : ScreenBreadcrumbControl private class HeaderBreadcrumbControl : ScreenBreadcrumbControl
{ {
public HeaderBreadcrumbControl(Screen initialScreen) public HeaderBreadcrumbControl(ScreenStack stack)
: base(initialScreen) : base(stack)
{ {
} }

View File

@ -3,8 +3,10 @@
namespace osu.Game.Screens.Multi namespace osu.Game.Screens.Multi
{ {
public interface IMultiplayerSubScreen public interface IMultiplayerSubScreen : IOsuScreen
{ {
string Title { get; }
string ShortTitle { get; } string ShortTitle { get; }
} }
} }

View File

@ -2,7 +2,6 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System; using System;
using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
@ -17,6 +16,8 @@ namespace osu.Game.Screens.Multi.Lounge
{ {
public class LoungeSubScreen : MultiplayerSubScreen public class LoungeSubScreen : MultiplayerSubScreen
{ {
public override string Title => "Lounge";
protected readonly FilterControl Filter; protected readonly FilterControl Filter;
private readonly Container content; private readonly Container content;
@ -24,20 +25,13 @@ namespace osu.Game.Screens.Multi.Lounge
private readonly Action<Screen> pushGameplayScreen; private readonly Action<Screen> pushGameplayScreen;
private readonly ProcessingOverlay processingOverlay; 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<Screen> pushGameplayScreen) public LoungeSubScreen(Action<Screen> pushGameplayScreen)
{ {
this.pushGameplayScreen = pushGameplayScreen; this.pushGameplayScreen = pushGameplayScreen;
RoomInspector inspector; RoomInspector inspector;
Children = new Drawable[] InternalChildren = new Drawable[]
{ {
Filter = new FilterControl { Depth = -1 }, Filter = new FilterControl { Depth = -1 },
content = new Container content = new Container
@ -81,7 +75,7 @@ namespace osu.Game.Screens.Multi.Lounge
Filter.Search.Current.ValueChanged += s => filterRooms(); Filter.Search.Current.ValueChanged += s => filterRooms();
Filter.Tabs.Current.ValueChanged += t => filterRooms(); Filter.Tabs.Current.ValueChanged += t => filterRooms();
Filter.Search.Exit += Exit; Filter.Search.Exit += this.Exit;
} }
protected override void UpdateAfterChildren() protected override void UpdateAfterChildren()
@ -91,8 +85,8 @@ namespace osu.Game.Screens.Multi.Lounge
content.Padding = new MarginPadding content.Padding = new MarginPadding
{ {
Top = Filter.DrawHeight, Top = Filter.DrawHeight,
Left = SearchableListOverlay.WIDTH_PADDING - DrawableRoom.SELECTION_BORDER_WIDTH + HORIZONTAL_OVERFLOW_PADDING, Left = SearchableListOverlay.WIDTH_PADDING - DrawableRoom.SELECTION_BORDER_WIDTH + OsuScreen.HORIZONTAL_OVERFLOW_PADDING,
Right = SearchableListOverlay.WIDTH_PADDING + HORIZONTAL_OVERFLOW_PADDING, Right = SearchableListOverlay.WIDTH_PADDING + OsuScreen.HORIZONTAL_OVERFLOW_PADDING,
}; };
} }
@ -101,20 +95,19 @@ namespace osu.Game.Screens.Multi.Lounge
Filter.Search.TakeFocus(); Filter.Search.TakeFocus();
} }
protected override void OnEntering(Screen last) public override void OnEntering(IScreen last)
{ {
base.OnEntering(last); base.OnEntering(last);
Filter.Search.HoldFocus = true; Filter.Search.HoldFocus = true;
} }
protected override bool OnExiting(Screen next) public override bool OnExiting(IScreen next)
{ {
Filter.Search.HoldFocus = false; Filter.Search.HoldFocus = false;
// no base call; don't animate return base.OnExiting(next);
return false;
} }
protected override void OnSuspending(Screen next) public override void OnSuspending(IScreen next)
{ {
base.OnSuspending(next); base.OnSuspending(next);
Filter.Search.HoldFocus = false; Filter.Search.HoldFocus = false;
@ -123,13 +116,13 @@ namespace osu.Game.Screens.Multi.Lounge
private void filterRooms() private void filterRooms()
{ {
rooms.Filter(Filter.CreateCriteria()); rooms.Filter(Filter.CreateCriteria());
roomManager?.Filter(Filter.CreateCriteria()); Manager?.Filter(Filter.CreateCriteria());
} }
private void joinRequested(Room room) private void joinRequested(Room room)
{ {
processingOverlay.Show(); processingOverlay.Show();
roomManager?.JoinRoom(room, r => Manager?.JoinRoom(room, r =>
{ {
Push(room); Push(room);
processingOverlay.Hide(); processingOverlay.Hide();
@ -142,10 +135,10 @@ namespace osu.Game.Screens.Multi.Lounge
public void Push(Room room) public void Push(Room room)
{ {
// Handles the case where a room is clicked 3 times in quick succession // Handles the case where a room is clicked 3 times in quick succession
if (!IsCurrentScreen) if (!this.IsCurrentScreen())
return; return;
Push(new MatchSubScreen(room, s => pushGameplayScreen?.Invoke(s))); this.Push(new MatchSubScreen(room, s => pushGameplayScreen?.Invoke(s)));
} }
} }
} }

View File

@ -21,6 +21,7 @@ namespace osu.Game.Screens.Multi.Match
public class MatchSubScreen : MultiplayerSubScreen public class MatchSubScreen : MultiplayerSubScreen
{ {
public override bool AllowBeatmapRulesetChange => false; public override bool AllowBeatmapRulesetChange => false;
public override string Title => room.RoomID.Value == null ? "New room" : room.Name.Value; public override string Title => room.RoomID.Value == null ? "New room" : room.Name.Value;
public override string ShortTitle => "room"; public override string ShortTitle => "room";
@ -36,12 +37,6 @@ namespace osu.Game.Screens.Multi.Match
[Resolved] [Resolved]
private BeatmapManager beatmapManager { get; set; } 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<Screen> pushGameplayScreen) public MatchSubScreen(Room room, Action<Screen> pushGameplayScreen)
{ {
this.room = room; this.room = room;
@ -55,7 +50,7 @@ namespace osu.Game.Screens.Multi.Match
GridContainer bottomRow; GridContainer bottomRow;
MatchSettingsOverlay settings; MatchSettingsOverlay settings;
Children = new Drawable[] InternalChildren = new Drawable[]
{ {
new GridContainer new GridContainer
{ {
@ -77,7 +72,7 @@ namespace osu.Game.Screens.Multi.Match
{ {
Padding = new MarginPadding Padding = new MarginPadding
{ {
Left = 10 + HORIZONTAL_OVERFLOW_PADDING, Left = 10 + OsuScreen.HORIZONTAL_OVERFLOW_PADDING,
Right = 10, Right = 10,
Vertical = 10, Vertical = 10,
}, },
@ -89,7 +84,7 @@ namespace osu.Game.Screens.Multi.Match
Padding = new MarginPadding Padding = new MarginPadding
{ {
Left = 10, Left = 10,
Right = 10 + HORIZONTAL_OVERFLOW_PADDING, Right = 10 + OsuScreen.HORIZONTAL_OVERFLOW_PADDING,
Vertical = 10, Vertical = 10,
}, },
RelativeSizeAxes = Axes.Both, 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, Selected = addPlaylistItem,
Padding = new MarginPadding { Horizontal = HORIZONTAL_OVERFLOW_PADDING }
}); });
header.Tabs.Current.ValueChanged += t => 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] [BackgroundDependencyLoader]
@ -150,9 +148,9 @@ namespace osu.Game.Screens.Multi.Match
beatmapManager.ItemAdded += beatmapAdded; beatmapManager.ItemAdded += beatmapAdded;
} }
protected override bool OnExiting(Screen next) public override bool OnExiting(IScreen next)
{ {
manager?.PartRoom(); Manager?.PartRoom();
return base.OnExiting(next); 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 // 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); 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) private void setRuleset(RulesetInfo ruleset)
@ -177,7 +175,7 @@ namespace osu.Game.Screens.Multi.Match
if (ruleset == null) if (ruleset == null)
return; return;
game?.ForcefullySetRuleset(ruleset); Game?.ForcefullySetRuleset(ruleset);
} }
private void beatmapAdded(BeatmapSetInfo model, bool existing, bool silent) => Schedule(() => 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); var localBeatmap = beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == bindings.CurrentBeatmap.Value.OnlineBeatmapID);
if (localBeatmap != null) if (localBeatmap != null)
game?.ForcefullySetBeatmap(beatmapManager.GetWorkingBeatmap(localBeatmap)); Game?.ForcefullySetBeatmap(beatmapManager.GetWorkingBeatmap(localBeatmap));
}); });
private void addPlaylistItem(PlaylistItem item) private void addPlaylistItem(PlaylistItem item)
@ -209,11 +207,9 @@ namespace osu.Game.Screens.Multi.Match
{ {
default: default:
case GameTypeTimeshift _: case GameTypeTimeshift _:
pushGameplayScreen?.Invoke(new PlayerLoader(() => { pushGameplayScreen?.Invoke(new PlayerLoader(() => new TimeshiftPlayer(room, room.Playlist.First().ID)
var player = new TimeshiftPlayer(room, room.Playlist.First().ID); {
player.Exited += _ => leaderboard.RefreshScores(); Exited = () => leaderboard.RefreshScores()
return player;
})); }));
break; break;
} }

View File

@ -8,6 +8,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Logging; using osu.Framework.Logging;
using osu.Framework.Screens; using osu.Framework.Screens;
using osu.Game.Beatmaps;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Backgrounds; using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
@ -15,6 +16,7 @@ using osu.Game.Graphics.UserInterface;
using osu.Game.Input; using osu.Game.Input;
using osu.Game.Online.API; using osu.Game.Online.API;
using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer;
using osu.Game.Overlays;
using osu.Game.Overlays.BeatmapSet.Buttons; using osu.Game.Overlays.BeatmapSet.Buttons;
using osu.Game.Screens.Menu; using osu.Game.Screens.Menu;
using osu.Game.Screens.Multi.Lounge; using osu.Game.Screens.Multi.Lounge;
@ -24,31 +26,56 @@ using osuTK;
namespace osu.Game.Screens.Multi namespace osu.Game.Screens.Multi
{ {
[Cached] [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 OsuButton createButton;
private readonly LoungeSubScreen loungeSubScreen; private readonly LoungeSubScreen loungeSubScreen;
private readonly ScreenStack screenStack;
private OsuScreen currentSubScreen;
[Cached(Type = typeof(IRoomManager))] [Cached(Type = typeof(IRoomManager))]
private RoomManager roomManager; private RoomManager roomManager;
[Resolved]
private IBindableBeatmap beatmap { get; set; }
[Resolved]
private OsuGameBase game { get; set; }
[Resolved] [Resolved]
private APIAccess api { get; set; } private APIAccess api { get; set; }
[Resolved(CanBeNull = true)]
private OsuLogo logo { get; set; }
public Multiplayer() public Multiplayer()
{ {
Child = waves = new MultiplayerWaveContainer Anchor = Anchor.Centre;
Origin = Anchor.Centre;
RelativeSizeAxes = Axes.Both;
InternalChild = waves = new MultiplayerWaveContainer
{ {
RelativeSizeAxes = Axes.Both, 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[] waves.AddRange(new Drawable[]
{ {
@ -76,9 +103,9 @@ namespace osu.Game.Screens.Multi
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Top = Header.HEIGHT }, Padding = new MarginPadding { Top = Header.HEIGHT },
Child = loungeSubScreen = new LoungeSubScreen(Push), Child = screenStack
}, },
new Header(loungeSubScreen), new Header(screenStack),
createButton = new HeaderButton createButton = new HeaderButton
{ {
Anchor = Anchor.TopRight, Anchor = Anchor.TopRight,
@ -88,7 +115,7 @@ namespace osu.Game.Screens.Multi
Margin = new MarginPadding Margin = new MarginPadding
{ {
Top = 10, Top = 10,
Right = 10 + HORIZONTAL_OVERFLOW_PADDING, Right = 10 + OsuScreen.HORIZONTAL_OVERFLOW_PADDING,
}, },
Text = "Create room", Text = "Create room",
Action = () => loungeSubScreen.Push(new Room Action = () => loungeSubScreen.Push(new Room
@ -99,8 +126,8 @@ namespace osu.Game.Screens.Multi
roomManager = new RoomManager() roomManager = new RoomManager()
}); });
screenAdded(loungeSubScreen); screenStack.ScreenPushed += screenPushed;
loungeSubScreen.Exited += _ => Exit(); screenStack.ScreenExited += screenExited;
} }
private readonly IBindable<bool> isIdle = new BindableBool(); private readonly IBindable<bool> isIdle = new BindableBool();
@ -122,7 +149,7 @@ namespace osu.Game.Screens.Multi
private void updatePollingRate(bool idle) 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}"); Logger.Log($"Polling adjusted to {roomManager.TimeBetweenPolls}");
} }
@ -135,114 +162,106 @@ namespace osu.Game.Screens.Multi
private void forcefullyExit() private void forcefullyExit()
{ {
// This is temporary since we don't currently have a way to force screens to be exited // This is temporary since we don't currently have a way to force screens to be exited
if (IsCurrentScreen) if (this.IsCurrentScreen())
Exit(); this.Exit();
else else
{ {
MakeCurrent(); this.MakeCurrent();
Schedule(forcefullyExit); Schedule(forcefullyExit);
} }
} }
protected override void OnEntering(Screen last) public void OnEntering(IScreen last)
{ {
Content.FadeIn(); this.FadeIn();
base.OnEntering(last);
waves.Show(); waves.Show();
} }
protected override bool OnExiting(Screen next) public bool OnExiting(IScreen next)
{ {
waves.Hide(); waves.Hide();
Content.Delay(WaveContainer.DISAPPEAR_DURATION).FadeOut(); this.Delay(WaveContainer.DISAPPEAR_DURATION).FadeOut();
cancelLooping(); cancelLooping();
loungeSubScreen.MakeCurrent();
if (screenStack.CurrentScreen != null)
loungeSubScreen.MakeCurrent();
updatePollingRate(isIdle.Value); 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); logo?.AppendAnimatingAction(() => OsuScreen.ApplyLogoArrivingDefaults(logo), true);
Content.ScaleTo(1, 250, Easing.OutSine);
updatePollingRate(isIdle.Value); updatePollingRate(isIdle.Value);
} }
protected override void OnSuspending(Screen next) public void OnSuspending(IScreen next)
{ {
Content.ScaleTo(1.1f, 250, Easing.InSine); this.ScaleTo(1.1f, 250, Easing.InSine);
Content.FadeOut(250); this.FadeOut(250);
cancelLooping(); cancelLooping();
roomManager.TimeBetweenPolls = 0; roomManager.TimeBetweenPolls = 0;
base.OnSuspending(next);
} }
private void cancelLooping() private void cancelLooping()
{ {
var track = Beatmap.Value.Track; var track = beatmap.Value.Track;
if (track != null) if (track != null)
track.Looping = false; 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() protected override void Update()
{ {
base.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) if (track != null)
{ {
track.Looping = true; track.Looping = true;
if (!track.IsRunning) if (!track.IsRunning)
{ {
Game.Audio.AddItemToList(track); game.Audio.AddItemToList(track);
track.Seek(Beatmap.Value.Metadata.PreviewTime); track.Seek(beatmap.Value.Metadata.PreviewTime);
track.Start(); track.Start();
} }
} }
createButton.Hide(); createButton.Hide();
} }
else if (currentSubScreen is LoungeSubScreen) else if (screenStack.CurrentScreen is LoungeSubScreen)
createButton.Show(); createButton.Show();
} }
private void screenAdded(Screen newScreen) private void screenPushed(IScreen lastScreen, IScreen newScreen)
{ => updatePollingRate(isIdle.Value);
currentSubScreen = (OsuScreen)newScreen;
updatePollingRate(isIdle.Value);
newScreen.ModePushed += screenAdded; private void screenExited(IScreen lastScreen, IScreen newScreen)
newScreen.Exited += screenRemoved;
}
private void screenRemoved(Screen newScreen)
{ {
if (currentSubScreen is MatchSubScreen) if (lastScreen is MatchSubScreen)
cancelLooping(); cancelLooping();
currentSubScreen = (OsuScreen)newScreen;
updatePollingRate(isIdle.Value); updatePollingRate(isIdle.Value);
if (screenStack.CurrentScreen == null)
this.Exit();
} }
protected override void Dispose(bool isDisposing) protected override void Dispose(bool isDisposing)

View File

@ -1,49 +1,95 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Bindings;
using osu.Framework.Screens; using osu.Framework.Screens;
using osu.Game.Beatmaps;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Input.Bindings;
using osu.Game.Overlays;
namespace osu.Game.Screens.Multi namespace osu.Game.Screens.Multi
{ {
public abstract class MultiplayerSubScreen : OsuScreen, IMultiplayerSubScreen public abstract class MultiplayerSubScreen : CompositeDrawable, IMultiplayerSubScreen, IKeyBindingHandler<GlobalAction>
{ {
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; public virtual string ShortTitle => Title;
protected override void OnEntering(Screen last) [Resolved]
{ protected IBindableBeatmap Beatmap { get; private set; }
base.OnEntering(last);
Content.FadeInFromZero(WaveContainer.APPEAR_DURATION, Easing.OutQuint); [Resolved(CanBeNull = true)]
TransitionContent.FadeInFromZero(WaveContainer.APPEAR_DURATION, Easing.OutQuint); protected OsuGame Game { get; private set; }
TransitionContent.MoveToX(200).MoveToX(0, WaveContainer.APPEAR_DURATION, Easing.OutQuint);
[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); this.FadeInFromZero(WaveContainer.APPEAR_DURATION, Easing.OutQuint);
TransitionContent.MoveToX(200, WaveContainer.DISAPPEAR_DURATION, Easing.OutQuint); this.FadeInFromZero(WaveContainer.APPEAR_DURATION, Easing.OutQuint);
this.MoveToX(200).MoveToX(0, WaveContainer.APPEAR_DURATION, Easing.OutQuint);
return base.OnExiting(next);
} }
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); return false;
TransitionContent.MoveToX(0, WaveContainer.APPEAR_DURATION, Easing.OutQuint);
} }
protected override void OnSuspending(Screen next) public virtual void OnResuming(IScreen last)
{ {
base.OnSuspending(next); this.FadeIn(WaveContainer.APPEAR_DURATION, Easing.OutQuint);
this.MoveToX(0, WaveContainer.APPEAR_DURATION, Easing.OutQuint);
Content.FadeOut(WaveContainer.DISAPPEAR_DURATION, Easing.OutQuint);
TransitionContent.MoveToX(-200, WaveContainer.DISAPPEAR_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;
} }
} }

View File

@ -6,6 +6,7 @@ using System.Diagnostics;
using System.Threading; using System.Threading;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Logging; using osu.Framework.Logging;
using osu.Framework.Screens;
using osu.Game.Online.API; using osu.Game.Online.API;
using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests;
using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer;
@ -18,6 +19,8 @@ namespace osu.Game.Screens.Multi.Play
{ {
public class TimeshiftPlayer : Player public class TimeshiftPlayer : Player
{ {
public Action Exited;
private readonly Room room; private readonly Room room;
private readonly int playlistItemId; private readonly int playlistItemId;
@ -50,7 +53,7 @@ namespace osu.Game.Screens.Multi.Play
Schedule(() => Schedule(() =>
{ {
ValidForResume = false; ValidForResume = false;
Exit(); this.Exit();
}); });
}; };
@ -60,6 +63,16 @@ namespace osu.Game.Screens.Multi.Play
Thread.Sleep(1000); Thread.Sleep(1000);
} }
public override bool OnExiting(IScreen next)
{
if (base.OnExiting(next))
return true;
Exited?.Invoke();
return false;
}
protected override ScoreInfo CreateScore() protected override ScoreInfo CreateScore()
{ {
submitScore(); submitScore();
@ -79,6 +92,13 @@ namespace osu.Game.Screens.Multi.Play
api.Queue(request); api.Queue(request);
} }
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
Exited = null;
}
protected override Results CreateResults(ScoreInfo score) => new MatchResults(score, room); protected override Results CreateResults(ScoreInfo score) => new MatchResults(score, room);
} }
} }

View File

@ -1,7 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System;
using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Internal;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Audio; using osu.Framework.Audio;
@ -11,17 +10,14 @@ using osu.Framework.Graphics;
using osu.Framework.Input.Bindings; using osu.Framework.Input.Bindings;
using osu.Framework.Screens; using osu.Framework.Screens;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Graphics.Containers;
using osu.Game.Input.Bindings; using osu.Game.Input.Bindings;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Screens.Menu; using osu.Game.Screens.Menu;
using osuTK;
using osu.Game.Overlays; using osu.Game.Overlays;
using osu.Framework.Graphics.Containers;
namespace osu.Game.Screens namespace osu.Game.Screens
{ {
public abstract class OsuScreen : Screen, IKeyBindingHandler<GlobalAction>, IHasDescription public abstract class OsuScreen : Screen, IOsuScreen, IKeyBindingHandler<GlobalAction>, IHasDescription
{ {
/// <summary> /// <summary>
/// The amount of negative padding that should be applied to game background content which touches both the left and right sides of the screen. /// 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
/// </summary> /// </summary>
public const float HORIZONTAL_OVERFLOW_PADDING = 50; public const float HORIZONTAL_OVERFLOW_PADDING = 50;
public BackgroundScreen Background { get; private set; }
/// <summary> /// <summary>
/// A user-facing title for this screen. /// A user-facing title for this screen.
/// </summary> /// </summary>
@ -42,80 +36,62 @@ namespace osu.Game.Screens
public virtual bool AllowExternalScreenChange => false; public virtual bool AllowExternalScreenChange => false;
/// <summary>
/// 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.
/// </summary>
protected virtual BackgroundScreen CreateBackground() => null;
private Action updateOverlayStates;
/// <summary> /// <summary>
/// Whether all overlays should be hidden when this screen is entered or resumed. /// Whether all overlays should be hidden when this screen is entered or resumed.
/// </summary> /// </summary>
protected virtual bool HideOverlaysOnEnter => false; public virtual bool HideOverlaysOnEnter => false;
protected readonly Bindable<OverlayActivation> OverlayActivationMode = new Bindable<OverlayActivation>();
/// <summary> /// <summary>
/// Whether overlays should be able to be opened once this screen is entered or resumed. /// Whether overlays should be able to be opened once this screen is entered or resumed.
/// </summary> /// </summary>
protected virtual OverlayActivation InitialOverlayActivationMode => OverlayActivation.All; public virtual OverlayActivation InitialOverlayActivationMode => OverlayActivation.All;
/// <summary>
/// Whether this <see cref="OsuScreen"/> allows the cursor to be displayed.
/// </summary>
public virtual bool CursorVisible => true; public virtual bool CursorVisible => true;
protected new OsuGameBase Game => base.Game as OsuGameBase; protected new OsuGameBase Game => base.Game as OsuGameBase;
private OsuLogo logo;
/// <summary>
/// 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.
/// </summary>
public virtual bool AllowBeatmapRulesetChange => true; public virtual bool AllowBeatmapRulesetChange => true;
protected readonly Bindable<WorkingBeatmap> Beatmap = new Bindable<WorkingBeatmap>(); protected readonly Bindable<WorkingBeatmap> Beatmap = new Bindable<WorkingBeatmap>();
protected virtual float BackgroundParallaxAmount => 1; public virtual float BackgroundParallaxAmount => 1;
private ParallaxContainer backgroundParallaxContainer;
protected readonly Bindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>(); protected readonly Bindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>();
private SampleChannel sampleExit; 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)] [BackgroundDependencyLoader(true)]
private void load(BindableBeatmap beatmap, OsuGame osu, AudioManager audio, Bindable<RulesetInfo> ruleset) private void load(BindableBeatmap beatmap, OsuGame osu, AudioManager audio, Bindable<RulesetInfo> ruleset)
{ {
Beatmap.BindTo(beatmap); Beatmap.BindTo(beatmap);
Ruleset.BindTo(ruleset); 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"); sampleExit = audio.Sample.Get(@"UI/screen-back");
} }
public virtual bool OnPressed(GlobalAction action) public virtual bool OnPressed(GlobalAction action)
{ {
if (!IsCurrentScreen) return false; if (!this.IsCurrentScreen()) return false;
if (action == GlobalAction.Back && AllowBackButton) if (action == GlobalAction.Back && AllowBackButton)
{ {
Exit(); this.Exit();
return true; return true;
} }
@ -124,7 +100,7 @@ namespace osu.Game.Screens
public bool OnReleased(GlobalAction action) => action == GlobalAction.Back && AllowBackButton; public bool OnReleased(GlobalAction action) => action == GlobalAction.Back && AllowBackButton;
protected override void OnResuming(Screen last) public override void OnResuming(IScreen last)
{ {
sampleExit?.Play(); sampleExit?.Play();
applyArrivingDefaults(true); applyArrivingDefaults(true);
@ -132,71 +108,32 @@ namespace osu.Game.Screens
base.OnResuming(last); base.OnResuming(last);
} }
protected override void OnSuspending(Screen next) public override void OnSuspending(IScreen next)
{ {
base.OnSuspending(next); base.OnSuspending(next);
onSuspendingLogo(); 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); applyArrivingDefaults(false);
backgroundStack?.Push(localBackground = CreateBackground());
base.OnEntering(last); base.OnEntering(last);
} }
protected override bool OnExiting(Screen next) public override bool OnExiting(IScreen next)
{ {
if (ValidForResume && logo != null) if (ValidForResume && logo != null)
onExitingLogo(); 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)) if (base.OnExiting(next))
return true; return true;
if (localBackground != null && backgroundStack?.CurrentScreen == localBackground)
backgroundStack?.Exit();
Beatmap.UnbindAll(); Beatmap.UnbindAll();
return false; 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. /// Fired when this screen was entered or resumed and the logo state is required to be adjusted.
/// </summary> /// </summary>
protected virtual void LogoArriving(OsuLogo logo, bool resuming) protected virtual void LogoArriving(OsuLogo logo, bool resuming)
{
ApplyLogoArrivingDefaults(logo);
}
private void applyArrivingDefaults(bool isResuming)
{
logo?.AppendAnimatingAction(() =>
{
if (this.IsCurrentScreen()) LogoArriving(logo, isResuming);
}, true);
}
/// <summary>
/// Applies default animations to an arriving logo.
/// Todo: This should not exist.
/// </summary>
/// <param name="logo">The logo to apply animations to.</param>
public static void ApplyLogoArrivingDefaults(OsuLogo logo)
{ {
logo.Action = null; logo.Action = null;
logo.FadeOut(300, Easing.OutQuint); logo.FadeOut(300, Easing.OutQuint);
@ -216,24 +171,9 @@ namespace osu.Game.Screens
logo.Ripple = true; 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() private void onExitingLogo()
{ {
logo.AppendAnimatingAction(() => { LogoExiting(logo); }, false); logo?.AppendAnimatingAction(() => LogoExiting(logo), false);
} }
/// <summary> /// <summary>
@ -245,7 +185,7 @@ namespace osu.Game.Screens
private void onSuspendingLogo() private void onSuspendingLogo()
{ {
logo.AppendAnimatingAction(() => { LogoSuspending(logo); }, false); logo?.AppendAnimatingAction(() => LogoSuspending(logo), false);
} }
/// <summary> /// <summary>
@ -254,5 +194,11 @@ namespace osu.Game.Screens
protected virtual void LogoSuspending(OsuLogo logo) protected virtual void LogoSuspending(OsuLogo logo)
{ {
} }
/// <summary>
/// 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.
/// </summary>
protected virtual BackgroundScreen CreateBackground() => null;
} }
} }

View File

@ -40,11 +40,11 @@ namespace osu.Game.Screens.Play
{ {
protected override bool AllowBackButton => false; // handled by HoldForMenuButton 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; public Action RestartRequested;
@ -166,7 +166,7 @@ namespace osu.Game.Screens.Play
if (!ScoreProcessor.Mode.Disabled) if (!ScoreProcessor.Mode.Disabled)
config.BindWith(OsuSetting.ScoreDisplayMode, ScoreProcessor.Mode); config.BindWith(OsuSetting.ScoreDisplayMode, ScoreProcessor.Mode);
Children = new Drawable[] InternalChildren = new Drawable[]
{ {
pauseContainer = new PauseContainer(offsetClock, adjustableClock) pauseContainer = new PauseContainer(offsetClock, adjustableClock)
{ {
@ -225,7 +225,7 @@ namespace osu.Game.Screens.Play
{ {
Action = () => Action = () =>
{ {
if (!IsCurrentScreen) return; if (!this.IsCurrentScreen()) return;
fadeOut(true); fadeOut(true);
Restart(); Restart();
@ -260,18 +260,18 @@ namespace osu.Game.Screens.Play
private void performUserRequestedExit() private void performUserRequestedExit()
{ {
if (!IsCurrentScreen) return; if (!this.IsCurrentScreen()) return;
Exit(); this.Exit();
} }
public void Restart() public void Restart()
{ {
if (!IsCurrentScreen) return; if (!this.IsCurrentScreen()) return;
sampleRestart?.Play(); sampleRestart?.Play();
ValidForResume = false; ValidForResume = false;
RestartRequested?.Invoke(); RestartRequested?.Invoke();
Exit(); this.Exit();
} }
private ScheduledDelegate onCompletionEvent; private ScheduledDelegate onCompletionEvent;
@ -290,13 +290,13 @@ namespace osu.Game.Screens.Play
{ {
onCompletionEvent = Schedule(delegate onCompletionEvent = Schedule(delegate
{ {
if (!IsCurrentScreen) return; if (!this.IsCurrentScreen()) return;
var score = CreateScore(); var score = CreateScore();
if (RulesetContainer.ReplayScore == null) if (RulesetContainer.ReplayScore == null)
scoreManager.Import(score, true); scoreManager.Import(score, true);
Push(CreateResults(score)); this.Push(CreateResults(score));
onCompletionEvent = null; onCompletionEvent = null;
}); });
@ -331,15 +331,15 @@ namespace osu.Game.Screens.Play
return true; return true;
} }
protected override void OnEntering(Screen last) public override void OnEntering(IScreen last)
{ {
base.OnEntering(last); base.OnEntering(last);
if (!LoadedBeatmapSuccessfully) if (!LoadedBeatmapSuccessfully)
return; return;
Content.Alpha = 0; Alpha = 0;
Content this
.ScaleTo(0.7f) .ScaleTo(0.7f)
.ScaleTo(1, 750, Easing.OutQuint) .ScaleTo(1, 750, Easing.OutQuint)
.Delay(250) .Delay(250)
@ -368,13 +368,13 @@ namespace osu.Game.Screens.Play
pauseContainer.FadeIn(750, Easing.OutQuint); pauseContainer.FadeIn(750, Easing.OutQuint);
} }
protected override void OnSuspending(Screen next) public override void OnSuspending(IScreen next)
{ {
fadeOut(); fadeOut();
base.OnSuspending(next); base.OnSuspending(next);
} }
protected override bool OnExiting(Screen next) public override bool OnExiting(IScreen next)
{ {
if (onCompletionEvent != null) if (onCompletionEvent != null)
{ {
@ -401,7 +401,7 @@ namespace osu.Game.Screens.Play
private void fadeOut(bool instant = false) private void fadeOut(bool instant = false)
{ {
float fadeOutDuration = instant ? 0 : 250; float fadeOutDuration = instant ? 0 : 250;
Content.FadeOut(fadeOutDuration); this.FadeOut(fadeOutDuration);
Background?.FadeColour(Color4.White, fadeOutDuration, Easing.OutQuint); Background?.FadeColour(Color4.White, fadeOutDuration, Easing.OutQuint);
} }
@ -425,7 +425,7 @@ namespace osu.Game.Screens.Play
protected override void UpdateBackgroundElements() protected override void UpdateBackgroundElements()
{ {
if (!IsCurrentScreen) return; if (!this.IsCurrentScreen()) return;
base.UpdateBackgroundElements(); base.UpdateBackgroundElements();

View File

@ -30,10 +30,12 @@ namespace osu.Game.Screens.Play
private Player player; private Player player;
private Container content;
private BeatmapMetadataDisplay info; private BeatmapMetadataDisplay info;
private bool hideOverlays; private bool hideOverlays;
protected override bool HideOverlaysOnEnter => hideOverlays; public override bool HideOverlaysOnEnter => hideOverlays;
private Task loadTask; private Task loadTask;
@ -51,34 +53,42 @@ namespace osu.Game.Screens.Play
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
Add(info = new BeatmapMetadataDisplay(Beatmap.Value) InternalChild = content = new Container
{ {
Alpha = 0,
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
}); RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
Add(new FillFlowContainer<PlayerSettingsGroup>
{
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(), info = new BeatmapMetadataDisplay(Beatmap.Value)
new InputSettings() {
Alpha = 0,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
},
new FillFlowContainer<PlayerSettingsGroup>
{
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(); loadNewPlayer();
} }
private void playerLoaded(Player player) => info.Loading = false; private void playerLoaded(Player player) => info.Loading = false;
protected override void OnResuming(Screen last) public override void OnResuming(IScreen last)
{ {
base.OnResuming(last); base.OnResuming(last);
@ -105,21 +115,21 @@ namespace osu.Game.Screens.Play
private void contentIn() private void contentIn()
{ {
Content.ScaleTo(1, 650, Easing.OutQuint); content.ScaleTo(1, 650, Easing.OutQuint);
Content.FadeInFromZero(400); content.FadeInFromZero(400);
} }
private void contentOut() private void contentOut()
{ {
Content.ScaleTo(0.7f, 300, Easing.InQuint); content.ScaleTo(0.7f, 300, Easing.InQuint);
Content.FadeOut(250); content.FadeOut(250);
} }
protected override void OnEntering(Screen last) public override void OnEntering(IScreen last)
{ {
base.OnEntering(last); base.OnEntering(last);
Content.ScaleTo(0.7f); content.ScaleTo(0.7f);
contentIn(); contentIn();
@ -154,11 +164,12 @@ namespace osu.Game.Screens.Play
protected override void OnHoverLost(HoverLostEvent e) protected override void OnHoverLost(HoverLostEvent e)
{ {
if (GetContainingInputManager().HoveredDrawables.Contains(visualSettings)) if (GetContainingInputManager()?.HoveredDrawables.Contains(visualSettings) == true)
{ {
// show user setting preview // show user setting preview
UpdateBackgroundElements(); UpdateBackgroundElements();
} }
base.OnHoverLost(e); base.OnHoverLost(e);
} }
@ -170,7 +181,7 @@ namespace osu.Game.Screens.Play
private void pushWhenLoaded() private void pushWhenLoaded()
{ {
if (!IsCurrentScreen) return; if (!this.IsCurrentScreen()) return;
try try
{ {
@ -191,7 +202,7 @@ namespace osu.Game.Screens.Play
this.Delay(250).Schedule(() => this.Delay(250).Schedule(() =>
{ {
if (!IsCurrentScreen) return; if (!this.IsCurrentScreen()) return;
loadTask = null; loadTask = null;
@ -200,9 +211,9 @@ namespace osu.Game.Screens.Play
ValidForResume = false; ValidForResume = false;
if (player.LoadedBeatmapSuccessfully) if (player.LoadedBeatmapSuccessfully)
Push(player); this.Push(player);
else else
Exit(); this.Exit();
}); });
}, 500); }, 500);
} }
@ -218,15 +229,15 @@ namespace osu.Game.Screens.Play
pushDebounce = null; pushDebounce = null;
} }
protected override void OnSuspending(Screen next) public override void OnSuspending(IScreen next)
{ {
base.OnSuspending(next); base.OnSuspending(next);
cancelLoad(); 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); this.FadeOut(150);
cancelLoad(); cancelLoad();

View File

@ -19,10 +19,10 @@ namespace osu.Game.Screens.Play.PlayerSettings
private readonly PlayerSliderBar<double> sliderbar; private readonly PlayerSliderBar<double> sliderbar;
private readonly OsuSpriteText multiplierText;
public PlaybackSettings() public PlaybackSettings()
{ {
OsuSpriteText multiplierText;
Children = new Drawable[] Children = new Drawable[]
{ {
new Container new Container
@ -57,9 +57,6 @@ namespace osu.Game.Screens.Play.PlayerSettings
}, },
} }
}; };
sliderbar.Bindable.ValueChanged += rateMultiplier => multiplierText.Text = $"{sliderbar.Bar.TooltipText}x";
sliderbar.Bindable.TriggerChange();
} }
protected override void LoadComplete() protected override void LoadComplete()
@ -70,7 +67,11 @@ namespace osu.Game.Screens.Play.PlayerSettings
return; return;
var clockRate = AdjustableClock.Rate; var clockRate = AdjustableClock.Rate;
sliderbar.Bindable.ValueChanged += rateMultiplier => AdjustableClock.Rate = clockRate * rateMultiplier;
// can't trigger this line instantly as the underlying clock may not be ready to accept adjustments yet.
sliderbar.Bindable.ValueChanged += multiplier => AdjustableClock.Rate = clockRate * multiplier;
sliderbar.Bindable.BindValueChanged(multiplier => multiplierText.Text = $"{multiplier:0.0}x", true);
} }
} }
} }

View File

@ -16,7 +16,7 @@ namespace osu.Game.Screens.Play
{ {
protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap.Value); 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; public override bool AllowBeatmapRulesetChange => false;
@ -40,7 +40,7 @@ namespace osu.Game.Screens.Play
ShowStoryboard = config.GetBindable<bool>(OsuSetting.ShowStoryboard); ShowStoryboard = config.GetBindable<bool>(OsuSetting.ShowStoryboard);
} }
protected override void OnEntering(Screen last) public override void OnEntering(IScreen last)
{ {
base.OnEntering(last); base.OnEntering(last);
DimLevel.ValueChanged += _ => UpdateBackgroundElements(); DimLevel.ValueChanged += _ => UpdateBackgroundElements();
@ -49,7 +49,7 @@ namespace osu.Game.Screens.Play
InitializeBackgroundElements(); InitializeBackgroundElements();
} }
protected override void OnResuming(Screen last) public override void OnResuming(IScreen last)
{ {
base.OnResuming(last); base.OnResuming(last);
InitializeBackgroundElements(); InitializeBackgroundElements();
@ -66,7 +66,7 @@ namespace osu.Game.Screens.Play
/// <param name="userChange"></param> /// <param name="userChange"></param>
protected virtual void UpdateBackgroundElements() protected virtual void UpdateBackgroundElements()
{ {
if (!IsCurrentScreen) return; if (!this.IsCurrentScreen()) return;
Background?.FadeColour(OsuColour.Gray(BackgroundOpacity), BACKGROUND_FADE_DURATION, Easing.OutQuint); Background?.FadeColour(OsuColour.Gray(BackgroundOpacity), BACKGROUND_FADE_DURATION, Easing.OutQuint);
Background?.BlurTo(new Vector2((float)BlurLevel.Value * 25), BACKGROUND_FADE_DURATION, Easing.OutQuint); Background?.BlurTo(new Vector2((float)BlurLevel.Value * 25), BACKGROUND_FADE_DURATION, Easing.OutQuint);

View File

@ -55,7 +55,7 @@ namespace osu.Game.Screens.Ranking
private IEnumerable<Drawable> allCircles => new Drawable[] { circleOuterBackground, circleInner, circleOuter }; private IEnumerable<Drawable> allCircles => new Drawable[] { circleOuterBackground, circleInner, circleOuter };
protected override void OnEntering(Screen last) public override void OnEntering(IScreen last)
{ {
base.OnEntering(last); base.OnEntering(last);
(Background as BackgroundScreenBeatmap)?.BlurTo(background_blur, 2500, Easing.OutQuint); (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 => allCircles.ForEach(c =>
{ {
@ -107,7 +107,7 @@ namespace osu.Game.Screens.Ranking
Background.ScaleTo(1f, transition_time / 4, Easing.OutQuint); Background.ScaleTo(1f, transition_time / 4, Easing.OutQuint);
Content.FadeOut(transition_time / 4); this.FadeOut(transition_time / 4);
return base.OnExiting(next); return base.OnExiting(next);
} }
@ -115,7 +115,7 @@ namespace osu.Game.Screens.Ranking
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuColour colours) private void load(OsuColour colours)
{ {
Children = new Drawable[] InternalChildren = new Drawable[]
{ {
new AspectContainer new AspectContainer
{ {
@ -260,7 +260,7 @@ namespace osu.Game.Screens.Ranking
{ {
Anchor = Anchor.BottomLeft, Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft, Origin = Anchor.BottomLeft,
Action = Exit Action = this.Exit
}, },
}; };

View File

@ -30,7 +30,7 @@ namespace osu.Game.Screens
protected override BackgroundScreen CreateBackground() => new BackgroundScreenCustom(@"Backgrounds/bg2"); protected override BackgroundScreen CreateBackground() => new BackgroundScreenCustom(@"Backgrounds/bg2");
protected override void OnEntering(Screen last) public override void OnEntering(IScreen last)
{ {
base.OnEntering(last); base.OnEntering(last);
@ -38,51 +38,51 @@ namespace osu.Game.Screens
if (last != null) if (last != null)
popButton.Alpha = 1; popButton.Alpha = 1;
Content.Alpha = 0; Alpha = 0;
textContainer.Position = new Vector2(DrawSize.X / 16, 0); textContainer.Position = new Vector2(DrawSize.X / 16, 0);
boxContainer.ScaleTo(0.2f); boxContainer.ScaleTo(0.2f);
boxContainer.RotateTo(-20); boxContainer.RotateTo(-20);
using (Content.BeginDelayedSequence(300, true)) using (BeginDelayedSequence(300, true))
{ {
boxContainer.ScaleTo(1, transition_time, Easing.OutElastic); boxContainer.ScaleTo(1, transition_time, Easing.OutElastic);
boxContainer.RotateTo(0, transition_time / 2, Easing.OutQuint); boxContainer.RotateTo(0, transition_time / 2, Easing.OutQuint);
textContainer.MoveTo(Vector2.Zero, transition_time, Easing.OutExpo); 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); 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); return base.OnExiting(next);
} }
protected override void OnSuspending(Screen next) public override void OnSuspending(IScreen next)
{ {
base.OnSuspending(next); base.OnSuspending(next);
textContainer.MoveTo(new Vector2(-(DrawSize.X / 16), 0), transition_time, Easing.OutExpo); 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); base.OnResuming(last);
textContainer.MoveTo(Vector2.Zero, transition_time, Easing.OutExpo); textContainer.MoveTo(Vector2.Zero, transition_time, Easing.OutExpo);
Content.FadeIn(transition_time, Easing.OutExpo); this.FadeIn(transition_time, Easing.OutExpo);
} }
public ScreenWhiteBox() public ScreenWhiteBox()
{ {
FillFlowContainer childModeButtons; FillFlowContainer childModeButtons;
Children = new Drawable[] InternalChildren = new Drawable[]
{ {
boxContainer = new Container boxContainer = new Container
{ {
@ -148,7 +148,7 @@ namespace osu.Game.Screens
Anchor = Anchor.BottomLeft, Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft, Origin = Anchor.BottomLeft,
Alpha = 0, Alpha = 0,
Action = Exit Action = this.Exit
}, },
childModeButtons = new FillFlowContainer childModeButtons = new FillFlowContainer
{ {
@ -171,7 +171,7 @@ namespace osu.Game.Screens
HoverColour = getColourFor(t).Lighten(0.2f), HoverColour = getColourFor(t).Lighten(0.2f),
Action = delegate Action = delegate
{ {
Push(Activator.CreateInstance(t) as Screen); this.Push(Activator.CreateInstance(t) as Screen);
} }
}); });
} }

View File

@ -1,6 +1,8 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using osu.Framework.Screens;
namespace osu.Game.Screens.Select namespace osu.Game.Screens.Select
{ {
public class EditSongSelect : SongSelect public class EditSongSelect : SongSelect
@ -9,7 +11,7 @@ namespace osu.Game.Screens.Select
protected override bool OnStart() protected override bool OnStart()
{ {
Exit(); this.Exit();
return true; return true;
} }
} }

View File

@ -3,6 +3,8 @@
using System; using System;
using Humanizer; using Humanizer;
using osu.Framework.Graphics;
using osu.Framework.Screens;
using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer;
using osu.Game.Screens.Multi; using osu.Game.Screens.Multi;
@ -15,6 +17,11 @@ namespace osu.Game.Screens.Select
public string ShortTitle => "song selection"; public string ShortTitle => "song selection";
public override string Title => ShortTitle.Humanize(); public override string Title => ShortTitle.Humanize();
public MatchSongSelect()
{
Padding = new MarginPadding { Horizontal = HORIZONTAL_OVERFLOW_PADDING };
}
protected override bool OnStart() protected override bool OnStart()
{ {
var item = new PlaylistItem var item = new PlaylistItem
@ -28,8 +35,8 @@ namespace osu.Game.Screens.Select
Selected?.Invoke(item); Selected?.Invoke(item);
if (IsCurrentScreen) if (this.IsCurrentScreen())
Exit(); this.Exit();
return true; return true;
} }

View File

@ -25,7 +25,7 @@ namespace osu.Game.Screens.Select
}, Key.Number3); }, Key.Number3);
} }
protected override void OnResuming(Screen last) public override void OnResuming(IScreen last)
{ {
player = null; player = null;
@ -64,7 +64,7 @@ namespace osu.Game.Screens.Select
LoadComponentAsync(player = new PlayerLoader(() => new Player()), l => LoadComponentAsync(player = new PlayerLoader(() => new Player()), l =>
{ {
if (IsCurrentScreen) Push(player); if (this.IsCurrentScreen())this.Push(player);
}); });
return true; return true;

View File

@ -88,7 +88,7 @@ namespace osu.Game.Screens.Select
const float carousel_width = 640; const float carousel_width = 640;
const float filter_height = 100; const float filter_height = 100;
AddRange(new Drawable[] AddRangeInternal(new Drawable[]
{ {
new ParallaxContainer new ParallaxContainer
{ {
@ -156,8 +156,8 @@ namespace osu.Game.Screens.Select
Background = { Width = 2 }, Background = { Width = 2 },
Exit = () => Exit = () =>
{ {
if (IsCurrentScreen) if (this.IsCurrentScreen())
Exit(); this.Exit();
}, },
}, },
} }
@ -182,7 +182,7 @@ namespace osu.Game.Screens.Select
if (ShowFooter) if (ShowFooter)
{ {
Add(FooterPanels = new Container AddInternal(FooterPanels = new Container
{ {
Anchor = Anchor.BottomLeft, Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft, Origin = Anchor.BottomLeft,
@ -193,7 +193,7 @@ namespace osu.Game.Screens.Select
Bottom = Footer.HEIGHT, Bottom = Footer.HEIGHT,
}, },
}); });
Add(Footer = new Footer AddInternal(Footer = new Footer
{ {
OnBack = ExitFromBack, 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)] [BackgroundDependencyLoader(true)]
@ -281,13 +281,13 @@ namespace osu.Game.Screens.Select
return; return;
} }
Exit(); this.Exit();
} }
public void Edit(BeatmapInfo beatmap = null) public void Edit(BeatmapInfo beatmap = null)
{ {
Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap ?? beatmapNoDebounce); Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap ?? beatmapNoDebounce);
Push(new Editor()); this.Push(new Editor());
} }
/// <summary> /// <summary>
@ -331,7 +331,7 @@ namespace osu.Game.Screens.Select
{ {
if (beatmap is DummyWorkingBeatmap) return; 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 selecting new beatmap without bypassing filters failed, there's possibly a ruleset mismatch
if (beatmap?.BeatmapInfo?.Ruleset != null && beatmap.BeatmapInfo.Ruleset != Ruleset.Value) 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); UpdateBeatmap(Beatmap.Value);
} }
@ -431,11 +431,11 @@ namespace osu.Game.Screens.Select
Carousel.SelectNextRandom(); Carousel.SelectNextRandom();
} }
protected override void OnEntering(Screen last) public override void OnEntering(IScreen last)
{ {
base.OnEntering(last); base.OnEntering(last);
Content.FadeInFromZero(250); this.FadeInFromZero(250);
FilterControl.Activate(); FilterControl.Activate();
} }
@ -476,7 +476,7 @@ namespace osu.Game.Screens.Select
logo.FadeOut(logo_transition / 2, Easing.Out); logo.FadeOut(logo_transition / 2, Easing.Out);
} }
protected override void OnResuming(Screen last) public override void OnResuming(IScreen last)
{ {
BeatmapDetails.Leaderboard.RefreshScores(); BeatmapDetails.Leaderboard.RefreshScores();
@ -490,26 +490,26 @@ namespace osu.Game.Screens.Select
base.OnResuming(last); base.OnResuming(last);
Content.FadeIn(250); this.FadeIn(250);
Content.ScaleTo(1, 250, Easing.OutSine); this.ScaleTo(1, 250, Easing.OutSine);
FilterControl.Activate(); FilterControl.Activate();
} }
protected override void OnSuspending(Screen next) public override void OnSuspending(IScreen next)
{ {
ModSelect.Hide(); ModSelect.Hide();
Content.ScaleTo(1.1f, 250, Easing.InSine); this.ScaleTo(1.1f, 250, Easing.InSine);
Content.FadeOut(250); this.FadeOut(250);
FilterControl.Deactivate(); FilterControl.Deactivate();
base.OnSuspending(next); base.OnSuspending(next);
} }
protected override bool OnExiting(Screen next) public override bool OnExiting(IScreen next)
{ {
if (ModSelect.State == Visibility.Visible) if (ModSelect.State == Visibility.Visible)
{ {
@ -521,7 +521,7 @@ namespace osu.Game.Screens.Select
beatmapInfoWedge.State = Visibility.Hidden; beatmapInfoWedge.State = Visibility.Hidden;
Content.FadeOut(100); this.FadeOut(100);
FilterControl.Deactivate(); FilterControl.Deactivate();
@ -627,7 +627,7 @@ namespace osu.Game.Screens.Select
public override bool OnPressed(GlobalAction action) public override bool OnPressed(GlobalAction action)
{ {
if (!IsCurrentScreen) return false; if (!this.IsCurrentScreen()) return false;
switch (action) switch (action)
{ {

View File

@ -22,6 +22,7 @@ using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
using osu.Framework.IO.Stores; using osu.Framework.IO.Stores;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Screens;
namespace osu.Game.Screens.Tournament namespace osu.Game.Screens.Tournament
{ {
@ -29,7 +30,7 @@ namespace osu.Game.Screens.Tournament
{ {
private const string results_filename = "drawings_results.txt"; private const string results_filename = "drawings_results.txt";
protected override bool HideOverlaysOnEnter => true; public override bool HideOverlaysOnEnter => true;
protected override BackgroundScreen CreateBackground() => new BackgroundScreenDefault(); protected override BackgroundScreen CreateBackground() => new BackgroundScreenDefault();
@ -70,13 +71,13 @@ namespace osu.Game.Screens.Tournament
if (!TeamList.Teams.Any()) if (!TeamList.Teams.Any())
{ {
Exit(); this.Exit();
return; return;
} }
drawingsConfig = new DrawingsConfigManager(storage); drawingsConfig = new DrawingsConfigManager(storage);
Children = new Drawable[] InternalChildren = new Drawable[]
{ {
new Box new Box
{ {

View File

@ -1,6 +1,8 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Screens; using osu.Framework.Screens;
using osu.Game.Screens; using osu.Game.Screens;
@ -11,38 +13,25 @@ namespace osu.Game.Tests.Visual
/// </summary> /// </summary>
public abstract class ScreenTestCase : OsuTestCase public abstract class ScreenTestCase : OsuTestCase
{ {
private readonly TestOsuScreen baseScreen; private readonly ScreenStack stack;
[Cached]
private BackgroundScreenStack backgroundStack;
protected ScreenTestCase() 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); protected void LoadScreen(OsuScreen screen)
public class TestOsuScreen : OsuScreen
{ {
private OsuScreen nextScreen; if (stack.CurrentScreen != null)
stack.Exit();
public void LoadScreen(OsuScreen screen) => Schedule(() => stack.Push(screen);
{
nextScreen = screen;
if (IsCurrentScreen)
{
Push(screen);
nextScreen = null;
}
else
MakeCurrent();
});
protected override void OnResuming(Screen last)
{
base.OnResuming(last);
if (nextScreen != null)
LoadScreen(nextScreen);
}
} }
} }
} }

View File

@ -6,6 +6,7 @@ using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Lists; using osu.Framework.Lists;
using osu.Framework.Screens;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;

View File

@ -10,15 +10,13 @@
<ItemGroup Label="Service"> <ItemGroup Label="Service">
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" /> <Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup> </ItemGroup>
<ItemGroup Label="Project References">
<ProjectReference Include="..\osu-resources\osu.Game.Resources\osu.Game.Resources.csproj" />
</ItemGroup>
<ItemGroup Label="Package References"> <ItemGroup Label="Package References">
<PackageReference Include="Humanizer" Version="2.5.16" /> <PackageReference Include="Humanizer" Version="2.5.16" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.1" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.1" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.1" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
<PackageReference Include="ppy.osu.Framework" Version="2019.125.0" /> <PackageReference Include="ppy.osu.Game.Resources" Version="2019.128.0" />
<PackageReference Include="ppy.osu.Framework" Version="2019.131.0" />
<PackageReference Include="SharpCompress" Version="0.22.0" /> <PackageReference Include="SharpCompress" Version="0.22.0" />
<PackageReference Include="NUnit" Version="3.11.0" /> <PackageReference Include="NUnit" Version="3.11.0" />
<PackageReference Include="SharpRaven" Version="2.4.0" /> <PackageReference Include="SharpRaven" Version="2.4.0" />

View File

@ -8,7 +8,6 @@
</ItemGroup> </ItemGroup>
<ItemGroup Label="Project References"> <ItemGroup Label="Project References">
<ProjectReference Include="..\osu.Game\osu.Game.csproj" /> <ProjectReference Include="..\osu.Game\osu.Game.csproj" />
<ProjectReference Include="..\osu-resources\osu.Game.Resources\osu.Game.Resources.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="..\osu.Game\Tests\VisualTestRunner.cs"> <Compile Include="..\osu.Game\Tests\VisualTestRunner.cs">

View File

@ -104,8 +104,9 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.1" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.1" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.1" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
<PackageReference Include="ppy.osu.Framework" Version="2019.125.0" /> <PackageReference Include="ppy.osu.Game.Resources" Version="2019.128.0" />
<PackageReference Include="ppy.osu.Framework.iOS" Version="2019.125.0" /> <PackageReference Include="ppy.osu.Framework" Version="2019.131.0" />
<PackageReference Include="ppy.osu.Framework.iOS" Version="2019.131.0" />
<PackageReference Include="SharpCompress" Version="0.22.0" /> <PackageReference Include="SharpCompress" Version="0.22.0" />
<PackageReference Include="NUnit" Version="3.11.0" /> <PackageReference Include="NUnit" Version="3.11.0" />
<PackageReference Include="SharpRaven" Version="2.4.0" /> <PackageReference Include="SharpRaven" Version="2.4.0" />

View File

@ -5,8 +5,6 @@ VisualStudioVersion = 15.0.27004.2006
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game", "osu.Game\osu.Game.csproj", "{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game", "osu.Game\osu.Game.csproj", "{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}"
EndProject 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}" 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 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}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Rulesets.Catch", "osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj", "{58F6C80C-1253-4A0E-A465-B8C85EBEADF3}"

View File

@ -57,10 +57,6 @@
<Project>{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}</Project> <Project>{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}</Project>
<Name>osu.Game</Name> <Name>osu.Game</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\osu-resources\osu.Game.Resources\osu.Game.Resources.csproj">
<Project>{D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}</Project>
<Name>osu.Game.Resources</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj"> <ProjectReference Include="..\osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj">
<Project>{58F6C80C-1253-4A0E-A465-B8C85EBEADF3}</Project> <Project>{58F6C80C-1253-4A0E-A465-B8C85EBEADF3}</Project>
<Name>osu.Game.Rulesets.Catch</Name> <Name>osu.Game.Rulesets.Catch</Name>

View File

@ -5,8 +5,6 @@ VisualStudioVersion = 15.0.27004.2006
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game", "osu.Game\osu.Game.csproj", "{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game", "osu.Game\osu.Game.csproj", "{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}"
EndProject 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}" 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 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}" 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 GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|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 EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU