1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-22 17:12:54 +08:00

Merge branch 'master' into fix-selecting-incompatible-freemods

This commit is contained in:
Dan Balasescu 2021-02-24 15:10:48 +09:00 committed by GitHub
commit c0f21c8cbe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 222 additions and 97 deletions

View File

@ -52,6 +52,6 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.211.1" /> <PackageReference Include="ppy.osu.Game.Resources" Version="2021.211.1" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.220.0" /> <PackageReference Include="ppy.osu.Framework.Android" Version="2021.222.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -852,6 +852,21 @@ namespace osu.Game.Tests.Beatmaps.IO
} }
} }
public static async Task<BeatmapSetInfo> LoadQuickOszIntoOsu(OsuGameBase osu)
{
var temp = TestResources.GetQuickTestBeatmapForImport();
var manager = osu.Dependencies.Get<BeatmapManager>();
var importedSet = await manager.Import(new ImportTask(temp));
ensureLoaded(osu);
waitForOrAssert(() => !File.Exists(temp), "Temporary file still exists after standard import", 5000);
return manager.GetAllUsableBeatmapSets().Find(beatmapSet => beatmapSet.ID == importedSet.ID);
}
public static async Task<BeatmapSetInfo> LoadOszIntoOsu(OsuGameBase osu, string path = null, bool virtualTrack = false) public static async Task<BeatmapSetInfo> LoadOszIntoOsu(OsuGameBase osu, string path = null, bool virtualTrack = false)
{ {
var temp = path ?? TestResources.GetTestBeatmapForImport(virtualTrack); var temp = path ?? TestResources.GetTestBeatmapForImport(virtualTrack);

View File

@ -52,7 +52,7 @@ namespace osu.Game.Tests.Online
{ {
beatmaps.AllowImport = new TaskCompletionSource<bool>(); beatmaps.AllowImport = new TaskCompletionSource<bool>();
testBeatmapFile = TestResources.GetTestBeatmapForImport(); testBeatmapFile = TestResources.GetQuickTestBeatmapForImport();
testBeatmapInfo = getTestBeatmapInfo(testBeatmapFile); testBeatmapInfo = getTestBeatmapInfo(testBeatmapFile);
testBeatmapSet = testBeatmapInfo.BeatmapSet; testBeatmapSet = testBeatmapInfo.BeatmapSet;

View File

@ -15,6 +15,28 @@ namespace osu.Game.Tests.Resources
public static Stream GetTestBeatmapStream(bool virtualTrack = false) => OpenResource($"Archives/241526 Soleily - Renatus{(virtualTrack ? "_virtual" : "")}.osz"); public static Stream GetTestBeatmapStream(bool virtualTrack = false) => OpenResource($"Archives/241526 Soleily - Renatus{(virtualTrack ? "_virtual" : "")}.osz");
/// <summary>
/// Retrieve a path to a copy of a shortened (~10 second) beatmap archive with a virtual track.
/// </summary>
/// <remarks>
/// This is intended for use in tests which need to run to completion as soon as possible and don't need to test a full length beatmap.</remarks>
/// <returns>A path to a copy of a beatmap archive (osz). Should be deleted after use.</returns>
public static string GetQuickTestBeatmapForImport()
{
var tempPath = Path.GetTempFileName() + ".osz";
using (var stream = OpenResource("Archives/241526 Soleily - Renatus_virtual_quick.osz"))
using (var newFile = File.Create(tempPath))
stream.CopyTo(newFile);
Assert.IsTrue(File.Exists(tempPath));
return tempPath;
}
/// <summary>
/// Retrieve a path to a copy of a full-fledged beatmap archive.
/// </summary>
/// <param name="virtualTrack">Whether the audio track should be virtual.</param>
/// <returns>A path to a copy of a beatmap archive (osz). Should be deleted after use.</returns>
public static string GetTestBeatmapForImport(bool virtualTrack = false) public static string GetTestBeatmapForImport(bool virtualTrack = false)
{ {
var tempPath = Path.GetTempFileName() + ".osz"; var tempPath = Path.GetTempFileName() + ".osz";

View File

@ -118,6 +118,10 @@ namespace osu.Game.Tests.Rulesets
public BindableNumber<double> Frequency => throw new NotImplementedException(); public BindableNumber<double> Frequency => throw new NotImplementedException();
public BindableNumber<double> Tempo => throw new NotImplementedException(); public BindableNumber<double> Tempo => throw new NotImplementedException();
public void BindAdjustments(IAggregateAudioAdjustment component) => throw new NotImplementedException();
public void UnbindAdjustments(IAggregateAudioAdjustment component) => throw new NotImplementedException();
public void AddAdjustment(AdjustableProperty type, IBindable<double> adjustBindable) => throw new NotImplementedException(); public void AddAdjustment(AdjustableProperty type, IBindable<double> adjustBindable) => throw new NotImplementedException();
public void RemoveAdjustment(AdjustableProperty type, IBindable<double> adjustBindable) => throw new NotImplementedException(); public void RemoveAdjustment(AdjustableProperty type, IBindable<double> adjustBindable) => throw new NotImplementedException();

View File

@ -51,7 +51,7 @@ namespace osu.Game.Tests.Visual.Background
Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default)); Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default));
Dependencies.Cache(new OsuConfigManager(LocalStorage)); Dependencies.Cache(new OsuConfigManager(LocalStorage));
manager.Import(TestResources.GetTestBeatmapForImport()).Wait(); manager.Import(TestResources.GetQuickTestBeatmapForImport()).Wait();
Beatmap.SetDefault(); Beatmap.SetDefault();
} }

View File

@ -38,7 +38,7 @@ namespace osu.Game.Tests.Visual.Collections
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory)); Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, Audio, host, Beatmap.Default)); Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, Audio, host, Beatmap.Default));
beatmapManager.Import(TestResources.GetTestBeatmapForImport()).Wait(); beatmapManager.Import(TestResources.GetQuickTestBeatmapForImport()).Wait();
base.Content.AddRange(new Drawable[] base.Content.AddRange(new Drawable[]
{ {

View File

@ -1,6 +1,7 @@
// 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.Collections.Generic;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
@ -8,21 +9,17 @@ using osu.Framework.Platform;
using osu.Framework.Testing; using osu.Framework.Testing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Storyboards;
using osu.Game.Tests.Beatmaps;
using osuTK;
namespace osu.Game.Tests.Visual.Gameplay namespace osu.Game.Tests.Visual.Gameplay
{ {
[HeadlessTest] // we alter unsafe properties on the game host to test inactive window state. [HeadlessTest] // we alter unsafe properties on the game host to test inactive window state.
public class TestScenePauseWhenInactive : OsuPlayerTestScene public class TestScenePauseWhenInactive : OsuPlayerTestScene
{ {
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
{
var beatmap = (Beatmap)base.CreateBeatmap(ruleset);
beatmap.HitObjects.RemoveAll(h => h.StartTime < 30000);
return beatmap;
}
[Resolved] [Resolved]
private GameHost host { get; set; } private GameHost host { get; set; }
@ -33,10 +30,57 @@ namespace osu.Game.Tests.Visual.Gameplay
AddStep("resume player", () => Player.GameplayClockContainer.Start()); AddStep("resume player", () => Player.GameplayClockContainer.Start());
AddAssert("ensure not paused", () => !Player.GameplayClockContainer.IsPaused.Value); AddAssert("ensure not paused", () => !Player.GameplayClockContainer.IsPaused.Value);
AddStep("progress time to gameplay", () => Player.GameplayClockContainer.Seek(Player.DrawableRuleset.GameplayStartTime));
AddUntilStep("wait for pause", () => Player.GameplayClockContainer.IsPaused.Value);
}
/// <summary>
/// Tests that if a pause from focus lose is performed while in pause cooldown,
/// the player will still pause after the cooldown is finished.
/// </summary>
[Test]
public void TestPauseWhileInCooldown()
{
AddStep("move cursor outside", () => InputManager.MoveMouseTo(Player.ScreenSpaceDrawQuad.TopLeft - new Vector2(10)));
AddStep("resume player", () => Player.GameplayClockContainer.Start());
AddStep("skip to gameplay", () => Player.GameplayClockContainer.Seek(Player.DrawableRuleset.GameplayStartTime));
AddStep("set inactive", () => ((Bindable<bool>)host.IsActive).Value = false);
AddUntilStep("wait for pause", () => Player.GameplayClockContainer.IsPaused.Value);
AddStep("set active", () => ((Bindable<bool>)host.IsActive).Value = true);
AddStep("resume player", () => Player.Resume());
AddAssert("unpaused", () => !Player.GameplayClockContainer.IsPaused.Value);
bool pauseCooldownActive = false;
AddStep("set inactive again", () =>
{
pauseCooldownActive = Player.PauseCooldownActive;
((Bindable<bool>)host.IsActive).Value = false;
});
AddAssert("pause cooldown active", () => pauseCooldownActive);
AddUntilStep("wait for pause", () => Player.GameplayClockContainer.IsPaused.Value); AddUntilStep("wait for pause", () => Player.GameplayClockContainer.IsPaused.Value);
AddAssert("time of pause is after gameplay start time", () => Player.GameplayClockContainer.GameplayClock.CurrentTime >= Player.DrawableRuleset.GameplayStartTime);
} }
protected override TestPlayer CreatePlayer(Ruleset ruleset) => new TestPlayer(true, true, true); protected override TestPlayer CreatePlayer(Ruleset ruleset) => new TestPlayer(true, true, true);
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
{
return new Beatmap
{
HitObjects = new List<HitObject>
{
new HitCircle { StartTime = 30000 },
new HitCircle { StartTime = 35000 },
},
};
}
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null)
=> new TestWorkingBeatmap(beatmap, storyboard, Audio);
} }
} }

View File

@ -42,7 +42,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
{ {
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory)); Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default)); Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default));
beatmaps.Import(TestResources.GetTestBeatmapForImport(true)).Wait(); beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).Wait();
Add(beatmapTracker = new OnlinePlayBeatmapAvailablilityTracker Add(beatmapTracker = new OnlinePlayBeatmapAvailablilityTracker
{ {

View File

@ -53,7 +53,7 @@ namespace osu.Game.Tests.Visual.Navigation
PushAndConfirm(() => new TestSongSelect()); PushAndConfirm(() => new TestSongSelect());
AddStep("import beatmap", () => ImportBeatmapTest.LoadOszIntoOsu(Game, virtualTrack: true).Wait()); AddStep("import beatmap", () => ImportBeatmapTest.LoadQuickOszIntoOsu(Game).Wait());
AddUntilStep("wait for selected", () => !Game.Beatmap.IsDefault); AddUntilStep("wait for selected", () => !Game.Beatmap.IsDefault);
@ -61,7 +61,7 @@ namespace osu.Game.Tests.Visual.Navigation
AddStep("press enter", () => InputManager.Key(Key.Enter)); AddStep("press enter", () => InputManager.Key(Key.Enter));
AddUntilStep("wait for player", () => (player = Game.ScreenStack.CurrentScreen as Player) != null); AddUntilStep("wait for player", () => (player = Game.ScreenStack.CurrentScreen as Player) != null);
AddStep("seek to end", () => beatmap().Track.Seek(beatmap().Track.Length)); AddStep("seek to end", () => player.ChildrenOfType<GameplayClockContainer>().First().Seek(beatmap().Track.Length));
AddUntilStep("wait for pass", () => (results = Game.ScreenStack.CurrentScreen as ResultsScreen) != null && results.IsLoaded); AddUntilStep("wait for pass", () => (results = Game.ScreenStack.CurrentScreen as ResultsScreen) != null && results.IsLoaded);
AddStep("attempt to retry", () => results.ChildrenOfType<HotkeyRetryOverlay>().First().Action()); AddStep("attempt to retry", () => results.ChildrenOfType<HotkeyRetryOverlay>().First().Action());
AddUntilStep("wait for player", () => Game.ScreenStack.CurrentScreen != player && Game.ScreenStack.CurrentScreen is Player); AddUntilStep("wait for player", () => Game.ScreenStack.CurrentScreen != player && Game.ScreenStack.CurrentScreen is Player);

View File

@ -42,7 +42,7 @@ namespace osu.Game.Tests.Visual.Online
ensureSoleilyRemoved(); ensureSoleilyRemoved();
createButtonWithBeatmap(createSoleily()); createButtonWithBeatmap(createSoleily());
AddAssert("button state not downloaded", () => downloadButton.DownloadState == DownloadState.NotDownloaded); AddAssert("button state not downloaded", () => downloadButton.DownloadState == DownloadState.NotDownloaded);
AddStep("import soleily", () => beatmaps.Import(TestResources.GetTestBeatmapForImport())); AddStep("import soleily", () => beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()));
AddUntilStep("wait for beatmap import", () => beatmaps.GetAllUsableBeatmapSets().Any(b => b.OnlineBeatmapSetID == 241526)); AddUntilStep("wait for beatmap import", () => beatmaps.GetAllUsableBeatmapSets().Any(b => b.OnlineBeatmapSetID == 241526));
createButtonWithBeatmap(createSoleily()); createButtonWithBeatmap(createSoleily());
AddAssert("button state downloaded", () => downloadButton.DownloadState == DownloadState.LocallyAvailable); AddAssert("button state downloaded", () => downloadButton.DownloadState == DownloadState.LocallyAvailable);

View File

@ -5,7 +5,6 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Threading.Tasks;
using JetBrains.Annotations; using JetBrains.Annotations;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using NUnit.Framework; using NUnit.Framework;
@ -76,7 +75,7 @@ namespace osu.Game.Tests.Visual.Playlists
AddStep("bind user score info handler", () => AddStep("bind user score info handler", () =>
{ {
userScore = new TestScoreInfo(new OsuRuleset().RulesetInfo) { OnlineScoreID = currentScoreId++ }; userScore = new TestScoreInfo(new OsuRuleset().RulesetInfo) { OnlineScoreID = currentScoreId++ };
bindHandler(3000, userScore); bindHandler(true, userScore);
}); });
createResults(() => userScore); createResults(() => userScore);
@ -89,7 +88,7 @@ namespace osu.Game.Tests.Visual.Playlists
[Test] [Test]
public void TestShowNullUserScoreWithDelay() public void TestShowNullUserScoreWithDelay()
{ {
AddStep("bind delayed handler", () => bindHandler(3000)); AddStep("bind delayed handler", () => bindHandler(true));
createResults(); createResults();
waitForDisplay(); waitForDisplay();
@ -103,7 +102,7 @@ namespace osu.Game.Tests.Visual.Playlists
createResults(); createResults();
waitForDisplay(); waitForDisplay();
AddStep("bind delayed handler", () => bindHandler(3000)); AddStep("bind delayed handler", () => bindHandler(true));
for (int i = 0; i < 2; i++) for (int i = 0; i < 2; i++)
{ {
@ -134,7 +133,7 @@ namespace osu.Game.Tests.Visual.Playlists
createResults(() => userScore); createResults(() => userScore);
waitForDisplay(); waitForDisplay();
AddStep("bind delayed handler", () => bindHandler(3000)); AddStep("bind delayed handler", () => bindHandler(true));
for (int i = 0; i < 2; i++) for (int i = 0; i < 2; i++)
{ {
@ -169,13 +168,17 @@ namespace osu.Game.Tests.Visual.Playlists
AddWaitStep("wait for display", 5); AddWaitStep("wait for display", 5);
} }
private void bindHandler(double delay = 0, ScoreInfo userScore = null, bool failRequests = false) => ((DummyAPIAccess)API).HandleRequest = request => private void bindHandler(bool delayed = false, ScoreInfo userScore = null, bool failRequests = false) => ((DummyAPIAccess)API).HandleRequest = request =>
{ {
requestComplete = false; requestComplete = false;
double delay = delayed ? 3000 : 0;
Scheduler.AddDelayed(() =>
{
if (failRequests) if (failRequests)
{ {
triggerFail(request, delay); triggerFail(request);
return; return;
} }
@ -183,57 +186,30 @@ namespace osu.Game.Tests.Visual.Playlists
{ {
case ShowPlaylistUserScoreRequest s: case ShowPlaylistUserScoreRequest s:
if (userScore == null) if (userScore == null)
triggerFail(s, delay); triggerFail(s);
else else
triggerSuccess(s, createUserResponse(userScore), delay); triggerSuccess(s, createUserResponse(userScore));
break; break;
case IndexPlaylistScoresRequest i: case IndexPlaylistScoresRequest i:
triggerSuccess(i, createIndexResponse(i), delay); triggerSuccess(i, createIndexResponse(i));
break; break;
} }
}, delay);
}; };
private void triggerSuccess<T>(APIRequest<T> req, T result, double delay) private void triggerSuccess<T>(APIRequest<T> req, T result)
where T : class where T : class
{
if (delay == 0)
success();
else
{
Task.Run(async () =>
{
await Task.Delay(TimeSpan.FromMilliseconds(delay));
Schedule(success);
});
}
void success()
{ {
requestComplete = true; requestComplete = true;
req.TriggerSuccess(result); req.TriggerSuccess(result);
} }
}
private void triggerFail(APIRequest req, double delay) private void triggerFail(APIRequest req)
{
if (delay == 0)
fail();
else
{
Task.Run(async () =>
{
await Task.Delay(TimeSpan.FromMilliseconds(delay));
Schedule(fail);
});
}
void fail()
{ {
requestComplete = true; requestComplete = true;
req.TriggerFailure(new WebException("Failed.")); req.TriggerFailure(new WebException("Failed."));
} }
}
private MultiplayerScore createUserResponse([NotNull] ScoreInfo userScore) private MultiplayerScore createUserResponse([NotNull] ScoreInfo userScore)
{ {

View File

@ -38,7 +38,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory)); Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, Audio, host, Beatmap.Default)); Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, Audio, host, Beatmap.Default));
beatmapManager.Import(TestResources.GetTestBeatmapForImport()).Wait(); beatmapManager.Import(TestResources.GetQuickTestBeatmapForImport()).Wait();
base.Content.AddRange(new Drawable[] base.Content.AddRange(new Drawable[]
{ {

View File

@ -84,7 +84,7 @@ namespace osu.Game.Tests.Visual.UserInterface
dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesetStore, null, dependencies.Get<AudioManager>(), dependencies.Get<GameHost>(), Beatmap.Default)); dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesetStore, null, dependencies.Get<AudioManager>(), dependencies.Get<GameHost>(), Beatmap.Default));
dependencies.Cache(scoreManager = new ScoreManager(rulesetStore, () => beatmapManager, LocalStorage, null, ContextFactory)); dependencies.Cache(scoreManager = new ScoreManager(rulesetStore, () => beatmapManager, LocalStorage, null, ContextFactory));
beatmap = beatmapManager.Import(new ImportTask(TestResources.GetTestBeatmapForImport())).Result.Beatmaps[0]; beatmap = beatmapManager.Import(new ImportTask(TestResources.GetQuickTestBeatmapForImport())).Result.Beatmaps[0];
for (int i = 0; i < 50; i++) for (int i = 0; i < 50; i++)
{ {

View File

@ -138,10 +138,10 @@ namespace osu.Game.Collections
PostNotification?.Invoke(notification); PostNotification?.Invoke(notification);
var collection = readCollections(stream, notification); var collections = readCollections(stream, notification);
await importCollections(collection); await importCollections(collections);
notification.CompletionText = $"Imported {collection.Count} collections"; notification.CompletionText = $"Imported {collections.Count} collections";
notification.State = ProgressNotificationState.Completed; notification.State = ProgressNotificationState.Completed;
} }
@ -155,7 +155,7 @@ namespace osu.Game.Collections
{ {
foreach (var newCol in newCollections) foreach (var newCol in newCollections)
{ {
var existing = Collections.FirstOrDefault(c => c.Name == newCol.Name); var existing = Collections.FirstOrDefault(c => c.Name.Value == newCol.Name.Value);
if (existing == null) if (existing == null)
Collections.Add(existing = new BeatmapCollection { Name = { Value = newCol.Name.Value } }); Collections.Add(existing = new BeatmapCollection { Name = { Value = newCol.Name.Value } });

View File

@ -10,6 +10,7 @@ using System.Net.Sockets;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using osu.Framework;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions.ExceptionExtensions; using osu.Framework.Extensions.ExceptionExtensions;
using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Extensions.ObjectExtensions;
@ -246,7 +247,14 @@ namespace osu.Game.Online.API
this.password = password; this.password = password;
} }
public IHubClientConnector GetHubConnector(string clientName, string endpoint) => new HubClientConnector(clientName, endpoint, this, versionHash); public IHubClientConnector GetHubConnector(string clientName, string endpoint)
{
// disabled until the underlying runtime issue is resolved, see https://github.com/mono/mono/issues/20805.
if (RuntimeInfo.OS == RuntimeInfo.Platform.iOS)
return null;
return new HubClientConnector(clientName, endpoint, this, versionHash);
}
public RegistrationRequest.RegistrationRequestErrors CreateAccount(string email, string username, string password) public RegistrationRequest.RegistrationRequestErrors CreateAccount(string email, string username, string password)
{ {

View File

@ -1,6 +1,7 @@
// 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.IO.Network;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
namespace osu.Game.Online.API.Requests namespace osu.Game.Online.API.Requests
@ -15,6 +16,13 @@ namespace osu.Game.Online.API.Requests
this.noVideo = noVideo; this.noVideo = noVideo;
} }
protected override WebRequest CreateWebRequest()
{
var req = base.CreateWebRequest();
req.Timeout = 60000;
return req;
}
protected override string Target => $@"beatmapsets/{Model.OnlineBeatmapSetID}/download{(noVideo ? "?noVideo=1" : "")}"; protected override string Target => $@"beatmapsets/{Model.OnlineBeatmapSetID}/download{(noVideo ? "?noVideo=1" : "")}";
} }
} }

View File

@ -134,6 +134,10 @@ namespace osu.Game.Rulesets.UI
public IBindable<double> AggregateTempo => throw new NotSupportedException(); public IBindable<double> AggregateTempo => throw new NotSupportedException();
public void BindAdjustments(IAggregateAudioAdjustment component) => throw new NotImplementedException();
public void UnbindAdjustments(IAggregateAudioAdjustment component) => throw new NotImplementedException();
public int PlaybackConcurrency public int PlaybackConcurrency
{ {
get => throw new NotSupportedException(); get => throw new NotSupportedException();

View File

@ -16,7 +16,6 @@ using osu.Game.Configuration;
using osu.Game.Input.Bindings; using osu.Game.Input.Bindings;
using osu.Game.Input.Handlers; using osu.Game.Input.Handlers;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
using osuTK.Input;
using static osu.Game.Input.Handlers.ReplayInputHandler; using static osu.Game.Input.Handlers.ReplayInputHandler;
namespace osu.Game.Rulesets.UI namespace osu.Game.Rulesets.UI
@ -109,9 +108,9 @@ namespace osu.Game.Rulesets.UI
{ {
switch (e) switch (e)
{ {
case MouseDownEvent mouseDown when mouseDown.Button == MouseButton.Left || mouseDown.Button == MouseButton.Right: case MouseDownEvent _:
if (mouseDisabled.Value) if (mouseDisabled.Value)
return false; return true; // importantly, block upwards propagation so global bindings also don't fire.
break; break;

View File

@ -172,6 +172,18 @@ namespace osu.Game.Screens.Menu
return; return;
} }
// disabled until the underlying runtime issue is resolved, see https://github.com/mono/mono/issues/20805.
if (RuntimeInfo.OS == RuntimeInfo.Platform.iOS)
{
notifications?.Post(new SimpleNotification
{
Text = "Multiplayer is temporarily unavailable on iOS as we figure out some low level issues.",
Icon = FontAwesome.Solid.AppleAlt,
});
return;
}
OnMultiplayer?.Invoke(); OnMultiplayer?.Invoke();
} }

View File

@ -427,11 +427,18 @@ namespace osu.Game.Screens.Play
private void updatePauseOnFocusLostState() private void updatePauseOnFocusLostState()
{ {
if (!PauseOnFocusLost || breakTracker.IsBreakTime.Value) if (!PauseOnFocusLost || !pausingSupportedByCurrentState || breakTracker.IsBreakTime.Value)
return; return;
if (gameActive.Value == false) if (gameActive.Value == false)
Pause(); {
bool paused = Pause();
// if the initial pause could not be satisfied, the pause cooldown may be active.
// reschedule the pause attempt until it can be achieved.
if (!paused)
Scheduler.AddOnce(updatePauseOnFocusLostState);
}
} }
private IBeatmap loadPlayableBeatmap() private IBeatmap loadPlayableBeatmap()
@ -674,6 +681,9 @@ namespace osu.Game.Screens.Play
private double? lastPauseActionTime; private double? lastPauseActionTime;
protected bool PauseCooldownActive =>
lastPauseActionTime.HasValue && GameplayClockContainer.GameplayClock.CurrentTime < lastPauseActionTime + pause_cooldown;
/// <summary> /// <summary>
/// A set of conditionals which defines whether the current game state and configuration allows for /// A set of conditionals which defines whether the current game state and configuration allows for
/// pausing to be attempted via <see cref="Pause"/>. If false, the game should generally exit if a user pause /// pausing to be attempted via <see cref="Pause"/>. If false, the game should generally exit if a user pause
@ -684,11 +694,9 @@ namespace osu.Game.Screens.Play
LoadedBeatmapSuccessfully && Configuration.AllowPause && ValidForResume LoadedBeatmapSuccessfully && Configuration.AllowPause && ValidForResume
// replays cannot be paused and exit immediately // replays cannot be paused and exit immediately
&& !DrawableRuleset.HasReplayLoaded.Value && !DrawableRuleset.HasReplayLoaded.Value
// cannot pause if we are already in a fail state
&& !HasFailed; && !HasFailed;
private bool pauseCooldownActive =>
lastPauseActionTime.HasValue && GameplayClockContainer.GameplayClock.CurrentTime < lastPauseActionTime + pause_cooldown;
private bool canResume => private bool canResume =>
// cannot resume from a non-paused state // cannot resume from a non-paused state
GameplayClockContainer.IsPaused.Value GameplayClockContainer.IsPaused.Value
@ -697,12 +705,12 @@ namespace osu.Game.Screens.Play
// already resuming // already resuming
&& !IsResuming; && !IsResuming;
public void Pause() public bool Pause()
{ {
if (!pausingSupportedByCurrentState) return; if (!pausingSupportedByCurrentState) return false;
if (!IsResuming && pauseCooldownActive) if (!IsResuming && PauseCooldownActive)
return; return false;
if (IsResuming) if (IsResuming)
{ {
@ -713,6 +721,7 @@ namespace osu.Game.Screens.Play
GameplayClockContainer.Stop(); GameplayClockContainer.Stop();
PauseOverlay.Show(); PauseOverlay.Show();
lastPauseActionTime = GameplayClockContainer.GameplayClock.CurrentTime; lastPauseActionTime = GameplayClockContainer.GameplayClock.CurrentTime;
return true;
} }
public void Resume() public void Resume()

View File

@ -17,7 +17,7 @@ namespace osu.Game.Skinning
/// <summary> /// <summary>
/// A sample corresponding to an <see cref="ISampleInfo"/> that supports being pooled and responding to skin changes. /// A sample corresponding to an <see cref="ISampleInfo"/> that supports being pooled and responding to skin changes.
/// </summary> /// </summary>
public class PoolableSkinnableSample : SkinReloadableDrawable, IAggregateAudioAdjustment, IAdjustableAudioComponent public class PoolableSkinnableSample : SkinReloadableDrawable, IAdjustableAudioComponent
{ {
/// <summary> /// <summary>
/// The currently-loaded <see cref="DrawableSample"/>. /// The currently-loaded <see cref="DrawableSample"/>.
@ -165,6 +165,10 @@ namespace osu.Game.Skinning
public BindableNumber<double> Tempo => sampleContainer.Tempo; public BindableNumber<double> Tempo => sampleContainer.Tempo;
public void BindAdjustments(IAggregateAudioAdjustment component) => sampleContainer.BindAdjustments(component);
public void UnbindAdjustments(IAggregateAudioAdjustment component) => sampleContainer.UnbindAdjustments(component);
public void AddAdjustment(AdjustableProperty type, IBindable<double> adjustBindable) => sampleContainer.AddAdjustment(type, adjustBindable); public void AddAdjustment(AdjustableProperty type, IBindable<double> adjustBindable) => sampleContainer.AddAdjustment(type, adjustBindable);
public void RemoveAdjustment(AdjustableProperty type, IBindable<double> adjustBindable) => sampleContainer.RemoveAdjustment(type, adjustBindable); public void RemoveAdjustment(AdjustableProperty type, IBindable<double> adjustBindable) => sampleContainer.RemoveAdjustment(type, adjustBindable);

View File

@ -176,6 +176,16 @@ namespace osu.Game.Skinning
public BindableNumber<double> Tempo => samplesContainer.Tempo; public BindableNumber<double> Tempo => samplesContainer.Tempo;
public void BindAdjustments(IAggregateAudioAdjustment component)
{
samplesContainer.BindAdjustments(component);
}
public void UnbindAdjustments(IAggregateAudioAdjustment component)
{
samplesContainer.UnbindAdjustments(component);
}
public void AddAdjustment(AdjustableProperty type, IBindable<double> adjustBindable) public void AddAdjustment(AdjustableProperty type, IBindable<double> adjustBindable)
=> samplesContainer.AddAdjustment(type, adjustBindable); => samplesContainer.AddAdjustment(type, adjustBindable);
@ -192,6 +202,14 @@ namespace osu.Game.Skinning
public bool IsPlayed => samplesContainer.Any(s => s.Played); public bool IsPlayed => samplesContainer.Any(s => s.Played);
public IBindable<double> AggregateVolume => samplesContainer.AggregateVolume;
public IBindable<double> AggregateBalance => samplesContainer.AggregateBalance;
public IBindable<double> AggregateFrequency => samplesContainer.AggregateFrequency;
public IBindable<double> AggregateTempo => samplesContainer.AggregateTempo;
#endregion #endregion
} }
} }

View File

@ -34,6 +34,8 @@ namespace osu.Game.Tests.Visual
public new HealthProcessor HealthProcessor => base.HealthProcessor; public new HealthProcessor HealthProcessor => base.HealthProcessor;
public new bool PauseCooldownActive => base.PauseCooldownActive;
public readonly List<JudgementResult> Results = new List<JudgementResult>(); public readonly List<JudgementResult> Results = new List<JudgementResult>();
public TestPlayer(bool allowPause = true, bool showResults = true, bool pauseOnFocusLost = false) public TestPlayer(bool allowPause = true, bool showResults = true, bool pauseOnFocusLost = false)

View File

@ -29,7 +29,7 @@
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="2.2.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="2.2.0" />
<PackageReference Include="Microsoft.NETCore.Targets" Version="3.1.0" /> <PackageReference Include="Microsoft.NETCore.Targets" Version="3.1.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="ppy.osu.Framework" Version="2021.220.0" /> <PackageReference Include="ppy.osu.Framework" Version="2021.222.0" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.211.1" /> <PackageReference Include="ppy.osu.Game.Resources" Version="2021.211.1" />
<PackageReference Include="Sentry" Version="3.0.1" /> <PackageReference Include="Sentry" Version="3.0.1" />
<PackageReference Include="SharpCompress" Version="0.27.1" /> <PackageReference Include="SharpCompress" Version="0.27.1" />

View File

@ -70,7 +70,7 @@
<Reference Include="System.Net.Http" /> <Reference Include="System.Net.Http" />
</ItemGroup> </ItemGroup>
<ItemGroup Label="Package References"> <ItemGroup Label="Package References">
<PackageReference Include="ppy.osu.Framework.iOS" Version="2021.220.0" /> <PackageReference Include="ppy.osu.Framework.iOS" Version="2021.222.0" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.211.1" /> <PackageReference Include="ppy.osu.Game.Resources" Version="2021.211.1" />
</ItemGroup> </ItemGroup>
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net5.0 / net6.0) --> <!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net5.0 / net6.0) -->
@ -91,7 +91,7 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="ppy.osu.Framework" Version="2021.220.0" /> <PackageReference Include="ppy.osu.Framework" Version="2021.222.0" />
<PackageReference Include="SharpCompress" Version="0.27.1" /> <PackageReference Include="SharpCompress" Version="0.27.1" />
<PackageReference Include="NUnit" Version="3.12.0" /> <PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="SharpRaven" Version="2.4.0" /> <PackageReference Include="SharpRaven" Version="2.4.0" />