diff --git a/osu.Android.props b/osu.Android.props index caaa83bff4..d5390e6a3d 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Android/AndroidJoystickSettings.cs b/osu.Android/AndroidJoystickSettings.cs new file mode 100644 index 0000000000..26e921a426 --- /dev/null +++ b/osu.Android/AndroidJoystickSettings.cs @@ -0,0 +1,76 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Android.Input; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Localisation; +using osu.Game.Localisation; +using osu.Game.Overlays.Settings; + +namespace osu.Android +{ + public class AndroidJoystickSettings : SettingsSubsection + { + protected override LocalisableString Header => JoystickSettingsStrings.JoystickGamepad; + + private readonly AndroidJoystickHandler joystickHandler; + + private readonly Bindable enabled = new BindableBool(true); + + private SettingsSlider deadzoneSlider = null!; + + private Bindable handlerDeadzone = null!; + + private Bindable localDeadzone = null!; + + public AndroidJoystickSettings(AndroidJoystickHandler joystickHandler) + { + this.joystickHandler = joystickHandler; + } + + [BackgroundDependencyLoader] + private void load() + { + // use local bindable to avoid changing enabled state of game host's bindable. + handlerDeadzone = joystickHandler.DeadzoneThreshold.GetBoundCopy(); + localDeadzone = handlerDeadzone.GetUnboundCopy(); + + Children = new Drawable[] + { + new SettingsCheckbox + { + LabelText = CommonStrings.Enabled, + Current = enabled + }, + deadzoneSlider = new SettingsSlider + { + LabelText = JoystickSettingsStrings.DeadzoneThreshold, + KeyboardStep = 0.01f, + DisplayAsPercentage = true, + Current = localDeadzone, + }, + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + enabled.BindTo(joystickHandler.Enabled); + enabled.BindValueChanged(e => deadzoneSlider.Current.Disabled = !e.NewValue, true); + + handlerDeadzone.BindValueChanged(val => + { + bool disabled = localDeadzone.Disabled; + + localDeadzone.Disabled = false; + localDeadzone.Value = val.NewValue; + localDeadzone.Disabled = disabled; + }, true); + + localDeadzone.BindValueChanged(val => handlerDeadzone.Value = val.NewValue); + } + } +} diff --git a/osu.Android/OsuGameAndroid.cs b/osu.Android/OsuGameAndroid.cs index 636fc7d2df..062f2ce10c 100644 --- a/osu.Android/OsuGameAndroid.cs +++ b/osu.Android/OsuGameAndroid.cs @@ -96,6 +96,9 @@ namespace osu.Android case AndroidMouseHandler mh: return new AndroidMouseSettings(mh); + case AndroidJoystickHandler jh: + return new AndroidJoystickSettings(jh); + default: return base.CreateSettingsSubsectionFor(handler); } diff --git a/osu.Android/osu.Android.csproj b/osu.Android/osu.Android.csproj index 90b02c527b..004cc8c39c 100644 --- a/osu.Android/osu.Android.csproj +++ b/osu.Android/osu.Android.csproj @@ -26,6 +26,7 @@ true + diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyFollowCircle.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyFollowCircle.cs index 324f2525bc..5b7da5a1ba 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyFollowCircle.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyFollowCircle.cs @@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy if (ParentObject.Judged) return; - double remainingTime = ParentObject.HitStateUpdateTime - Time.Current; + double remainingTime = Math.Max(0, ParentObject.HitStateUpdateTime - Time.Current); // Note that the scale adjust here is 2 instead of DrawableSliderBall.FOLLOW_AREA to match legacy behaviour. // This means the actual tracking area for gameplay purposes is larger than the sprite (but skins may be accounting for this). diff --git a/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs index be03328caa..6ef87f762c 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs @@ -274,14 +274,18 @@ namespace osu.Game.Tests.Visual.Online } }; + const int initial_great_count = 2000; + + int greatCount = initial_great_count; + foreach (var s in scores.Scores) { s.Statistics = new Dictionary { - { HitResult.Great, RNG.Next(2000) }, - { HitResult.Ok, RNG.Next(2000) }, - { HitResult.Meh, RNG.Next(2000) }, - { HitResult.Miss, RNG.Next(2000) } + { HitResult.Great, greatCount -= 100 }, + { HitResult.Ok, RNG.Next(100) }, + { HitResult.Meh, RNG.Next(100) }, + { HitResult.Miss, initial_great_count - greatCount } }; } diff --git a/osu.Game/Database/EFToRealmMigrator.cs b/osu.Game/Database/EFToRealmMigrator.cs index 3b5424b3fb..294a8cd3ed 100644 --- a/osu.Game/Database/EFToRealmMigrator.cs +++ b/osu.Game/Database/EFToRealmMigrator.cs @@ -443,7 +443,6 @@ namespace osu.Game.Database TotalScore = score.TotalScore, MaxCombo = score.MaxCombo, Accuracy = score.Accuracy, - HasReplay = ((IScoreInfo)score).HasReplay, Date = score.Date, PP = score.PP, Rank = score.Rank, diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs index 02b5a51f1f..bebc101b13 100644 --- a/osu.Game/Database/RealmAccess.cs +++ b/osu.Game/Database/RealmAccess.cs @@ -59,8 +59,9 @@ namespace osu.Game.Database /// 13 2022-01-13 Final migration of beatmaps and scores to realm (multiple new storage fields). /// 14 2022-03-01 Added BeatmapUserSettings to BeatmapInfo. /// 15 2022-07-13 Added LastPlayed to BeatmapInfo. + /// 16 2022-07-15 Removed HasReplay from ScoreInfo. /// - private const int schema_version = 15; + private const int schema_version = 16; /// /// Lock object which is held during sections, blocking realm retrieval during blocking periods. diff --git a/osu.Game/Online/API/Requests/GetScoresRequest.cs b/osu.Game/Online/API/Requests/GetScoresRequest.cs index a6cd9a52c7..966e69938c 100644 --- a/osu.Game/Online/API/Requests/GetScoresRequest.cs +++ b/osu.Game/Online/API/Requests/GetScoresRequest.cs @@ -35,7 +35,7 @@ namespace osu.Game.Online.API.Requests this.mods = mods ?? Array.Empty(); } - protected override string Target => $@"beatmaps/{beatmapInfo.OnlineID}/scores{createQueryParameters()}"; + protected override string Target => $@"beatmaps/{beatmapInfo.OnlineID}/solo-scores{createQueryParameters()}"; private string createQueryParameters() { diff --git a/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs b/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs index b70da194a5..6c48c7883f 100644 --- a/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs +++ b/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs @@ -103,9 +103,6 @@ namespace osu.Game.Online.API.Requests.Responses var mods = Mods.Select(apiMod => rulesetInstance.CreateModFromAcronym(apiMod.Acronym)).Where(m => m != null).ToArray(); - // all API scores provided by this class are considered to be legacy. - mods = mods.Append(rulesetInstance.CreateMod()).ToArray(); - var scoreInfo = ToScoreInfo(mods); scoreInfo.Ruleset = ruleset; @@ -132,8 +129,7 @@ namespace osu.Game.Online.API.Requests.Responses Rank = Rank, Statistics = Statistics, Date = EndedAt ?? DateTimeOffset.Now, - Hash = "online", // TODO: temporary? - HasReplay = HasReplay, + Hash = HasReplay ? "online" : string.Empty, // TODO: temporary? Mods = mods, PP = PP, }; diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs index 767b8646e3..2ca369d459 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs @@ -143,7 +143,7 @@ namespace osu.Game.Overlays.BeatmapListing } public void Search(string query) - => searchControl.Query.Value = query; + => Schedule(() => searchControl.Query.Value = query); protected override void LoadComplete() { diff --git a/osu.Game/Overlays/BeatmapSet/MetadataSection.cs b/osu.Game/Overlays/BeatmapSet/MetadataSection.cs index c6bf94f507..317b369d8f 100644 --- a/osu.Game/Overlays/BeatmapSet/MetadataSection.cs +++ b/osu.Game/Overlays/BeatmapSet/MetadataSection.cs @@ -3,6 +3,7 @@ #nullable disable +using System; using osu.Framework.Extensions; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -22,11 +23,14 @@ namespace osu.Game.Overlays.BeatmapSet private readonly MetadataType type; private TextFlowContainer textFlow; + private readonly Action searchAction; + private const float transition_duration = 250; - public MetadataSection(MetadataType type) + public MetadataSection(MetadataType type, Action searchAction = null) { this.type = type; + this.searchAction = searchAction; Alpha = 0; @@ -91,7 +95,12 @@ namespace osu.Game.Overlays.BeatmapSet for (int i = 0; i <= tags.Length - 1; i++) { - loaded.AddLink(tags[i], LinkAction.SearchBeatmapSet, tags[i]); + string tag = tags[i]; + + if (searchAction != null) + loaded.AddLink(tag, () => searchAction(tag)); + else + loaded.AddLink(tag, LinkAction.SearchBeatmapSet, tag); if (i != tags.Length - 1) loaded.AddText(" "); @@ -100,7 +109,11 @@ namespace osu.Game.Overlays.BeatmapSet break; case MetadataType.Source: - loaded.AddLink(text, LinkAction.SearchBeatmapSet, text); + if (searchAction != null) + loaded.AddLink(text, () => searchAction(text)); + else + loaded.AddLink(text, LinkAction.SearchBeatmapSet, text); + break; default: diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs index cbe9615380..81ca5f0300 100644 --- a/osu.Game/Scoring/ScoreInfo.cs +++ b/osu.Game/Scoring/ScoreInfo.cs @@ -45,7 +45,7 @@ namespace osu.Game.Scoring public double Accuracy { get; set; } - public bool HasReplay { get; set; } + public bool HasReplay => !string.IsNullOrEmpty(Hash); public DateTimeOffset Date { get; set; } diff --git a/osu.Game/Scoring/ScoreRank.cs b/osu.Game/Scoring/ScoreRank.cs index a4bb99add1..a1916953c4 100644 --- a/osu.Game/Scoring/ScoreRank.cs +++ b/osu.Game/Scoring/ScoreRank.cs @@ -11,6 +11,7 @@ namespace osu.Game.Scoring { public enum ScoreRank { + // TODO: Localisable? [Description(@"F")] F = -1, diff --git a/osu.Game/Screens/Ranking/ReplayDownloadButton.cs b/osu.Game/Screens/Ranking/ReplayDownloadButton.cs index 954a5159b9..7081a0156e 100644 --- a/osu.Game/Screens/Ranking/ReplayDownloadButton.cs +++ b/osu.Game/Screens/Ranking/ReplayDownloadButton.cs @@ -33,7 +33,7 @@ namespace osu.Game.Screens.Ranking if (State.Value == DownloadState.LocallyAvailable) return ReplayAvailability.Local; - if (!string.IsNullOrEmpty(Score.Value?.Hash)) + if (Score.Value?.HasReplay == true) return ReplayAvailability.Online; return ReplayAvailability.NotAvailable; diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index 2fe62c4a4e..90418efe15 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System.Linq; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; @@ -38,15 +36,18 @@ namespace osu.Game.Screens.Select private readonly LoadingLayer loading; [Resolved] - private IAPIProvider api { get; set; } + private IAPIProvider api { get; set; } = null!; - private IBeatmapInfo beatmapInfo; + [Resolved] + private SongSelect? songSelect { get; set; } - private APIFailTimes failTimes; + private IBeatmapInfo? beatmapInfo; - private int[] ratings; + private APIFailTimes? failTimes; - public IBeatmapInfo BeatmapInfo + private int[]? ratings; + + public IBeatmapInfo? BeatmapInfo { get => beatmapInfo; set @@ -56,7 +57,7 @@ namespace osu.Game.Screens.Select beatmapInfo = value; var onlineInfo = beatmapInfo as IBeatmapOnlineInfo; - var onlineSetInfo = beatmapInfo.BeatmapSet as IBeatmapSetOnlineInfo; + var onlineSetInfo = beatmapInfo?.BeatmapSet as IBeatmapSetOnlineInfo; failTimes = onlineInfo?.FailTimes; ratings = onlineSetInfo?.Ratings; @@ -140,9 +141,9 @@ namespace osu.Game.Screens.Select LayoutEasing = Easing.OutQuad, Children = new[] { - description = new MetadataSection(MetadataType.Description), - source = new MetadataSection(MetadataType.Source), - tags = new MetadataSection(MetadataType.Tags), + description = new MetadataSection(MetadataType.Description, searchOnSongSelect), + source = new MetadataSection(MetadataType.Source, searchOnSongSelect), + tags = new MetadataSection(MetadataType.Tags, searchOnSongSelect), }, }, }, @@ -175,6 +176,12 @@ namespace osu.Game.Screens.Select }, loading = new LoadingLayer(true) }; + + void searchOnSongSelect(string text) + { + if (songSelect != null) + songSelect.FilterControl.CurrentTextSearch.Value = text; + } } private void updateStatistics() diff --git a/osu.Game/Screens/Select/FilterControl.cs b/osu.Game/Screens/Select/FilterControl.cs index a92b631100..e43261f374 100644 --- a/osu.Game/Screens/Select/FilterControl.cs +++ b/osu.Game/Screens/Select/FilterControl.cs @@ -31,6 +31,8 @@ namespace osu.Game.Screens.Select public Action FilterChanged; + public Bindable CurrentTextSearch => searchTextBox.Current; + private OsuTabControl sortTabs; private Bindable sortMode; @@ -63,6 +65,7 @@ namespace osu.Game.Screens.Select } private SeekLimitedSearchTextBox searchTextBox; + private CollectionFilterDropdown collectionDropdown; public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => diff --git a/osu.Game/Screens/Select/NoResultsPlaceholder.cs b/osu.Game/Screens/Select/NoResultsPlaceholder.cs index b8b589ff99..f3c3fb4d87 100644 --- a/osu.Game/Screens/Select/NoResultsPlaceholder.cs +++ b/osu.Game/Screens/Select/NoResultsPlaceholder.cs @@ -109,7 +109,7 @@ namespace osu.Game.Screens.Select textFlow.AddParagraph("No beatmaps found!"); textFlow.AddParagraph(string.Empty); - textFlow.AddParagraph("Consider using the \""); + textFlow.AddParagraph("- Consider running the \""); textFlow.AddLink(FirstRunSetupOverlayStrings.FirstRunSetupTitle, () => firstRunSetupOverlay?.Show()); textFlow.AddText("\" to download or import some beatmaps!"); } @@ -141,15 +141,14 @@ namespace osu.Game.Screens.Select textFlow.AddLink(" enabling ", () => config.SetValue(OsuSetting.ShowConvertedBeatmaps, true)); textFlow.AddText("automatic conversion!"); } - - if (!string.IsNullOrEmpty(filter?.SearchText)) - { - textFlow.AddParagraph("- Try "); - textFlow.AddLink("searching online", LinkAction.SearchBeatmapSet, filter.SearchText); - textFlow.AddText($" for \"{filter.SearchText}\"."); - } } + if (!string.IsNullOrEmpty(filter?.SearchText)) + { + textFlow.AddParagraph("- Try "); + textFlow.AddLink("searching online", LinkAction.SearchBeatmapSet, filter.SearchText); + textFlow.AddText($" for \"{filter.SearchText}\"."); + } // TODO: add clickable link to reset criteria. } } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 355fd5f458..61fcf2e375 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index fcf71f3ab0..8843b5c831 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -61,7 +61,7 @@ - + @@ -84,7 +84,7 @@ - +