From eab2776755694526f8f99c6dc1aec4718216d4b7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 21 Nov 2018 17:14:08 +0900 Subject: [PATCH 01/12] Fix a crash on leaving the selected channel --- osu.Game/Overlays/ChatOverlay.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index e45373c36f..6a5b72c0f3 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -209,7 +209,6 @@ namespace osu.Game.Overlays { textbox.Current.Disabled = true; currentChannelContainer.Clear(false); - channelTabControl.Current.Value = null; return; } From 4cde66240dcba75444ac1693aef3a117498cb122 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 21 Nov 2018 17:14:48 +0900 Subject: [PATCH 02/12] Fix default channels not being joined --- osu.Game/Online/Chat/ChannelManager.cs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 9014fce18d..9ee6cfa483 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . +// Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; @@ -362,12 +362,6 @@ namespace osu.Game.Online.Chat } } - if (!channelsInitialised) - { - channelsInitialised = true; - // we want this to run after the first presence so we can see if the user is in any channels already. - initializeChannels(); - } //todo: handle left channels @@ -379,6 +373,13 @@ namespace osu.Game.Online.Chat lastMessageId = updates.Messages.LastOrDefault()?.Id ?? lastMessageId; } + if (!channelsInitialised) + { + channelsInitialised = true; + // we want this to run after the first presence so we can see if the user is in any channels already. + initializeChannels(); + } + fetchUpdates(); }; From 88f82eb722738f323314afa5e51467deecd9b01a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 21 Nov 2018 17:15:10 +0900 Subject: [PATCH 03/12] Fix instabilities in channel join logic --- osu.Game/Online/Chat/ChannelManager.cs | 89 +++++++++++++++++--------- 1 file changed, 57 insertions(+), 32 deletions(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 9ee6cfa483..621cdb5737 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . +// Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; @@ -223,13 +223,11 @@ namespace osu.Game.Online.Chat { foreach (var channel in channels) { - // add as available if not already - if (AvailableChannels.All(c => c.Id != channel.Id)) - AvailableChannels.Add(channel); + var ch = getChannel(channel, addToAvailable: true); // join any channels classified as "defaults" if (joinDefaults && defaultChannels.Any(c => c.Equals(channel.Name, StringComparison.OrdinalIgnoreCase))) - JoinChannel(channel); + JoinChannel(ch); } }; req.Failure += error => @@ -262,38 +260,68 @@ namespace osu.Game.Online.Chat api.Queue(fetchInitialMsgReq); } - public void JoinChannel(Channel channel) + /// + /// Find an existing channel instance for the provided channel. Lookup is performed basd on ID. + /// The provided channel may be used if an existing instance is not found. + /// + /// A candidate channel to be used for lookup or permanently on lookup failure. + /// Whether the channel should be added to if not already. + /// Whether the channel should be added to if not already. + /// The found channel. + private Channel getChannel(Channel lookup, bool addToAvailable = false, bool addToJoined = false) { - if (channel == null) return; + Channel found = null; - // ReSharper disable once AccessToModifiedClosure - var existing = JoinedChannels.FirstOrDefault(c => c.Id == channel.Id); + var available = AvailableChannels.FirstOrDefault(c => c.Id == lookup.Id); + if (available != null) + found = available; - if (existing != null) + var joined = JoinedChannels.FirstOrDefault(c => c.Id == lookup.Id); + if (found == null && joined != null) + found = joined; + + if (found == null) { - // if we already have this channel loaded, we don't want to make a second one. - channel = existing; - } - else - { - var foundSelf = channel.Users.FirstOrDefault(u => u.Id == api.LocalUser.Value.Id); + found = lookup; + + // if we're using a channel object from the server, we want to remove ourselves from the users list. + // this is because we check the first user in the channel to display a name/icon on tabs for now. + var foundSelf = found.Users.FirstOrDefault(u => u.Id == api.LocalUser.Value.Id); if (foundSelf != null) - channel.Users.Remove(foundSelf); + found.Users.Remove(foundSelf); + } - JoinedChannels.Add(channel); + if (joined == null && addToJoined) JoinedChannels.Add(found); + if (available == null && addToAvailable) AvailableChannels.Add(found); - if (channel.Type == ChannelType.Public && !channel.Joined) + return found; + } + + /// + /// Joins a channel if it has not already been joined. + /// + /// The channel to join. + /// Whether the channel has already been joined server-side. Will skip a join request. + /// The joined channel. Note that this may not match the parameter channel as it is a backed object. + public Channel JoinChannel(Channel channel, bool alreadyJoined = false) + { + if (channel == null) return null; + + channel = getChannel(channel, addToJoined: true); + + // ensure we are joined to the channel + if (!channel.Joined.Value) + { + if (!alreadyJoined && channel.Type == ChannelType.Public) { var req = new JoinChannelRequest(channel, api.LocalUser); - req.Success += () => - { - channel.Joined.Value = true; - JoinChannel(channel); - }; + req.Success += () => JoinChannel(channel, true); req.Failure += ex => LeaveChannel(channel); api.Queue(req); - return; + return channel; } + + channel.Joined.Value = true; } if (CurrentChannel.Value == null) @@ -304,6 +332,8 @@ namespace osu.Game.Online.Chat // let's fetch a small number of messages to bring us up-to-date with the backlog. fetchInitalMessages(channel); } + + return channel; } public void LeaveChannel(Channel channel) @@ -353,13 +383,8 @@ namespace osu.Game.Online.Chat { foreach (var channel in updates.Presence) { - if (!channel.Joined.Value) - { - // we received this from the server so should mark the channel already joined. - channel.Joined.Value = true; - - JoinChannel(channel); - } + // we received this from the server so should mark the channel already joined. + JoinChannel(channel, true); } From d67792168029a6d9f2ea491d102d45aa3ce46c0d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 21 Nov 2018 18:53:50 +0900 Subject: [PATCH 04/12] Remove excess newline --- osu.Game/Online/Chat/ChannelManager.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 621cdb5737..3ce162ee30 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -387,7 +387,6 @@ namespace osu.Game.Online.Chat JoinChannel(channel, true); } - //todo: handle left channels handleChannelMessages(updates.Messages); From b31efb7bb992256134d581b30a6b603ffbbe77fc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 21 Nov 2018 20:31:47 +0900 Subject: [PATCH 05/12] Fix PM channel type --- osu.Game/Online/Chat/ChannelManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 3ce162ee30..d9098956ec 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -77,7 +77,7 @@ namespace osu.Game.Online.Chat throw new ArgumentNullException(nameof(user)); CurrentChannel.Value = JoinedChannels.FirstOrDefault(c => c.Type == ChannelType.PM && c.Users.Count == 1 && c.Users.Any(u => u.Id == user.Id)) - ?? new Channel { Name = user.Username, Users = { user } }; + ?? new Channel { Name = user.Username, Users = { user }, Type = ChannelType.PM }; } private void currentChannelChanged(Channel channel) => JoinChannel(channel); From 2126cf0d9a6f68acf52002a018396fba9cf3ec75 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 21 Nov 2018 20:44:41 +0900 Subject: [PATCH 06/12] Fix join process for PMs being incorrect --- osu.Game/Online/Chat/ChannelManager.cs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index d9098956ec..a9610e72b1 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -312,16 +312,20 @@ namespace osu.Game.Online.Chat // ensure we are joined to the channel if (!channel.Joined.Value) { - if (!alreadyJoined && channel.Type == ChannelType.Public) + if (alreadyJoined) + channel.Joined.Value = true; + else { - var req = new JoinChannelRequest(channel, api.LocalUser); - req.Success += () => JoinChannel(channel, true); - req.Failure += ex => LeaveChannel(channel); - api.Queue(req); - return channel; + switch (channel.Type) + { + case ChannelType.Public: + var req = new JoinChannelRequest(channel, api.LocalUser); + req.Success += () => JoinChannel(channel, true); + req.Failure += ex => LeaveChannel(channel); + api.Queue(req); + return channel; + } } - - channel.Joined.Value = true; } if (CurrentChannel.Value == null) From a144e975687d43bde1d36fe330f614758793104d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 22 Nov 2018 18:27:22 +0900 Subject: [PATCH 07/12] Fix crash on creating two new PM channels --- osu.Game/Online/Chat/ChannelManager.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index a9610e72b1..73ac7c9df4 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -272,11 +272,13 @@ namespace osu.Game.Online.Chat { Channel found = null; - var available = AvailableChannels.FirstOrDefault(c => c.Id == lookup.Id); + bool lookupCondition(Channel ch) => lookup.Id > 0 ? ch.Id == lookup.Id : lookup.Name == ch.Name; + + var available = AvailableChannels.FirstOrDefault(lookupCondition); if (available != null) found = available; - var joined = JoinedChannels.FirstOrDefault(c => c.Id == lookup.Id); + var joined = JoinedChannels.FirstOrDefault(lookupCondition); if (found == null && joined != null) found = joined; From 6cd69b794d170c8a4c51e8be091166824e1ef5c0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 22 Nov 2018 19:08:46 +0900 Subject: [PATCH 08/12] Fix leaderboard accessing drawables in a possibly invalid state --- osu.Game/Screens/Select/Leaderboards/Leaderboard.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs index 4a677001a0..0748f68dca 100644 --- a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs @@ -310,9 +310,9 @@ namespace osu.Game.Screens.Select.Leaderboards currentPlaceholder = placeholder; } - protected override void Update() + protected override void UpdateAfterChildren() { - base.Update(); + base.UpdateAfterChildren(); var fadeStart = scrollContainer.Current + scrollContainer.DrawHeight; From a48c26d9993696fda11d624d5508dd8f06955530 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 22 Nov 2018 19:40:44 +0900 Subject: [PATCH 09/12] Fix precision scroll events being handled incorrectly by editor --- osu.Game/Screens/Edit/Editor.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 0be15de7f4..b355d1f349 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using osuTK.Graphics; using osu.Framework.Screens; using osu.Game.Screens.Backgrounds; @@ -181,12 +182,20 @@ namespace osu.Game.Screens.Edit LoadComponentAsync(currentScreen, screenContainer.Add); } + private double scrollAccumulation; + protected override bool OnScroll(ScrollEvent e) { - if (e.ScrollDelta.X + e.ScrollDelta.Y > 0) + scrollAccumulation += e.ScrollDelta.X + e.ScrollDelta.Y * (e.IsPrecise ? 0.1 : 1); + if (Math.Abs(scrollAccumulation) < 1) + return true; + + if (scrollAccumulation > 0) clock.SeekBackward(!clock.IsRunning); else clock.SeekForward(!clock.IsRunning); + + scrollAccumulation = 0; return true; } From 10047e6815c8a72cab9c76498dc96e8f8635296b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 22 Nov 2018 20:13:40 +0900 Subject: [PATCH 10/12] Adjust tick-based wheel control to be more correct --- osu.Game/Overlays/Volume/VolumeMeter.cs | 16 ++++++++++------ osu.Game/Screens/Edit/Editor.cs | 18 +++++++++++------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/osu.Game/Overlays/Volume/VolumeMeter.cs b/osu.Game/Overlays/Volume/VolumeMeter.cs index c249651f98..c67ed5b845 100644 --- a/osu.Game/Overlays/Volume/VolumeMeter.cs +++ b/osu.Game/Overlays/Volume/VolumeMeter.cs @@ -228,15 +228,19 @@ namespace osu.Game.Overlays.Volume public void Decrease(double amount = 1, bool isPrecise = false) => adjust(-amount, isPrecise); // because volume precision is set to 0.01, this local is required to keep track of more precise adjustments and only apply when possible. - private double adjustAccumulator; + private double scrollAccumulation; private void adjust(double delta, bool isPrecise) { - adjustAccumulator += delta * adjust_step * (isPrecise ? 0.1 : 1); - if (Math.Abs(adjustAccumulator) < Bindable.Precision) - return; - Volume += adjustAccumulator; - adjustAccumulator = 0; + scrollAccumulation += delta * adjust_step * (isPrecise ? 0.1 : 1); + + var precision = Bindable.Precision; + + while (Math.Abs(scrollAccumulation) > precision) + { + Volume += Math.Sign(scrollAccumulation) * precision; + scrollAccumulation = scrollAccumulation < 0 ? Math.Min(0, scrollAccumulation + precision) : Math.Max(0, scrollAccumulation - precision); + } } protected override bool OnScroll(ScrollEvent e) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index b355d1f349..01df79c06d 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -187,15 +187,19 @@ namespace osu.Game.Screens.Edit protected override bool OnScroll(ScrollEvent e) { scrollAccumulation += e.ScrollDelta.X + e.ScrollDelta.Y * (e.IsPrecise ? 0.1 : 1); - if (Math.Abs(scrollAccumulation) < 1) - return true; - if (scrollAccumulation > 0) - clock.SeekBackward(!clock.IsRunning); - else - clock.SeekForward(!clock.IsRunning); + const int precision = 1; + + while (Math.Abs(scrollAccumulation) > precision) + { + if (scrollAccumulation > 0) + clock.SeekBackward(!clock.IsRunning); + else + clock.SeekForward(!clock.IsRunning); + + scrollAccumulation = scrollAccumulation < 0 ? Math.Min(0, scrollAccumulation + precision) : Math.Max(0, scrollAccumulation - precision); + } - scrollAccumulation = 0; return true; } From b446a73c0c52de46451e9e2d527f6eebbb6f5d9e Mon Sep 17 00:00:00 2001 From: Dan Balasescu <1329837+smoogipoo@users.noreply.github.com> Date: Fri, 23 Nov 2018 10:06:06 +0900 Subject: [PATCH 11/12] Add brackets Co-Authored-By: peppy --- osu.Game/Screens/Edit/Editor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 01df79c06d..c4fb9dc419 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -186,7 +186,7 @@ namespace osu.Game.Screens.Edit protected override bool OnScroll(ScrollEvent e) { - scrollAccumulation += e.ScrollDelta.X + e.ScrollDelta.Y * (e.IsPrecise ? 0.1 : 1); + scrollAccumulation += (e.ScrollDelta.X + e.ScrollDelta.Y) * (e.IsPrecise ? 0.1 : 1); const int precision = 1; From afa547af848cd20a7bf24842e2d04b257329d07b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 23 Nov 2018 11:00:17 +0900 Subject: [PATCH 12/12] Fix order of ChannelManager dependency caching --- osu.Game/OsuGame.cs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 4a358da227..2894e096fb 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -50,7 +50,9 @@ namespace osu.Game { public Toolbar Toolbar; - private ChatOverlay chat; + private ChatOverlay chatOverlay; + + private ChannelManager channelManager; private MusicController musicController; @@ -338,12 +340,8 @@ namespace osu.Game //overlay elements loadComponentSingleFile(direct = new DirectOverlay { Depth = -1 }, mainContent.Add); loadComponentSingleFile(social = new SocialOverlay { Depth = -1 }, mainContent.Add); - loadComponentSingleFile(new ChannelManager(), channelManager => - { - dependencies.Cache(channelManager); - AddInternal(channelManager); - }); - loadComponentSingleFile(chat = new ChatOverlay { Depth = -1 }, mainContent.Add); + loadComponentSingleFile(channelManager = new ChannelManager(), AddInternal); + loadComponentSingleFile(chatOverlay = new ChatOverlay { Depth = -1 }, mainContent.Add); loadComponentSingleFile(settings = new MainSettings { GetToolbarHeight = () => ToolbarOffset, @@ -376,7 +374,8 @@ namespace osu.Game dependencies.Cache(onscreenDisplay); dependencies.Cache(social); dependencies.Cache(direct); - dependencies.Cache(chat); + dependencies.Cache(chatOverlay); + dependencies.Cache(channelManager); dependencies.Cache(userProfile); dependencies.Cache(musicController); dependencies.Cache(beatmapSetOverlay); @@ -409,7 +408,7 @@ namespace osu.Game } // ensure only one of these overlays are open at once. - var singleDisplayOverlays = new OverlayContainer[] { chat, social, direct }; + var singleDisplayOverlays = new OverlayContainer[] { chatOverlay, social, direct }; overlays.AddRange(singleDisplayOverlays); foreach (var overlay in singleDisplayOverlays) @@ -534,7 +533,7 @@ namespace osu.Game switch (action) { case GlobalAction.ToggleChat: - chat.ToggleVisibility(); + chatOverlay.ToggleVisibility(); return true; case GlobalAction.ToggleSocial: social.ToggleVisibility();