diff --git a/appveyor_deploy.yml b/appveyor_deploy.yml index 6d8d95e773..22a4859885 100644 --- a/appveyor_deploy.yml +++ b/appveyor_deploy.yml @@ -10,8 +10,8 @@ before_build: - cmd: nuget restore -verbosity quiet build_script: - ps: iex ((New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/appveyor/secure-file/master/install.ps1')) - - appveyor DownloadFile https://puu.sh/A6g5K/4d08705438.enc # signing certificate - - cmd: appveyor-tools\secure-file -decrypt 4d08705438.enc -secret %decode_secret% -out %HOMEPATH%\deanherbert.pfx + - appveyor DownloadFile https://puu.sh/BCrS8/7faccf7876.enc # signing certificate + - cmd: appveyor-tools\secure-file -decrypt 7faccf7876.enc -secret %decode_secret% -out %HOMEPATH%\deanherbert.pfx - appveyor DownloadFile https://puu.sh/A6g75/fdc6f19b04.enc # deploy configuration - cd osu-deploy - nuget restore -verbosity quiet diff --git a/osu.Desktop/Overlays/VersionManager.cs b/osu.Desktop/Overlays/VersionManager.cs index 1129969694..8881884fb4 100644 --- a/osu.Desktop/Overlays/VersionManager.cs +++ b/osu.Desktop/Overlays/VersionManager.cs @@ -27,8 +27,8 @@ namespace osu.Desktop.Overlays private NotificationOverlay notificationOverlay; private GameHost host; - public override bool HandleKeyboardInput => false; - public override bool HandleMouseInput => false; + public override bool HandleNonPositionalInput => false; + public override bool HandlePositionalInput => false; [BackgroundDependencyLoader] private void load(NotificationOverlay notification, OsuColour colours, TextureStore textures, OsuGameBase game, OsuConfigManager config, GameHost host) diff --git a/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/HoldNoteMask.cs b/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/HoldNoteMask.cs index bfa6bc0a17..03d2ba19cb 100644 --- a/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/HoldNoteMask.cs +++ b/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/HoldNoteMask.cs @@ -78,7 +78,7 @@ namespace osu.Game.Rulesets.Mania.Edit.Layers.Selection.Overlays } // Todo: This is temporary, since the note masks don't do anything special yet. In the future they will handle input. - public override bool HandleMouseInput => false; + public override bool HandlePositionalInput => false; } } } diff --git a/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderCircleMask.cs b/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderCircleMask.cs index adb28289cf..151564a2a8 100644 --- a/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderCircleMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderCircleMask.cs @@ -56,6 +56,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Layers.Selection.Overlays } // Todo: This is temporary, since the slider circle masks don't do anything special yet. In the future they will handle input. - public override bool HandleMouseInput => false; + public override bool HandlePositionalInput => false; } } diff --git a/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderMask.cs b/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderMask.cs index 0f6143a83d..aff42dd233 100644 --- a/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderMask.cs @@ -59,7 +59,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Layers.Selection.Overlays body.UpdateProgress(0); } - public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => body.ReceiveMouseInputAt(screenSpacePos); + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => body.ReceivePositionalInputAt(screenSpacePos); public override Vector2 SelectionPoint => ToScreenSpace(OriginPosition); public override Quad SelectionQuad => body.PathDrawQuad; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index 66f491532d..89f380db4e 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -184,6 +184,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables public Drawable ProxiedLayer => HeadCircle.ApproachCircle; - public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => Body.ReceiveMouseInputAt(screenSpacePos); + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Body.ReceivePositionalInputAt(screenSpacePos); } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs index b79750a1b3..1388b23fa8 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs @@ -153,10 +153,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces if (Time.Current < slider.EndTime) { - // Make sure to use the base version of ReceiveMouseInputAt so that we correctly check the position. + // Make sure to use the base version of ReceivePositionalInputAt so that we correctly check the position. Tracking = canCurrentlyTrack && lastState != null - && ReceiveMouseInputAt(lastState.Mouse.NativeState.Position) + && ReceivePositionalInputAt(lastState.Mouse.NativeState.Position) && (drawableSlider?.OsuActionInputManager?.PressedActions.Any(x => x == OsuAction.LeftButton || x == OsuAction.RightButton) ?? false); } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs index 6f0197e711..f3924ec43b 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs @@ -112,7 +112,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces container.Attach(RenderbufferInternalFormat.DepthComponent16); } - public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => path.ReceiveMouseInputAt(screenSpacePos); + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => path.ReceivePositionalInputAt(screenSpacePos); public void SetRange(double p0, double p1) { diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerBackground.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerBackground.cs index 1a7455838f..0401df7a91 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerBackground.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerBackground.cs @@ -11,8 +11,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces { public class SpinnerBackground : CircularContainer, IHasAccentColour { - public override bool HandleKeyboardInput => false; - public override bool HandleMouseInput => false; + public override bool HandleNonPositionalInput => false; + public override bool HandlePositionalInput => false; protected Box Disc; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs index 5aba60ba03..6e5bc5258b 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs @@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces }; } - public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => true; + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; private bool tracking; public bool Tracking diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs index 4a6b12d41a..60c24a6fbd 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs @@ -76,7 +76,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor } } - public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => true; + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; [BackgroundDependencyLoader] private void load(ShaderManager shaders, TextureStore textures) diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs b/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs index 4d6722b61b..4a45d4fb31 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs @@ -72,7 +72,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor return false; } - public override bool HandleMouseInput => true; // OverlayContainer will set this false when we go hidden, but we always want to receive input. + public override bool HandlePositionalInput => true; // OverlayContainer will set this false when we go hidden, but we always want to receive input. protected override void PopIn() { diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs index 61937a535c..b0010ccbf6 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs @@ -72,7 +72,8 @@ namespace osu.Game.Rulesets.Osu.UI DrawableOsuJudgement explosion = new DrawableOsuJudgement(result, judgedObject) { Origin = Anchor.Centre, - Position = ((OsuHitObject)judgedObject.HitObject).StackedEndPosition + Position = ((OsuHitObject)judgedObject.HitObject).StackedEndPosition, + Scale = new Vector2(((OsuHitObject)judgedObject.HitObject).Scale * 1.65f) }; judgementLayer.Add(explosion); diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs index f59dc8c1ee..6f7264e23b 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs @@ -24,6 +24,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables private bool validActionPressed; + private bool pressHandledThisFrame; + protected DrawableHit(Hit hit) : base(hit) { @@ -51,6 +53,9 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables public override bool OnPressed(TaikoAction action) { + if (pressHandledThisFrame) + return true; + if (Judged) return false; @@ -62,6 +67,10 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables if (IsHit) HitAction = action; + // Regardless of whether we've hit or not, any secondary key presses in the same frame should be discarded + // E.g. hitting a non-strong centre as a strong should not fall through and perform a hit on the next note + pressHandledThisFrame = true; + return result; } @@ -76,6 +85,10 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables { base.Update(); + // The input manager processes all input prior to us updating, so this is the perfect time + // for us to remove the extra press blocking, before input is handled in the next frame + pressHandledThisFrame = false; + Size = BaseSize * Parent.RelativeChildSize; } diff --git a/osu.Game.Tests/Visual/TestCaseCursors.cs b/osu.Game.Tests/Visual/TestCaseCursors.cs index 361e255894..d4c409b144 100644 --- a/osu.Game.Tests/Visual/TestCaseCursors.cs +++ b/osu.Game.Tests/Visual/TestCaseCursors.cs @@ -193,7 +193,7 @@ namespace osu.Game.Tests.Visual public CursorContainer Cursor { get; } public bool ProvidingUserCursor { get; } - public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => base.ReceiveMouseInputAt(screenSpacePos) || SmoothTransition && !ProvidingUserCursor; + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => base.ReceivePositionalInputAt(screenSpacePos) || SmoothTransition && !ProvidingUserCursor; private readonly Box background; diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index 2a31df462e..723bb90e7e 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -282,17 +282,19 @@ namespace osu.Game.Database /// Is a no-op for already deleted items. /// /// The item to delete. - public void Delete(TModel item) + /// false if no operation was performed + public bool Delete(TModel item) { using (ContextFactory.GetForWrite()) { // re-fetch the model on the import context. - var foundModel = queryModel().Include(s => s.Files).ThenInclude(f => f.FileInfo).First(s => s.ID == item.ID); + var foundModel = queryModel().Include(s => s.Files).ThenInclude(f => f.FileInfo).FirstOrDefault(s => s.ID == item.ID); - if (foundModel.DeletePending) return; + if (foundModel == null || foundModel.DeletePending) return false; if (ModelStore.Delete(foundModel)) Files.Dereference(foundModel.Files.Select(f => f.FileInfo).ToArray()); + return true; } } diff --git a/osu.Game/Graphics/Backgrounds/Triangles.cs b/osu.Game/Graphics/Backgrounds/Triangles.cs index 0f382900ce..bff9e49dce 100644 --- a/osu.Game/Graphics/Backgrounds/Triangles.cs +++ b/osu.Game/Graphics/Backgrounds/Triangles.cs @@ -30,8 +30,8 @@ namespace osu.Game.Graphics.Backgrounds /// private const float edge_smoothness = 1; - public override bool HandleKeyboardInput => false; - public override bool HandleMouseInput => false; + public override bool HandleNonPositionalInput => false; + public override bool HandlePositionalInput => false; public Color4 ColourLight = Color4.White; diff --git a/osu.Game/Graphics/Containers/LinkFlowContainer.cs b/osu.Game/Graphics/Containers/LinkFlowContainer.cs index 9c5da71aff..7c17f95e80 100644 --- a/osu.Game/Graphics/Containers/LinkFlowContainer.cs +++ b/osu.Game/Graphics/Containers/LinkFlowContainer.cs @@ -20,7 +20,7 @@ namespace osu.Game.Graphics.Containers { } - public override bool HandleMouseInput => true; + public override bool HandlePositionalInput => true; private OsuGame game; diff --git a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs index d2ab8441eb..a143c056ff 100644 --- a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs +++ b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs @@ -22,7 +22,7 @@ namespace osu.Game.Graphics.Containers protected virtual bool PlaySamplesOnStateChange => true; - protected override bool BlockPassThroughKeyboard => true; + protected override bool BlockNonPositionalInput => true; private PreviewTrackManager previewTrackManager; @@ -54,14 +54,14 @@ namespace osu.Game.Graphics.Containers /// Whether mouse input should be blocked screen-wide while this overlay is visible. /// Performing mouse actions outside of the valid extents will hide the overlay. /// - public virtual bool BlockScreenWideMouse => BlockPassThroughMouse; + public virtual bool BlockScreenWideMouse => BlockPositionalInput; // receive input outside our bounds so we can trigger a close event on ourselves. - public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => BlockScreenWideMouse || base.ReceiveMouseInputAt(screenSpacePos); + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => BlockScreenWideMouse || base.ReceivePositionalInputAt(screenSpacePos); protected override bool OnClick(InputState state) { - if (!base.ReceiveMouseInputAt(state.Mouse.NativeState.Position)) + if (!base.ReceivePositionalInputAt(state.Mouse.NativeState.Position)) { State = Visibility.Hidden; return true; diff --git a/osu.Game/Graphics/DrawableDate.cs b/osu.Game/Graphics/DrawableDate.cs index be794d93a6..1a7ed607e6 100644 --- a/osu.Game/Graphics/DrawableDate.cs +++ b/osu.Game/Graphics/DrawableDate.cs @@ -54,7 +54,7 @@ namespace osu.Game.Graphics Scheduler.AddDelayed(updateTimeWithReschedule, timeUntilNextUpdate); } - public override bool HandleMouseInput => true; + public override bool HandlePositionalInput => true; protected virtual string Format() => Date.Humanize(); diff --git a/osu.Game/Graphics/UserInterface/BreadcrumbControl.cs b/osu.Game/Graphics/UserInterface/BreadcrumbControl.cs index f5017de639..ebb7b686e4 100644 --- a/osu.Game/Graphics/UserInterface/BreadcrumbControl.cs +++ b/osu.Game/Graphics/UserInterface/BreadcrumbControl.cs @@ -47,10 +47,10 @@ namespace osu.Game.Graphics.UserInterface public readonly SpriteIcon Chevron; //don't allow clicking between transitions and don't make the chevron clickable - public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => Alpha == 1f && Text.ReceiveMouseInputAt(screenSpacePos); + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Alpha == 1f && Text.ReceivePositionalInputAt(screenSpacePos); - public override bool HandleKeyboardInput => State == Visibility.Visible; - public override bool HandleMouseInput => State == Visibility.Visible; + public override bool HandleNonPositionalInput => State == Visibility.Visible; + public override bool HandlePositionalInput => State == Visibility.Visible; public override bool IsRemovable => true; private Visibility state; diff --git a/osu.Game/Graphics/UserInterface/DialogButton.cs b/osu.Game/Graphics/UserInterface/DialogButton.cs index ee2448ff02..5094062fae 100644 --- a/osu.Game/Graphics/UserInterface/DialogButton.cs +++ b/osu.Game/Graphics/UserInterface/DialogButton.cs @@ -211,7 +211,7 @@ namespace osu.Game.Graphics.UserInterface } } - public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => backgroundContainer.ReceiveMouseInputAt(screenSpacePos); + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => backgroundContainer.ReceivePositionalInputAt(screenSpacePos); protected override bool OnClick(InputState state) { diff --git a/osu.Game/Graphics/UserInterface/FocusedTextBox.cs b/osu.Game/Graphics/UserInterface/FocusedTextBox.cs index e4fd71e17e..18ec35c76e 100644 --- a/osu.Game/Graphics/UserInterface/FocusedTextBox.cs +++ b/osu.Game/Graphics/UserInterface/FocusedTextBox.cs @@ -34,7 +34,7 @@ namespace osu.Game.Graphics.UserInterface } // We may not be focused yet, but we need to handle keyboard input to be able to request focus - public override bool HandleKeyboardInput => HoldFocus || base.HandleKeyboardInput; + public override bool HandleNonPositionalInput => HoldFocus || base.HandleNonPositionalInput; protected override void OnFocus(InputState state) { diff --git a/osu.Game/Graphics/UserInterface/TwoLayerButton.cs b/osu.Game/Graphics/UserInterface/TwoLayerButton.cs index 4e6361d1ae..027ba67f66 100644 --- a/osu.Game/Graphics/UserInterface/TwoLayerButton.cs +++ b/osu.Game/Graphics/UserInterface/TwoLayerButton.cs @@ -170,7 +170,7 @@ namespace osu.Game.Graphics.UserInterface } } - public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => IconLayer.ReceiveMouseInputAt(screenSpacePos) || TextLayer.ReceiveMouseInputAt(screenSpacePos); + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => IconLayer.ReceivePositionalInputAt(screenSpacePos) || TextLayer.ReceivePositionalInputAt(screenSpacePos); protected override bool OnHover(InputState state) { diff --git a/osu.Game/IPC/ArchiveImportIPCChannel.cs b/osu.Game/IPC/ArchiveImportIPCChannel.cs index 6783b9712c..fa8168c1de 100644 --- a/osu.Game/IPC/ArchiveImportIPCChannel.cs +++ b/osu.Game/IPC/ArchiveImportIPCChannel.cs @@ -37,7 +37,7 @@ namespace osu.Game.IPC return; } - if (importer.HandledExtensions.Contains(Path.GetExtension(path))) + if (importer.HandledExtensions.Contains(Path.GetExtension(path)?.ToLowerInvariant())) importer.Import(path); } } diff --git a/osu.Game/Online/API/OAuth.cs b/osu.Game/Online/API/OAuth.cs index 67b908e894..7892df9aab 100644 --- a/osu.Game/Online/API/OAuth.cs +++ b/osu.Game/Online/API/OAuth.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System.Diagnostics; +using System.Net.Http; using osu.Framework.Configuration; using osu.Framework.IO.Network; @@ -40,7 +41,7 @@ namespace osu.Game.Online.API using (var req = new AccessTokenRequestPassword(username, password) { Url = $@"{endpoint}/oauth/token", - Method = HttpMethod.POST, + Method = HttpMethod.Post, ClientId = clientId, ClientSecret = clientSecret }) @@ -66,7 +67,7 @@ namespace osu.Game.Online.API using (var req = new AccessTokenRequestRefresh(refresh) { Url = $@"{endpoint}/oauth/token", - Method = HttpMethod.POST, + Method = HttpMethod.Post, ClientId = clientId, ClientSecret = clientSecret }) diff --git a/osu.Game/Online/API/Requests/GetMessagesRequest.cs b/osu.Game/Online/API/Requests/GetMessagesRequest.cs index 68de194bae..94f5a114ad 100644 --- a/osu.Game/Online/API/Requests/GetMessagesRequest.cs +++ b/osu.Game/Online/API/Requests/GetMessagesRequest.cs @@ -2,34 +2,19 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System.Collections.Generic; -using System.Linq; -using osu.Framework.IO.Network; using osu.Game.Online.Chat; namespace osu.Game.Online.API.Requests { public class GetMessagesRequest : APIRequest> { - private readonly List channels; - private readonly long? since; + private readonly Channel channel; - public GetMessagesRequest(List channels, long? sinceId) + public GetMessagesRequest(Channel channel) { - this.channels = channels; - since = sinceId; + this.channel = channel; } - protected override WebRequest CreateWebRequest() - { - string channelString = string.Join(",", channels.Select(x => x.Id)); - - var req = base.CreateWebRequest(); - req.AddParameter(@"channels", channelString); - if (since.HasValue) req.AddParameter(@"since", since.Value.ToString()); - - return req; - } - - protected override string Target => @"chat/messages"; + protected override string Target => $@"chat/channels/{channel.Id}/messages"; } } diff --git a/osu.Game/Online/API/Requests/GetUpdatesRequest.cs b/osu.Game/Online/API/Requests/GetUpdatesRequest.cs new file mode 100644 index 0000000000..950ad93396 --- /dev/null +++ b/osu.Game/Online/API/Requests/GetUpdatesRequest.cs @@ -0,0 +1,32 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using JetBrains.Annotations; +using osu.Framework.IO.Network; +using osu.Game.Online.Chat; + +namespace osu.Game.Online.API.Requests +{ + public class GetUpdatesRequest : APIRequest + { + private readonly long since; + private readonly Channel channel; + + public GetUpdatesRequest(long sinceId, [CanBeNull] Channel channel = null) + { + this.channel = channel; + since = sinceId; + } + + protected override WebRequest CreateWebRequest() + { + var req = base.CreateWebRequest(); + if (channel != null) req.AddParameter(@"channel", channel.Id.ToString()); + req.AddParameter(@"since", since.ToString()); + + return req; + } + + protected override string Target => @"chat/updates"; + } +} diff --git a/osu.Game/Online/API/Requests/GetUpdatesResponse.cs b/osu.Game/Online/API/Requests/GetUpdatesResponse.cs new file mode 100644 index 0000000000..474d8e1501 --- /dev/null +++ b/osu.Game/Online/API/Requests/GetUpdatesResponse.cs @@ -0,0 +1,18 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Collections.Generic; +using Newtonsoft.Json; +using osu.Game.Online.Chat; + +namespace osu.Game.Online.API.Requests +{ + public class GetUpdatesResponse + { + [JsonProperty] + public List Presence; + + [JsonProperty] + public List Messages; + } +} diff --git a/osu.Game/Online/API/Requests/JoinChannelRequest.cs b/osu.Game/Online/API/Requests/JoinChannelRequest.cs new file mode 100644 index 0000000000..a0a4667e98 --- /dev/null +++ b/osu.Game/Online/API/Requests/JoinChannelRequest.cs @@ -0,0 +1,31 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Net.Http; +using osu.Framework.IO.Network; +using osu.Game.Online.Chat; +using osu.Game.Users; + +namespace osu.Game.Online.API.Requests +{ + public class JoinChannelRequest : APIRequest + { + private readonly Channel channel; + private readonly User user; + + public JoinChannelRequest(Channel channel, User user) + { + this.channel = channel; + this.user = user; + } + + protected override WebRequest CreateWebRequest() + { + var req = base.CreateWebRequest(); + req.Method = HttpMethod.Put; + return req; + } + + protected override string Target => $@"chat/channels/{channel.Id}/users/{user.Id}"; + } +} diff --git a/osu.Game/Online/API/Requests/LeaveChannelRequest.cs b/osu.Game/Online/API/Requests/LeaveChannelRequest.cs new file mode 100644 index 0000000000..89bfa303c6 --- /dev/null +++ b/osu.Game/Online/API/Requests/LeaveChannelRequest.cs @@ -0,0 +1,31 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Net.Http; +using osu.Framework.IO.Network; +using osu.Game.Online.Chat; +using osu.Game.Users; + +namespace osu.Game.Online.API.Requests +{ + public class LeaveChannelRequest : APIRequest + { + private readonly Channel channel; + private readonly User user; + + public LeaveChannelRequest(Channel channel, User user) + { + this.channel = channel; + this.user = user; + } + + protected override WebRequest CreateWebRequest() + { + var req = base.CreateWebRequest(); + req.Method = HttpMethod.Delete; + return req; + } + + protected override string Target => $@"chat/channels/{channel.Id}/users/{user.Id}"; + } +} diff --git a/osu.Game/Online/API/Requests/PostMessageRequest.cs b/osu.Game/Online/API/Requests/PostMessageRequest.cs index e0a9fb83b2..8d9ba5dd5d 100644 --- a/osu.Game/Online/API/Requests/PostMessageRequest.cs +++ b/osu.Game/Online/API/Requests/PostMessageRequest.cs @@ -1,7 +1,7 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Framework.Extensions; +using System.Net.Http; using osu.Framework.IO.Network; using osu.Game.Online.Chat; @@ -20,15 +20,13 @@ namespace osu.Game.Online.API.Requests { var req = base.CreateWebRequest(); - req.Method = HttpMethod.POST; - req.AddParameter(@"target_type", message.TargetType.GetDescription()); - req.AddParameter(@"target_id", message.TargetId.ToString()); + req.Method = HttpMethod.Post; req.AddParameter(@"is_action", message.IsAction.ToString().ToLowerInvariant()); req.AddParameter(@"message", message.Content); return req; } - protected override string Target => @"chat/messages"; + protected override string Target => $@"chat/channels/{message.ChannelId}/messages"; } } diff --git a/osu.Game/Online/Chat/Channel.cs b/osu.Game/Online/Chat/Channel.cs index e7aabad780..bbe74fcac0 100644 --- a/osu.Game/Online/Chat/Channel.cs +++ b/osu.Game/Online/Chat/Channel.cs @@ -19,11 +19,14 @@ namespace osu.Game.Online.Chat public string Topic; [JsonProperty(@"type")] - public string Type; + public ChannelType Type; [JsonProperty(@"channel_id")] public int Id; + [JsonProperty(@"last_message_id")] + public long? LastMessageId; + public readonly SortedList Messages = new SortedList(Comparer.Default); private readonly List pendingMessages = new List(); @@ -51,11 +54,20 @@ namespace osu.Game.Online.Chat NewMessagesArrived?.Invoke(new[] { message }); } + public bool MessagesLoaded { get; private set; } + public void AddNewMessages(params Message[] messages) { messages = messages.Except(Messages).ToArray(); + if (messages.Length == 0) return; + Messages.AddRange(messages); + MessagesLoaded = true; + + var maxMessageId = messages.Max(m => m.Id); + if (maxMessageId > LastMessageId) + LastMessageId = maxMessageId; purgeOldMessages(); diff --git a/osu.Game/Online/Chat/ChannelType.cs b/osu.Game/Online/Chat/ChannelType.cs new file mode 100644 index 0000000000..4ac0a99fc6 --- /dev/null +++ b/osu.Game/Online/Chat/ChannelType.cs @@ -0,0 +1,11 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +namespace osu.Game.Online.Chat +{ + public enum ChannelType + { + PM, + Public + } +} diff --git a/osu.Game/Online/Chat/DrawableLinkCompiler.cs b/osu.Game/Online/Chat/DrawableLinkCompiler.cs index 475363bd51..0148d1d2c3 100644 --- a/osu.Game/Online/Chat/DrawableLinkCompiler.cs +++ b/osu.Game/Online/Chat/DrawableLinkCompiler.cs @@ -24,7 +24,7 @@ namespace osu.Game.Online.Chat /// public List Parts; - public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => Parts.Any(d => d.ReceiveMouseInputAt(screenSpacePos)); + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Parts.Any(d => d.ReceivePositionalInputAt(screenSpacePos)); protected override HoverClickSounds CreateHoverClickSounds(HoverSampleSet sampleSet) => new LinkHoverSounds(sampleSet, Parts); @@ -53,7 +53,7 @@ namespace osu.Game.Online.Chat this.parts = parts; } - public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => parts.Any(d => d.ReceiveMouseInputAt(screenSpacePos)); + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => parts.Any(d => d.ReceivePositionalInputAt(screenSpacePos)); } } } diff --git a/osu.Game/Online/Chat/Message.cs b/osu.Game/Online/Chat/Message.cs index 535035e4fc..65e0415cd3 100644 --- a/osu.Game/Online/Chat/Message.cs +++ b/osu.Game/Online/Chat/Message.cs @@ -18,11 +18,8 @@ namespace osu.Game.Online.Chat [JsonProperty(@"sender_id")] public int UserId; - [JsonProperty(@"target_type")] - public TargetType TargetType; - - [JsonProperty(@"target_id")] - public int TargetId; + [JsonProperty(@"channel_id")] + public int ChannelId; [JsonProperty(@"is_action")] public bool IsAction; diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 9a5dac35b9..73c970ce5d 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -154,7 +154,7 @@ namespace osu.Game dependencies.Cache(RulesetStore = new RulesetStore(contextFactory)); dependencies.Cache(FileStore = new FileStore(contextFactory, Host.Storage)); dependencies.Cache(BeatmapManager = new BeatmapManager(Host.Storage, contextFactory, RulesetStore, api, Audio, Host)); - dependencies.Cache(ScoreStore = new ScoreStore(Host.Storage, contextFactory, Host, BeatmapManager, RulesetStore)); + dependencies.Cache(ScoreStore = new ScoreStore(contextFactory, Host, BeatmapManager, RulesetStore)); dependencies.Cache(KeyBindingStore = new KeyBindingStore(contextFactory, RulesetStore)); dependencies.Cache(SettingsStore = new SettingsStore(contextFactory)); dependencies.Cache(RulesetConfigCache = new RulesetConfigCache(SettingsStore)); @@ -243,7 +243,7 @@ namespace osu.Game public void Import(params string[] paths) { - var extension = Path.GetExtension(paths.First()); + var extension = Path.GetExtension(paths.First())?.ToLowerInvariant(); foreach (var importer in fileImporters) if (importer.HandledExtensions.Contains(extension)) importer.Import(paths); diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs index 02cc89e57e..f66e103a21 100644 --- a/osu.Game/Overlays/BeatmapSetOverlay.cs +++ b/osu.Game/Overlays/BeatmapSetOverlay.cs @@ -51,7 +51,7 @@ namespace osu.Game.Overlays } // receive input outside our bounds so we can trigger a close event on ourselves. - public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => true; + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; public BeatmapSetOverlay() { diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 8e20d76914..dcf5b74d08 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -47,7 +47,7 @@ namespace osu.Game.Overlays public const float TAB_AREA_HEIGHT = 50; - private GetMessagesRequest fetchReq; + private GetUpdatesRequest fetchReq; private readonly ChatTabControl channelTabs; @@ -62,7 +62,7 @@ namespace osu.Game.Overlays private readonly Container channelSelectionContainer; private readonly ChannelSelectionOverlay channelSelection; - public override bool Contains(Vector2 screenSpacePos) => chatContainer.ReceiveMouseInputAt(screenSpacePos) || channelSelection.State == Visibility.Visible && channelSelection.ReceiveMouseInputAt(screenSpacePos); + public override bool Contains(Vector2 screenSpacePos) => chatContainer.ReceivePositionalInputAt(screenSpacePos) || channelSelection.State == Visibility.Visible && channelSelection.ReceivePositionalInputAt(screenSpacePos); public ChatOverlay() { @@ -285,7 +285,7 @@ namespace osu.Game.Overlays chatBackground.Colour = colours.ChatBlue; } - private long? lastMessageId; + private long lastMessageId; private readonly List careChannels = new List(); @@ -304,9 +304,9 @@ namespace osu.Game.Overlays Scheduler.Add(delegate { + //todo: decide how to handle default channels for a user now that they are saved server-side. addChannel(channels.Find(c => c.Name == @"#lazer")); addChannel(channels.Find(c => c.Name == @"#osu")); - addChannel(channels.Find(c => c.Name == @"#lobby")); channelSelection.OnRequestJoin = addChannel; channelSelection.OnRequestLeave = removeChannel; @@ -320,7 +320,7 @@ namespace osu.Game.Overlays }; }); - messageRequest = Scheduler.AddDelayed(fetchNewMessages, 1000, true); + messageRequest = Scheduler.AddDelayed(fetchUpdates, 1000, true); }; api.Queue(req); @@ -362,7 +362,7 @@ namespace osu.Game.Overlays loadedChannels.Add(loaded); LoadComponentAsync(loaded, l => { - if (currentChannel.Messages.Any()) + if (currentChannel.MessagesLoaded) loading.Hide(); currentChannelContainer.Clear(false); @@ -394,6 +394,15 @@ namespace osu.Game.Overlays { careChannels.Add(channel); channelTabs.AddItem(channel); + + if (channel.Type == ChannelType.Public && !channel.Joined) + { + var req = new JoinChannelRequest(channel, api.LocalUser); + req.Success += () => addChannel(channel); + req.Failure += ex => removeChannel(channel); + api.Queue(req); + return; + } } // let's fetch a small number of messages to bring us up-to-date with the backlog. @@ -415,47 +424,53 @@ namespace osu.Game.Overlays loadedChannels.Remove(loadedChannels.Find(c => c.Channel == channel)); channelTabs.RemoveItem(channel); + api.Queue(new LeaveChannelRequest(channel, api.LocalUser)); channel.Joined.Value = false; } private void fetchInitialMessages(Channel channel) { - var req = new GetMessagesRequest(new List { channel }, null); - - req.Success += delegate (List messages) + var req = new GetMessagesRequest(channel); + req.Success += messages => { - loading.Hide(); channel.AddNewMessages(messages.ToArray()); - Debug.Write("success!"); - }; - req.Failure += delegate - { - Debug.Write("failure!"); + if (channel == currentChannel) + loading.Hide(); }; api.Queue(req); } - private void fetchNewMessages() + private void fetchUpdates() { if (fetchReq != null) return; - fetchReq = new GetMessagesRequest(careChannels, lastMessageId); + fetchReq = new GetUpdatesRequest(lastMessageId); - fetchReq.Success += delegate (List messages) + fetchReq.Success += updates => { - foreach (var group in messages.Where(m => m.TargetType == TargetType.Channel).GroupBy(m => m.TargetId)) - careChannels.Find(c => c.Id == group.Key)?.AddNewMessages(group.ToArray()); + if (updates?.Presence != null) + { + foreach (var channel in updates.Presence) + { + if (careChannels.Find(c => c.Id == channel.Id) == null) + { + channel.Joined.Value = true; + addChannel(channel); + } + } - lastMessageId = messages.LastOrDefault()?.Id ?? lastMessageId; + foreach (var group in updates.Messages.GroupBy(m => m.ChannelId)) + careChannels.Find(c => c.Id == group.Key)?.AddNewMessages(group.ToArray()); + + lastMessageId = updates.Messages.LastOrDefault()?.Id ?? lastMessageId; + } - Debug.Write("success!"); fetchReq = null; }; fetchReq.Failure += delegate { - Debug.Write("failure!"); fetchReq = null; }; @@ -517,8 +532,7 @@ namespace osu.Game.Overlays { Sender = api.LocalUser.Value, Timestamp = DateTimeOffset.Now, - TargetType = TargetType.Channel, //TODO: read this from channel - TargetId = target.Id, + ChannelId = target.Id, IsAction = isAction, Content = postText }; diff --git a/osu.Game/Overlays/Dialog/PopupDialog.cs b/osu.Game/Overlays/Dialog/PopupDialog.cs index 3f79fa98e5..ccbb7cc496 100644 --- a/osu.Game/Overlays/Dialog/PopupDialog.cs +++ b/osu.Game/Overlays/Dialog/PopupDialog.cs @@ -26,7 +26,7 @@ namespace osu.Game.Overlays.Dialog public static readonly float ENTER_DURATION = 500; public static readonly float EXIT_DURATION = 200; - protected override bool BlockPassThroughMouse => false; + protected override bool BlockPositionalInput => false; private readonly Vector2 ringSize = new Vector2(100f); private readonly Vector2 ringMinifiedSize = new Vector2(20f); diff --git a/osu.Game/Overlays/DialogOverlay.cs b/osu.Game/Overlays/DialogOverlay.cs index c40f517023..dae502dbd9 100644 --- a/osu.Game/Overlays/DialogOverlay.cs +++ b/osu.Game/Overlays/DialogOverlay.cs @@ -43,7 +43,7 @@ namespace osu.Game.Overlays protected override bool PlaySamplesOnStateChange => false; - protected override bool BlockPassThroughKeyboard => true; + protected override bool BlockNonPositionalInput => true; private void onDialogOnStateChanged(VisibilityContainer dialog, Visibility v) { diff --git a/osu.Game/Overlays/Direct/FilterControl.cs b/osu.Game/Overlays/Direct/FilterControl.cs index df98cc3c32..c4825f72fe 100644 --- a/osu.Game/Overlays/Direct/FilterControl.cs +++ b/osu.Game/Overlays/Direct/FilterControl.cs @@ -73,8 +73,8 @@ namespace osu.Game.Overlays.Direct iconContainer.FadeTo(Ruleset.ID == obj?.ID ? 1f : 0.5f, 100); } - public override bool HandleKeyboardInput => !bindable.Disabled && base.HandleKeyboardInput; - public override bool HandleMouseInput => !bindable.Disabled && base.HandleMouseInput; + public override bool HandleNonPositionalInput => !bindable.Disabled && base.HandleNonPositionalInput; + public override bool HandlePositionalInput => !bindable.Disabled && base.HandlePositionalInput; public RulesetToggleButton(Bindable bindable, RulesetInfo ruleset) { diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index e83dedaf35..55d5d797e7 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -40,7 +40,7 @@ namespace osu.Game.Overlays.Mods protected readonly OsuSpriteText MultiplierLabel, UnrankedLabel; private readonly FillFlowContainer footerContainer; - protected override bool BlockPassThroughKeyboard => false; + protected override bool BlockNonPositionalInput => false; protected readonly FillFlowContainer ModSectionsContainer; diff --git a/osu.Game/Overlays/OnScreenDisplay.cs b/osu.Game/Overlays/OnScreenDisplay.cs index 041ceab365..e40004aa01 100644 --- a/osu.Game/Overlays/OnScreenDisplay.cs +++ b/osu.Game/Overlays/OnScreenDisplay.cs @@ -25,8 +25,8 @@ namespace osu.Game.Overlays { private readonly Container box; - public override bool HandleKeyboardInput => false; - public override bool HandleMouseInput => false; + public override bool HandleNonPositionalInput => false; + public override bool HandlePositionalInput => false; private readonly SpriteText textLine1; private readonly SpriteText textLine2; diff --git a/osu.Game/Overlays/Toolbar/Toolbar.cs b/osu.Game/Overlays/Toolbar/Toolbar.cs index cdc3bc2b51..3f44cb403a 100644 --- a/osu.Game/Overlays/Toolbar/Toolbar.cs +++ b/osu.Game/Overlays/Toolbar/Toolbar.cs @@ -24,7 +24,7 @@ namespace osu.Game.Overlays.Toolbar private readonly ToolbarUserArea userArea; - protected override bool BlockPassThroughMouse => false; + protected override bool BlockPositionalInput => false; private const double transition_time = 500; diff --git a/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs b/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs index f2744ae83f..4b6fb366bb 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs @@ -103,8 +103,8 @@ namespace osu.Game.Overlays.Toolbar return false; } - public override bool HandleKeyboardInput => !ruleset.Disabled && base.HandleKeyboardInput; - public override bool HandleMouseInput => !ruleset.Disabled && base.HandleMouseInput; + public override bool HandleNonPositionalInput => !ruleset.Disabled && base.HandleNonPositionalInput; + public override bool HandlePositionalInput => !ruleset.Disabled && base.HandlePositionalInput; private void disabledChanged(bool isDisabled) => this.FadeColour(isDisabled ? Color4.Gray : Color4.White, 300); diff --git a/osu.Game/Overlays/VolumeOverlay.cs b/osu.Game/Overlays/VolumeOverlay.cs index 4dcdd23768..bf1c81393d 100644 --- a/osu.Game/Overlays/VolumeOverlay.cs +++ b/osu.Game/Overlays/VolumeOverlay.cs @@ -28,7 +28,7 @@ namespace osu.Game.Overlays private VolumeMeter volumeMeterMusic; private MuteButton muteButton; - protected override bool BlockPassThroughMouse => false; + protected override bool BlockPositionalInput => false; private readonly BindableDouble muteAdjustment = new BindableDouble(); diff --git a/osu.Game/Overlays/WaveOverlayContainer.cs b/osu.Game/Overlays/WaveOverlayContainer.cs index 97f52d88f7..c5a4953c5e 100644 --- a/osu.Game/Overlays/WaveOverlayContainer.cs +++ b/osu.Game/Overlays/WaveOverlayContainer.cs @@ -11,7 +11,7 @@ namespace osu.Game.Overlays { protected readonly WaveContainer Waves; - protected override bool BlockPassThroughKeyboard => true; + protected override bool BlockNonPositionalInput => true; protected override Container Content => Waves; protected WaveOverlayContainer() diff --git a/osu.Game/Rulesets/Edit/HitObjectMask.cs b/osu.Game/Rulesets/Edit/HitObjectMask.cs index ada026b32f..0ba67e1dca 100644 --- a/osu.Game/Rulesets/Edit/HitObjectMask.cs +++ b/osu.Game/Rulesets/Edit/HitObjectMask.cs @@ -45,7 +45,7 @@ namespace osu.Game.Rulesets.Edit public readonly DrawableHitObject HitObject; protected override bool ShouldBeAlive => HitObject.IsAlive && HitObject.IsPresent || State == SelectionState.Selected; - public override bool HandleMouseInput => ShouldBeAlive; + public override bool HandlePositionalInput => ShouldBeAlive; public override bool RemoveWhenNotAlive => false; public HitObjectMask(DrawableHitObject hitObject) diff --git a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs index 65b2ef75c4..c2a52e5794 100644 --- a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs +++ b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs @@ -65,13 +65,15 @@ namespace osu.Game.Rulesets.Judgements this.FadeInFromZero(100, Easing.OutQuint); + var origScale = Scale; + switch (Result.Type) { case HitResult.None: break; case HitResult.Miss: - this.ScaleTo(1.6f); - this.ScaleTo(1, 100, Easing.In); + this.ScaleTo(origScale * 1.6f); + this.ScaleTo(origScale, 100, Easing.In); this.MoveToOffset(new Vector2(0, 100), 800, Easing.InQuint); this.RotateTo(40, 800, Easing.InQuint); @@ -79,8 +81,8 @@ namespace osu.Game.Rulesets.Judgements this.Delay(600).FadeOut(200); break; default: - this.ScaleTo(0.9f); - this.ScaleTo(1, 500, Easing.OutElastic); + this.ScaleTo(origScale * 0.9f); + this.ScaleTo(origScale, 500, Easing.OutElastic); this.Delay(100).FadeOut(400); break; diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index a274d9b12f..8489f0b19e 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -78,8 +78,8 @@ namespace osu.Game.Rulesets.Objects.Drawables private bool judgementOccurred; public bool Interactive = true; - public override bool HandleKeyboardInput => Interactive; - public override bool HandleMouseInput => Interactive; + public override bool HandleNonPositionalInput => Interactive; + public override bool HandlePositionalInput => Interactive; public override bool RemoveWhenNotAlive => false; public override bool RemoveCompletedTransforms => false; diff --git a/osu.Game/Rulesets/Scoring/Score.cs b/osu.Game/Rulesets/Scoring/Score.cs index dfe7ff0195..02f528791a 100644 --- a/osu.Game/Rulesets/Scoring/Score.cs +++ b/osu.Game/Rulesets/Scoring/Score.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using Newtonsoft.Json; using osu.Game.Beatmaps; using osu.Game.Rulesets.Mods; using osu.Game.Users; @@ -32,6 +33,7 @@ namespace osu.Game.Rulesets.Scoring public User User; + [JsonIgnore] public Replay Replay; public BeatmapInfo Beatmap; diff --git a/osu.Game/Rulesets/Scoring/ScoreStore.cs b/osu.Game/Rulesets/Scoring/ScoreStore.cs index 69d25fcb67..091cb29a71 100644 --- a/osu.Game/Rulesets/Scoring/ScoreStore.cs +++ b/osu.Game/Rulesets/Scoring/ScoreStore.cs @@ -3,6 +3,7 @@ using System; using System.IO; +using osu.Framework.Logging; using osu.Framework.Platform; using osu.Game.Beatmaps; using osu.Game.Database; @@ -13,8 +14,6 @@ namespace osu.Game.Rulesets.Scoring { public class ScoreStore : DatabaseBackedStore, ICanAcceptFiles { - private readonly Storage storage; - private readonly BeatmapManager beatmaps; private readonly RulesetStore rulesets; @@ -25,9 +24,8 @@ namespace osu.Game.Rulesets.Scoring // ReSharper disable once NotAccessedField.Local (we should keep a reference to this so it is not finalised) private ScoreIPCChannel ipc; - public ScoreStore(Storage storage, DatabaseContextFactory factory, IIpcHost importHost = null, BeatmapManager beatmaps = null, RulesetStore rulesets = null) : base(factory) + public ScoreStore(DatabaseContextFactory factory, IIpcHost importHost = null, BeatmapManager beatmaps = null, RulesetStore rulesets = null) : base(factory) { - this.storage = storage; this.beatmaps = beatmaps; this.rulesets = rulesets; @@ -49,8 +47,14 @@ namespace osu.Game.Rulesets.Scoring public Score ReadReplayFile(string replayFilename) { - using (Stream s = storage.GetStream(Path.Combine(replay_folder, replayFilename))) - return new DatabasedLegacyScoreParser(rulesets, beatmaps).Parse(s); + if (File.Exists(replayFilename)) + { + using (var stream = File.OpenRead(replayFilename)) + return new DatabasedLegacyScoreParser(rulesets, beatmaps).Parse(stream); + } + + Logger.Log($"Replay file {replayFilename} cannot be found", LoggingTarget.Information, LogLevel.Error); + return null; } } } diff --git a/osu.Game/Screens/Edit/Screens/Compose/BeatDivisorControl.cs b/osu.Game/Screens/Edit/Screens/Compose/BeatDivisorControl.cs index 63df143ca8..833c4464c3 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/BeatDivisorControl.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/BeatDivisorControl.cs @@ -231,7 +231,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose { } - public override bool HandleKeyboardInput => IsHovered && !CurrentNumber.Disabled; + public override bool HandleNonPositionalInput => IsHovered && !CurrentNumber.Disabled; protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) { diff --git a/osu.Game/Screens/Menu/Button.cs b/osu.Game/Screens/Menu/Button.cs index e53905a102..38d74a3a4b 100644 --- a/osu.Game/Screens/Menu/Button.cs +++ b/osu.Game/Screens/Menu/Button.cs @@ -47,7 +47,7 @@ namespace osu.Game.Screens.Menu private SampleChannel sampleClick; private SampleChannel sampleHover; - public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => box.ReceiveMouseInputAt(screenSpacePos); + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => box.ReceivePositionalInputAt(screenSpacePos); public Button(string text, string sampleName, FontAwesome symbol, Color4 colour, Action clickAction = null, float extraWidth = 0, Key triggerKey = Key.Unknown) { @@ -229,8 +229,8 @@ namespace osu.Game.Screens.Menu boxHoverLayer.FadeOut(800, Easing.OutExpo); } - public override bool HandleKeyboardInput => state == ButtonState.Expanded; - public override bool HandleMouseInput => state != ButtonState.Exploded && box.Scale.X >= 0.8f; + public override bool HandleNonPositionalInput => state == ButtonState.Expanded; + public override bool HandlePositionalInput => state != ButtonState.Exploded && box.Scale.X >= 0.8f; protected override void Update() { diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index dba0a3ac50..5c17317fc1 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -160,8 +160,8 @@ namespace osu.Game.Screens.Menu private ButtonSystemState state = ButtonSystemState.Initial; - public override bool HandleKeyboardInput => state != ButtonSystemState.Exit; - public override bool HandleMouseInput => state != ButtonSystemState.Exit; + public override bool HandleNonPositionalInput => state != ButtonSystemState.Exit; + public override bool HandlePositionalInput => state != ButtonSystemState.Exit; public ButtonSystemState State { diff --git a/osu.Game/Screens/Menu/LogoVisualisation.cs b/osu.Game/Screens/Menu/LogoVisualisation.cs index a3cb2f13d0..5d76206905 100644 --- a/osu.Game/Screens/Menu/LogoVisualisation.cs +++ b/osu.Game/Screens/Menu/LogoVisualisation.cs @@ -64,8 +64,8 @@ namespace osu.Game.Screens.Menu private readonly float[] frequencyAmplitudes = new float[256]; - public override bool HandleKeyboardInput => false; - public override bool HandleMouseInput => false; + public override bool HandleNonPositionalInput => false; + public override bool HandlePositionalInput => false; private Shader shader; private readonly Texture texture; diff --git a/osu.Game/Screens/Menu/MenuSideFlashes.cs b/osu.Game/Screens/Menu/MenuSideFlashes.cs index 7d46aad089..a9e3310fbe 100644 --- a/osu.Game/Screens/Menu/MenuSideFlashes.cs +++ b/osu.Game/Screens/Menu/MenuSideFlashes.cs @@ -19,8 +19,8 @@ namespace osu.Game.Screens.Menu { public class MenuSideFlashes : BeatSyncedContainer { - public override bool HandleKeyboardInput => false; - public override bool HandleMouseInput => false; + public override bool HandleNonPositionalInput => false; + public override bool HandlePositionalInput => false; private readonly IBindable beatmap = new Bindable(); diff --git a/osu.Game/Screens/Menu/OsuLogo.cs b/osu.Game/Screens/Menu/OsuLogo.cs index 5ad6427fd8..52354241d2 100644 --- a/osu.Game/Screens/Menu/OsuLogo.cs +++ b/osu.Game/Screens/Menu/OsuLogo.cs @@ -68,7 +68,7 @@ namespace osu.Game.Screens.Menu public bool BeatMatching = true; - public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => logoContainer.ReceiveMouseInputAt(screenSpacePos); + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => logoContainer.ReceivePositionalInputAt(screenSpacePos); public bool Ripple { @@ -342,7 +342,7 @@ namespace osu.Game.Screens.Menu } } - public override bool HandleMouseInput => base.HandleMouseInput && Action != null && Alpha > 0.2f; + public override bool HandlePositionalInput => base.HandlePositionalInput && Action != null && Alpha > 0.2f; protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) { diff --git a/osu.Game/Screens/Play/GameplayMenuOverlay.cs b/osu.Game/Screens/Play/GameplayMenuOverlay.cs index f50b3e9661..a978bd916e 100644 --- a/osu.Game/Screens/Play/GameplayMenuOverlay.cs +++ b/osu.Game/Screens/Play/GameplayMenuOverlay.cs @@ -28,9 +28,9 @@ namespace osu.Game.Screens.Play private const int button_height = 70; private const float background_alpha = 0.75f; - protected override bool BlockPassThroughKeyboard => true; + protected override bool BlockNonPositionalInput => true; - public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => true; + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; public Action OnRetry; public Action OnQuit; diff --git a/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs b/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs index e5e2ed7ee0..7534c7a22e 100644 --- a/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs +++ b/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs @@ -51,7 +51,7 @@ namespace osu.Game.Screens.Play.HUD protected override void PopOut() => this.FadeOut(fade_duration); //We want to handle keyboard inputs all the time in order to trigger ToggleVisibility() when not visible - public override bool HandleKeyboardInput => true; + public override bool HandleNonPositionalInput => true; protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) { diff --git a/osu.Game/Screens/Play/HUD/QuitButton.cs b/osu.Game/Screens/Play/HUD/QuitButton.cs index 2a4b1f408d..6b120421ad 100644 --- a/osu.Game/Screens/Play/HUD/QuitButton.cs +++ b/osu.Game/Screens/Play/HUD/QuitButton.cs @@ -20,7 +20,7 @@ namespace osu.Game.Screens.Play.HUD { public class QuitButton : FillFlowContainer { - public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => true; + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; private readonly Button button; diff --git a/osu.Game/Screens/Play/KeyCounterCollection.cs b/osu.Game/Screens/Play/KeyCounterCollection.cs index 76c102c840..925f96f33b 100644 --- a/osu.Game/Screens/Play/KeyCounterCollection.cs +++ b/osu.Game/Screens/Play/KeyCounterCollection.cs @@ -118,8 +118,8 @@ namespace osu.Game.Screens.Play private void updateVisibility() => this.FadeTo(Visible.Value || configVisibility.Value ? 1 : 0, duration); - public override bool HandleKeyboardInput => receptor == null; - public override bool HandleMouseInput => receptor == null; + public override bool HandleNonPositionalInput => receptor == null; + public override bool HandlePositionalInput => receptor == null; public IFrameBasedClock AudioClock { get; set; } @@ -149,7 +149,7 @@ namespace osu.Game.Screens.Play Target = target; } - public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => true; + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; protected override bool Handle(UIEvent e) { diff --git a/osu.Game/Screens/Play/KeyCounterMouse.cs b/osu.Game/Screens/Play/KeyCounterMouse.cs index 20cc53caee..37c2b4f072 100644 --- a/osu.Game/Screens/Play/KeyCounterMouse.cs +++ b/osu.Game/Screens/Play/KeyCounterMouse.cs @@ -17,7 +17,7 @@ namespace osu.Game.Screens.Play Button = button; } - public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => true; + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; private static string getStringRepresentation(MouseButton button) { diff --git a/osu.Game/Screens/Play/SkipOverlay.cs b/osu.Game/Screens/Play/SkipOverlay.cs index 046a00d79b..d736a51a99 100644 --- a/osu.Game/Screens/Play/SkipOverlay.cs +++ b/osu.Game/Screens/Play/SkipOverlay.cs @@ -37,8 +37,8 @@ namespace osu.Game.Screens.Play private FadeContainer fadeContainer; private double displayTime; - public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => true; - protected override bool BlockPassThroughMouse => false; + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; + protected override bool BlockPositionalInput => false; public SkipOverlay(double startTime) { diff --git a/osu.Game/Screens/Play/SongProgress.cs b/osu.Game/Screens/Play/SongProgress.cs index 2ca471c5c1..2e2c77c1c8 100644 --- a/osu.Game/Screens/Play/SongProgress.cs +++ b/osu.Game/Screens/Play/SongProgress.cs @@ -31,8 +31,8 @@ namespace osu.Game.Screens.Play public Action OnSeek; - public override bool HandleKeyboardInput => AllowSeeking; - public override bool HandleMouseInput => AllowSeeking; + public override bool HandleNonPositionalInput => AllowSeeking; + public override bool HandlePositionalInput => AllowSeeking; private IClock audioClock; public IClock AudioClock { set { audioClock = info.AudioClock = value; } } diff --git a/osu.Game/Screens/Play/SquareGraph.cs b/osu.Game/Screens/Play/SquareGraph.cs index 8ffd04b35c..6b4918af75 100644 --- a/osu.Game/Screens/Play/SquareGraph.cs +++ b/osu.Game/Screens/Play/SquareGraph.cs @@ -21,8 +21,8 @@ namespace osu.Game.Screens.Play public int ColumnCount => columns.Length; - public override bool HandleKeyboardInput => false; - public override bool HandleMouseInput => false; + public override bool HandleNonPositionalInput => false; + public override bool HandlePositionalInput => false; private int progress; public int Progress diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index b6cbaf45e9..5771cb1f70 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -52,8 +52,8 @@ namespace osu.Game.Screens.Select /// public Action SelectionChanged; - public override bool HandleKeyboardInput => AllowSelection; - public override bool HandleMouseInput => AllowSelection; + public override bool HandleNonPositionalInput => AllowSelection; + public override bool HandlePositionalInput => AllowSelection; /// /// Used to avoid firing null selections before the initial beatmaps have been loaded via . diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index 4129a9596f..81455833e9 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -59,7 +59,7 @@ namespace osu.Game.Screens.Select ruleset.ValueChanged += _ => updateDisplay(); } - protected override bool BlockPassThroughMouse => false; + protected override bool BlockPositionalInput => false; protected override void PopIn() { @@ -89,6 +89,8 @@ namespace osu.Game.Screens.Select } } + public override bool IsPresent => base.IsPresent || Info == null; // Visibility is updated in the LoadComponentAsync callback + private BufferedWedgeInfo loadingInfo; private void updateDisplay() @@ -154,7 +156,7 @@ namespace osu.Game.Screens.Select RelativeSizeAxes = Axes.Both; titleBinding = localisation.GetLocalisedString(new LocalisedString((metadata.TitleUnicode, metadata.Title))); - artistBinding = localisation.GetLocalisedString(new LocalisedString((metadata.ArtistUnicode, metadata.Artist))); + artistBinding = localisation.GetLocalisedString(new LocalisedString((metadata.ArtistUnicode, metadata.Artist))); Children = new Drawable[] { diff --git a/osu.Game/Screens/Select/FilterControl.cs b/osu.Game/Screens/Select/FilterControl.cs index 9ba8b085f3..32b6620c84 100644 --- a/osu.Game/Screens/Select/FilterControl.cs +++ b/osu.Game/Screens/Select/FilterControl.cs @@ -72,8 +72,8 @@ namespace osu.Game.Screens.Select private readonly SearchTextBox searchTextBox; - public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => - base.ReceiveMouseInputAt(screenSpacePos) || groupTabs.ReceiveMouseInputAt(screenSpacePos) || sortTabs.ReceiveMouseInputAt(screenSpacePos); + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => + base.ReceivePositionalInputAt(screenSpacePos) || groupTabs.ReceivePositionalInputAt(screenSpacePos) || sortTabs.ReceivePositionalInputAt(screenSpacePos); public FilterControl() { diff --git a/osu.Game/Screens/Select/FooterButton.cs b/osu.Game/Screens/Select/FooterButton.cs index 1b0e3a1620..8fb95d394e 100644 --- a/osu.Game/Screens/Select/FooterButton.cs +++ b/osu.Game/Screens/Select/FooterButton.cs @@ -56,7 +56,7 @@ namespace osu.Game.Screens.Select private readonly Box box; private readonly Box light; - public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => box.ReceiveMouseInputAt(screenSpacePos); + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => box.ReceivePositionalInputAt(screenSpacePos); public FooterButton() { diff --git a/osu.Game/Screens/Select/Leaderboards/Placeholder.cs b/osu.Game/Screens/Select/Leaderboards/Placeholder.cs index 307986a299..105f9e2064 100644 --- a/osu.Game/Screens/Select/Leaderboards/Placeholder.cs +++ b/osu.Game/Screens/Select/Leaderboards/Placeholder.cs @@ -11,7 +11,7 @@ namespace osu.Game.Screens.Select.Leaderboards { protected const float TEXT_SIZE = 22; - public override bool HandleMouseInput => true; + public override bool HandlePositionalInput => true; protected Placeholder() : base(cp => cp.TextSize = TEXT_SIZE) diff --git a/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs b/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs index d4cd882433..f9127ace19 100644 --- a/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs +++ b/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs @@ -85,7 +85,7 @@ namespace osu.Game.Screens.Select.Options return false; } - public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => box.ReceiveMouseInputAt(screenSpacePos); + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => box.ReceivePositionalInputAt(screenSpacePos); public BeatmapOptionsButton() { diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index efdf55e477..b4dcbcce41 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -536,7 +536,7 @@ namespace osu.Game.Screens.Select private void delete(BeatmapSetInfo beatmap) { - if (beatmap == null) return; + if (beatmap == null || beatmap.ID <= 0) return; dialogOverlay?.Push(new BeatmapDeleteDialog(beatmap)); } diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs index 37c198f370..02a4b46f1c 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs @@ -18,8 +18,8 @@ namespace osu.Game.Storyboards.Drawables protected override Container Content => content; protected override Vector2 DrawScale => new Vector2(Parent.DrawHeight / 480); - public override bool HandleKeyboardInput => false; - public override bool HandleMouseInput => false; + public override bool HandleNonPositionalInput => false; + public override bool HandlePositionalInput => false; private bool passing = true; public bool Passing diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 5ce04b813b..8fb42c0cea 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -18,7 +18,7 @@ - + diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings index 1f1b6a79b1..404b19deda 100644 --- a/osu.sln.DotSettings +++ b/osu.sln.DotSettings @@ -218,6 +218,7 @@ GMT QAT BNG + UI HINT <?xml version="1.0" encoding="utf-16"?> <Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns">