From 56de6c10670199f6d0633e3bd59720610bd1376d Mon Sep 17 00:00:00 2001 From: miterosan Date: Wed, 28 Mar 2018 21:11:06 +0200 Subject: [PATCH 001/155] Rename Channel to ChannelChat --- osu.Game.Tests/Visual/TestCaseChatLink.cs | 4 ++-- .../Online/API/Requests/GetMessagesRequest.cs | 4 ++-- .../API/Requests/ListChannelsRequest.cs | 2 +- .../Chat/{Channel.cs => ChannelChat.cs} | 4 ++-- osu.Game/Overlays/Chat/ChannelListItem.cs | 8 ++++---- osu.Game/Overlays/Chat/ChannelSection.cs | 2 +- .../Overlays/Chat/ChannelSelectionOverlay.cs | 4 ++-- osu.Game/Overlays/Chat/ChatTabControl.cs | 20 +++++++++---------- osu.Game/Overlays/Chat/DrawableChannel.cs | 8 ++++---- osu.Game/Overlays/ChatOverlay.cs | 20 +++++++++---------- 10 files changed, 38 insertions(+), 38 deletions(-) rename osu.Game/Online/Chat/{Channel.cs => ChannelChat.cs} (95%) diff --git a/osu.Game.Tests/Visual/TestCaseChatLink.cs b/osu.Game.Tests/Visual/TestCaseChatLink.cs index 786fcb64ab..d638019b24 100644 --- a/osu.Game.Tests/Visual/TestCaseChatLink.cs +++ b/osu.Game.Tests/Visual/TestCaseChatLink.cs @@ -57,8 +57,8 @@ namespace osu.Game.Tests.Visual { AvailableChannels = { - new Channel { Name = "#english" }, - new Channel { Name = "#japanese" } + new ChannelChat { Name = "#english" }, + new ChannelChat { Name = "#japanese" } } }); diff --git a/osu.Game/Online/API/Requests/GetMessagesRequest.cs b/osu.Game/Online/API/Requests/GetMessagesRequest.cs index a8f63887a1..b7546ce7f4 100644 --- a/osu.Game/Online/API/Requests/GetMessagesRequest.cs +++ b/osu.Game/Online/API/Requests/GetMessagesRequest.cs @@ -10,10 +10,10 @@ namespace osu.Game.Online.API.Requests { public class GetMessagesRequest : APIRequest> { - private readonly List channels; + private readonly List channels; private long? since; - public GetMessagesRequest(List channels, long? sinceId) + public GetMessagesRequest(List channels, long? sinceId) { this.channels = channels; since = sinceId; diff --git a/osu.Game/Online/API/Requests/ListChannelsRequest.cs b/osu.Game/Online/API/Requests/ListChannelsRequest.cs index b387af9694..97ed3d3cbc 100644 --- a/osu.Game/Online/API/Requests/ListChannelsRequest.cs +++ b/osu.Game/Online/API/Requests/ListChannelsRequest.cs @@ -6,7 +6,7 @@ using osu.Game.Online.Chat; namespace osu.Game.Online.API.Requests { - public class ListChannelsRequest : APIRequest> + public class ListChannelsRequest : APIRequest> { protected override string Target => @"chat/channels"; } diff --git a/osu.Game/Online/Chat/Channel.cs b/osu.Game/Online/Chat/ChannelChat.cs similarity index 95% rename from osu.Game/Online/Chat/Channel.cs rename to osu.Game/Online/Chat/ChannelChat.cs index 35952fbc6e..c39d5cf4b1 100644 --- a/osu.Game/Online/Chat/Channel.cs +++ b/osu.Game/Online/Chat/ChannelChat.cs @@ -10,7 +10,7 @@ using osu.Framework.Lists; namespace osu.Game.Online.Chat { - public class Channel + public class ChannelChat { [JsonProperty(@"name")] public string Name; @@ -35,7 +35,7 @@ namespace osu.Game.Online.Chat public const int MAX_HISTORY = 300; [JsonConstructor] - public Channel() + public ChannelChat() { } diff --git a/osu.Game/Overlays/Chat/ChannelListItem.cs b/osu.Game/Overlays/Chat/ChannelListItem.cs index 19418c63a8..9625c715d2 100644 --- a/osu.Game/Overlays/Chat/ChannelListItem.cs +++ b/osu.Game/Overlays/Chat/ChannelListItem.cs @@ -24,7 +24,7 @@ namespace osu.Game.Overlays.Chat private const float text_size = 15; private const float transition_duration = 100; - private readonly Channel channel; + private readonly ChannelChat channel; private readonly Bindable joinedBind = new Bindable(); private readonly OsuSpriteText name; @@ -44,10 +44,10 @@ namespace osu.Game.Overlays.Chat } } - public Action OnRequestJoin; - public Action OnRequestLeave; + public Action OnRequestJoin; + public Action OnRequestLeave; - public ChannelListItem(Channel channel) + public ChannelListItem(ChannelChat channel) { this.channel = channel; diff --git a/osu.Game/Overlays/Chat/ChannelSection.cs b/osu.Game/Overlays/Chat/ChannelSection.cs index 132891bcc0..6bec82f505 100644 --- a/osu.Game/Overlays/Chat/ChannelSection.cs +++ b/osu.Game/Overlays/Chat/ChannelSection.cs @@ -33,7 +33,7 @@ namespace osu.Game.Overlays.Chat set { header.Text = value.ToUpper(); } } - public IEnumerable Channels + public IEnumerable Channels { set { ChannelFlow.ChildrenEnumerable = value.Select(c => new ChannelListItem(c)); } } diff --git a/osu.Game/Overlays/Chat/ChannelSelectionOverlay.cs b/osu.Game/Overlays/Chat/ChannelSelectionOverlay.cs index 3684c47e40..598e1fe527 100644 --- a/osu.Game/Overlays/Chat/ChannelSelectionOverlay.cs +++ b/osu.Game/Overlays/Chat/ChannelSelectionOverlay.cs @@ -32,8 +32,8 @@ namespace osu.Game.Overlays.Chat private readonly SearchTextBox search; private readonly SearchContainer sectionsFlow; - public Action OnRequestJoin; - public Action OnRequestLeave; + public Action OnRequestJoin; + public Action OnRequestLeave; public IEnumerable Sections { diff --git a/osu.Game/Overlays/Chat/ChatTabControl.cs b/osu.Game/Overlays/Chat/ChatTabControl.cs index 1d3dab249d..e495faf944 100644 --- a/osu.Game/Overlays/Chat/ChatTabControl.cs +++ b/osu.Game/Overlays/Chat/ChatTabControl.cs @@ -21,11 +21,11 @@ using osu.Game.Graphics.Containers; namespace osu.Game.Overlays.Chat { - public class ChatTabControl : OsuTabControl + public class ChatTabControl : OsuTabControl { private const float shear_width = 10; - public Action OnRequestLeave; + public Action OnRequestLeave; public readonly Bindable ChannelSelectorActive = new Bindable(); @@ -46,12 +46,12 @@ namespace osu.Game.Overlays.Chat Margin = new MarginPadding(10), }); - AddTabItem(selectorTab = new ChannelTabItem.ChannelSelectorTabItem(new Channel { Name = "+" })); + AddTabItem(selectorTab = new ChannelTabItem.ChannelSelectorTabItem(new ChannelChat { Name = "+" })); ChannelSelectorActive.BindTo(selectorTab.Active); } - protected override void AddTabItem(TabItem item, bool addToDropdown = true) + protected override void AddTabItem(TabItem item, bool addToDropdown = true) { if (item != selectorTab && TabContainer.GetLayoutPosition(selectorTab) < float.MaxValue) // performTabSort might've made selectorTab's position wonky, fix it @@ -63,9 +63,9 @@ namespace osu.Game.Overlays.Chat SelectTab(item); } - protected override TabItem CreateTabItem(Channel value) => new ChannelTabItem(value) { OnRequestClose = tabCloseRequested }; + protected override TabItem CreateTabItem(ChannelChat value) => new ChannelTabItem(value) { OnRequestClose = tabCloseRequested }; - protected override void SelectTab(TabItem tab) + protected override void SelectTab(TabItem tab) { if (tab is ChannelTabItem.ChannelSelectorTabItem) { @@ -78,7 +78,7 @@ namespace osu.Game.Overlays.Chat base.SelectTab(tab); } - private void tabCloseRequested(TabItem tab) + private void tabCloseRequested(TabItem tab) { int totalTabs = TabContainer.Count - 1; // account for selectorTab int currentIndex = MathHelper.Clamp(TabContainer.IndexOf(tab), 1, totalTabs); @@ -93,7 +93,7 @@ namespace osu.Game.Overlays.Chat OnRequestLeave?.Invoke(tab.Value); } - private class ChannelTabItem : TabItem + private class ChannelTabItem : TabItem { private Color4 backgroundInactive; private Color4 backgroundHover; @@ -175,7 +175,7 @@ namespace osu.Game.Overlays.Chat updateState(); } - public ChannelTabItem(Channel value) : base(value) + public ChannelTabItem(ChannelChat value) : base(value) { Width = 150; @@ -307,7 +307,7 @@ namespace osu.Game.Overlays.Chat { public override bool IsRemovable => false; - public ChannelSelectorTabItem(Channel value) : base(value) + public ChannelSelectorTabItem(ChannelChat value) : base(value) { Depth = float.MaxValue; Width = 45; diff --git a/osu.Game/Overlays/Chat/DrawableChannel.cs b/osu.Game/Overlays/Chat/DrawableChannel.cs index d12df70b74..ac41b2f157 100644 --- a/osu.Game/Overlays/Chat/DrawableChannel.cs +++ b/osu.Game/Overlays/Chat/DrawableChannel.cs @@ -17,11 +17,11 @@ namespace osu.Game.Overlays.Chat { public class DrawableChannel : Container { - public readonly Channel Channel; + public readonly ChannelChat Channel; private readonly ChatLineContainer flow; private readonly ScrollContainer scroll; - public DrawableChannel(Channel channel) + public DrawableChannel(ChannelChat channel) { Channel = channel; @@ -79,7 +79,7 @@ namespace osu.Game.Overlays.Chat private void newMessagesArrived(IEnumerable newMessages) { // Add up to last Channel.MAX_HISTORY messages - var displayMessages = newMessages.Skip(Math.Max(0, newMessages.Count() - Channel.MAX_HISTORY)); + var displayMessages = newMessages.Skip(Math.Max(0, newMessages.Count() - ChannelChat.MAX_HISTORY)); flow.AddRange(displayMessages.Select(m => new ChatLine(m))); @@ -89,7 +89,7 @@ namespace osu.Game.Overlays.Chat scrollToEnd(); var staleMessages = flow.Children.Where(c => c.LifetimeEnd == double.MaxValue).ToArray(); - int count = staleMessages.Length - Channel.MAX_HISTORY; + int count = staleMessages.Length - ChannelChat.MAX_HISTORY; for (int i = 0; i < count; i++) { diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 210f5ce01e..315f8d2c41 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -60,7 +60,7 @@ namespace osu.Game.Overlays public Bindable ChatHeight { get; set; } - public List AvailableChannels { get; private set; } = new List(); + public List AvailableChannels { get; private set; } = new List(); private readonly Container channelSelectionContainer; private readonly ChannelSelectionOverlay channelSelection; @@ -191,7 +191,7 @@ namespace osu.Game.Overlays private double startDragChatHeight; private bool isDragging; - public void OpenChannel(Channel channel) => addChannel(channel); + public void OpenChannel(ChannelChat channel) => addChannel(channel); protected override bool OnDragStart(InputState state) { @@ -289,7 +289,7 @@ namespace osu.Game.Overlays private long? lastMessageId; - private readonly List careChannels = new List(); + private readonly List careChannels = new List(); private readonly List loadedChannels = new List(); @@ -300,7 +300,7 @@ namespace osu.Game.Overlays messageRequest?.Cancel(); ListChannelsRequest req = new ListChannelsRequest(); - req.Success += delegate (List channels) + req.Success += delegate (List channels) { AvailableChannels = channels; @@ -328,9 +328,9 @@ namespace osu.Game.Overlays api.Queue(req); } - private Channel currentChannel; + private ChannelChat currentChannel; - protected Channel CurrentChannel + protected ChannelChat CurrentChannel { get { @@ -380,7 +380,7 @@ namespace osu.Game.Overlays } } - private void addChannel(Channel channel) + private void addChannel(ChannelChat channel) { if (channel == null) return; @@ -407,7 +407,7 @@ namespace osu.Game.Overlays channel.Joined.Value = true; } - private void removeChannel(Channel channel) + private void removeChannel(ChannelChat channel) { if (channel == null) return; @@ -420,9 +420,9 @@ namespace osu.Game.Overlays channel.Joined.Value = false; } - private void fetchInitialMessages(Channel channel) + private void fetchInitialMessages(ChannelChat channel) { - var req = new GetMessagesRequest(new List { channel }, null); + var req = new GetMessagesRequest(new List { channel }, null); req.Success += delegate (List messages) { From c9377896848861a0bcd035e42b726bdbed334efe Mon Sep 17 00:00:00 2001 From: miterosan Date: Wed, 28 Mar 2018 21:33:50 +0200 Subject: [PATCH 002/155] Rename GetMessagesRequest to GetChannelMessagesRequest --- .../{GetMessagesRequest.cs => GetChannelMessagesRequest.cs} | 4 ++-- osu.Game/Overlays/ChatOverlay.cs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) rename osu.Game/Online/API/Requests/{GetMessagesRequest.cs => GetChannelMessagesRequest.cs} (83%) diff --git a/osu.Game/Online/API/Requests/GetMessagesRequest.cs b/osu.Game/Online/API/Requests/GetChannelMessagesRequest.cs similarity index 83% rename from osu.Game/Online/API/Requests/GetMessagesRequest.cs rename to osu.Game/Online/API/Requests/GetChannelMessagesRequest.cs index b7546ce7f4..45541c202e 100644 --- a/osu.Game/Online/API/Requests/GetMessagesRequest.cs +++ b/osu.Game/Online/API/Requests/GetChannelMessagesRequest.cs @@ -8,12 +8,12 @@ using osu.Game.Online.Chat; namespace osu.Game.Online.API.Requests { - public class GetMessagesRequest : APIRequest> + public class GetChannelMessagesRequest : APIRequest> { private readonly List channels; private long? since; - public GetMessagesRequest(List channels, long? sinceId) + public GetChannelMessagesRequest(List channels, long? sinceId) { this.channels = channels; since = sinceId; diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 315f8d2c41..8b3031b9e7 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -49,7 +49,7 @@ namespace osu.Game.Overlays public const float TAB_AREA_HEIGHT = 50; - private GetMessagesRequest fetchReq; + private GetChannelMessagesRequest fetchReq; private readonly ChatTabControl channelTabs; @@ -422,7 +422,7 @@ namespace osu.Game.Overlays private void fetchInitialMessages(ChannelChat channel) { - var req = new GetMessagesRequest(new List { channel }, null); + var req = new GetChannelMessagesRequest(new List { channel }, null); req.Success += delegate (List messages) { @@ -442,7 +442,7 @@ namespace osu.Game.Overlays { if (fetchReq != null) return; - fetchReq = new GetMessagesRequest(careChannels, lastMessageId); + fetchReq = new GetChannelMessagesRequest(careChannels, lastMessageId); fetchReq.Success += delegate (List messages) { From f1696eae922d812ad41337d1e79ffa431530f78d Mon Sep 17 00:00:00 2001 From: miterosan Date: Sun, 8 Apr 2018 15:01:14 +0200 Subject: [PATCH 003/155] Use IEnumable instead of List --- osu.Game/Online/API/Requests/GetChannelMessagesRequest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/API/Requests/GetChannelMessagesRequest.cs b/osu.Game/Online/API/Requests/GetChannelMessagesRequest.cs index 45541c202e..d463af6c25 100644 --- a/osu.Game/Online/API/Requests/GetChannelMessagesRequest.cs +++ b/osu.Game/Online/API/Requests/GetChannelMessagesRequest.cs @@ -10,10 +10,10 @@ namespace osu.Game.Online.API.Requests { public class GetChannelMessagesRequest : APIRequest> { - private readonly List channels; + private readonly IEnumerable channels; private long? since; - public GetChannelMessagesRequest(List channels, long? sinceId) + public GetChannelMessagesRequest(IEnumerable channels, long? sinceId) { this.channels = channels; since = sinceId; From a70b329155e69f27113bc66af9840cbceed4d040 Mon Sep 17 00:00:00 2001 From: miterosan Date: Sun, 8 Apr 2018 18:21:48 +0200 Subject: [PATCH 004/155] Split drawing and business logic of ChatOverlay --- osu.Game.Tests/Visual/TestCaseChatLink.cs | 16 +- .../Graphics/Containers/LinkFlowContainer.cs | 10 +- osu.Game/Online/Chat/ChannelChat.cs | 80 +--- osu.Game/Online/Chat/ChatBase.cs | 85 ++++ osu.Game/Online/Chat/ChatManager.cs | 193 +++++++++ osu.Game/Online/Chat/Message.cs | 2 +- osu.Game/OsuGame.cs | 7 +- osu.Game/OsuGameBase.cs | 6 + osu.Game/Overlays/Chat/ChatLine.cs | 10 +- .../{DrawableChannel.cs => DrawableChat.cs} | 28 +- osu.Game/Overlays/ChatOverlay.cs | 382 +++++------------- 11 files changed, 431 insertions(+), 388 deletions(-) create mode 100644 osu.Game/Online/Chat/ChatBase.cs create mode 100644 osu.Game/Online/Chat/ChatManager.cs rename osu.Game/Overlays/Chat/{DrawableChannel.cs => DrawableChat.cs} (80%) diff --git a/osu.Game.Tests/Visual/TestCaseChatLink.cs b/osu.Game.Tests/Visual/TestCaseChatLink.cs index d638019b24..4f85779bce 100644 --- a/osu.Game.Tests/Visual/TestCaseChatLink.cs +++ b/osu.Game.Tests/Visual/TestCaseChatLink.cs @@ -15,6 +15,7 @@ using System.Linq; using NUnit.Framework; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; +using osu.Game.Online.API; using osu.Game.Overlays; namespace osu.Game.Tests.Visual @@ -50,17 +51,14 @@ namespace osu.Game.Tests.Visual } [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load(OsuColour colours, IAPIProvider api) { linkColour = colours.Blue; - dependencies.Cache(new ChatOverlay - { - AvailableChannels = - { - new ChannelChat { Name = "#english" }, - new ChannelChat { Name = "#japanese" } - } - }); + dependencies.Cache(new ChatOverlay()); + + var chatManager = new ChatManager(Scheduler); + api.Register(chatManager); + dependencies.Cache(chatManager); testLinksGeneral(); testEcho(); diff --git a/osu.Game/Graphics/Containers/LinkFlowContainer.cs b/osu.Game/Graphics/Containers/LinkFlowContainer.cs index 1d231ada23..627efbda76 100644 --- a/osu.Game/Graphics/Containers/LinkFlowContainer.cs +++ b/osu.Game/Graphics/Containers/LinkFlowContainer.cs @@ -23,15 +23,15 @@ namespace osu.Game.Graphics.Containers public override bool HandleMouseInput => true; private OsuGame game; - + private ChatManager chatManager; private Action showNotImplementedError; [BackgroundDependencyLoader(true)] - private void load(OsuGame game, NotificationOverlay notifications) + private void load(OsuGame game, NotificationOverlay notifications, ChatManager chatManager) { // will be null in tests this.game = game; - + this.chatManager = chatManager; showNotImplementedError = () => notifications?.Post(new SimpleNotification { Text = @"This link type is not yet supported!", @@ -80,7 +80,9 @@ namespace osu.Game.Graphics.Containers game?.ShowBeatmapSet(setId); break; case LinkAction.OpenChannel: - game?.OpenChannel(linkArgument); + var channel = chatManager.AvailableChannels.FirstOrDefault(c => c.Name == linkArgument); + if (channel != null) + chatManager.CurrentChat.Value = channel; break; case LinkAction.OpenEditorTimestamp: case LinkAction.JoinMultiplayerMatch: diff --git a/osu.Game/Online/Chat/ChannelChat.cs b/osu.Game/Online/Chat/ChannelChat.cs index c39d5cf4b1..fb24806294 100644 --- a/osu.Game/Online/Chat/ChannelChat.cs +++ b/osu.Game/Online/Chat/ChannelChat.cs @@ -1,16 +1,11 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System; -using System.Collections.Generic; -using System.Linq; using Newtonsoft.Json; -using osu.Framework.Configuration; -using osu.Framework.Lists; namespace osu.Game.Online.Chat { - public class ChannelChat + public class ChannelChat : ChatBase { [JsonProperty(@"name")] public string Name; @@ -24,82 +19,13 @@ namespace osu.Game.Online.Chat [JsonProperty(@"channel_id")] public int Id; - public readonly SortedList Messages = new SortedList(Comparer.Default); - - private readonly List pendingMessages = new List(); - - public Bindable Joined = new Bindable(); - - public bool ReadOnly => false; - - public const int MAX_HISTORY = 300; - [JsonConstructor] public ChannelChat() { } - public event Action> NewMessagesArrived; - public event Action PendingMessageResolved; - public event Action MessageRemoved; - - public void AddLocalEcho(LocalEchoMessage message) - { - pendingMessages.Add(message); - Messages.Add(message); - - NewMessagesArrived?.Invoke(new[] { message }); - } - - public void AddNewMessages(params Message[] messages) - { - messages = messages.Except(Messages).ToArray(); - - Messages.AddRange(messages); - - purgeOldMessages(); - - NewMessagesArrived?.Invoke(messages); - } - - private void purgeOldMessages() - { - // never purge local echos - int messageCount = Messages.Count - pendingMessages.Count; - if (messageCount > MAX_HISTORY) - Messages.RemoveRange(0, messageCount - MAX_HISTORY); - } - - /// - /// Replace or remove a message from the channel. - /// - /// The local echo message (client-side). - /// The response message, or null if the message became invalid. - public void ReplaceMessage(LocalEchoMessage echo, Message final) - { - if (!pendingMessages.Remove(echo)) - throw new InvalidOperationException("Attempted to remove echo that wasn't present"); - - Messages.Remove(echo); - - if (final == null) - { - MessageRemoved?.Invoke(echo); - return; - } - - if (Messages.Contains(final)) - { - // message already inserted, so let's throw away this update. - // we may want to handle this better in the future, but for the time being api requests are single-threaded so order is assumed. - MessageRemoved?.Invoke(echo); - return; - } - - Messages.Add(final); - PendingMessageResolved?.Invoke(echo, final); - } - public override string ToString() => Name; + public override long ChatID => Id; + public override TargetType Target => TargetType.Channel; } } diff --git a/osu.Game/Online/Chat/ChatBase.cs b/osu.Game/Online/Chat/ChatBase.cs new file mode 100644 index 0000000000..969d2c0f1f --- /dev/null +++ b/osu.Game/Online/Chat/ChatBase.cs @@ -0,0 +1,85 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using System.Linq; +using osu.Framework.Configuration; +using osu.Framework.Lists; + +namespace osu.Game.Online.Chat +{ + public abstract class ChatBase + { + public const int MAX_HISTORY = 300; + public bool ReadOnly { get; } = false; + public abstract TargetType Target { get; } + public abstract long ChatID { get; } + public Bindable Joined = new Bindable(); + + public readonly SortedList Messages = new SortedList(Comparer.Default); + private readonly List pendingMessages = new List(); + + public event Action> NewMessagesArrived; + public event Action PendingMessageResolved; + public event Action MessageRemoved; + + public void AddLocalEcho(LocalEchoMessage message) + { + pendingMessages.Add(message); + Messages.Add(message); + + NewMessagesArrived?.Invoke(new[] { message }); + } + + public void AddNewMessages(params Message[] messages) + { + messages = messages.Except(Messages).ToArray(); + + Messages.AddRange(messages); + + purgeOldMessages(); + + NewMessagesArrived?.Invoke(messages); + } + + private void purgeOldMessages() + { + // never purge local echos + int messageCount = Messages.Count - pendingMessages.Count; + if (messageCount > MAX_HISTORY) + Messages.RemoveRange(0, messageCount - MAX_HISTORY); + } + + /// + /// Replace or remove a message from the chat. + /// + /// The local echo message (client-side). + /// The response message, or null if the message became invalid. + public void ReplaceMessage(LocalEchoMessage echo, Message final) + { + if (!pendingMessages.Remove(echo)) + throw new InvalidOperationException("Attempted to remove echo that wasn't present"); + + Messages.Remove(echo); + + if (final == null) + { + MessageRemoved?.Invoke(echo); + return; + } + + if (Messages.Contains(final)) + { + // message already inserted, so let's throw away this update. + // we may want to handle this better in the future, but for the time being api requests are single-threaded so order is assumed. + MessageRemoved?.Invoke(echo); + return; + } + + Messages.Add(final); + PendingMessageResolved?.Invoke(echo, final); + } + + } +} diff --git a/osu.Game/Online/Chat/ChatManager.cs b/osu.Game/Online/Chat/ChatManager.cs new file mode 100644 index 0000000000..69620c8f53 --- /dev/null +++ b/osu.Game/Online/Chat/ChatManager.cs @@ -0,0 +1,193 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using osu.Framework.Configuration; +using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Framework.Logging; +using osu.Framework.Threading; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; + +namespace osu.Game.Online.Chat +{ + /// + /// Manages everything chat related + /// + public sealed class ChatManager : IOnlineComponent + { + /// + /// The channels the player joins on startup + /// + private readonly string[] defaultChannels = + { + @"#lazer", @"#osu", @"#lobby" + }; + + /// + /// The currently opened chat + /// + public Bindable CurrentChat { get; } = new Bindable(); + /// + /// The Channels the player has joined + /// + public ObservableCollection JoinedChannels { get; } = new ObservableCollection(); + /// + /// The channels available for the player to join + /// + public ObservableCollection AvailableChannels { get; } = new ObservableCollection(); + + private APIAccess api; + private readonly Scheduler scheduler; + private ScheduledDelegate fetchMessagesScheduleder; + private GetChannelMessagesRequest fetchChannelMsgReq; + private long? lastChannelMsgId; + + public ChatManager(Scheduler scheduler) + { + this.scheduler = scheduler ?? throw new ArgumentNullException(nameof(scheduler)); + CurrentChat.ValueChanged += currentChatChanged; + } + + private void currentChatChanged(ChatBase chatBase) + { + if (chatBase is ChannelChat channel && !JoinedChannels.Contains(channel)) + JoinedChannels.Add(channel); + + } + + /// + /// Posts a message to the currently opened chat. + /// + /// The message text that is going to be posted + /// Is true if the message is an action, e.g.: user is currently eating + public void PostMessage(string text, bool isAction = false) + { + if (CurrentChat.Value == null) + return; + + if (!api.IsLoggedIn) + { + CurrentChat.Value.AddNewMessages(new ErrorMessage("Please sign in to participate in chat!")); + return; + } + + var message = new LocalEchoMessage + { + Sender = api.LocalUser.Value, + Timestamp = DateTimeOffset.Now, + TargetType = CurrentChat.Value.Target, + TargetId = CurrentChat.Value.ChatID, + IsAction = isAction, + Content = text + }; + + CurrentChat.Value.AddLocalEcho(message); + + var req = new PostMessageRequest(message); + req.Failure += e => CurrentChat.Value?.ReplaceMessage(message, null); + req.Success += m => CurrentChat.Value?.ReplaceMessage(message, m); + api.Queue(req); + } + + public void PostCommand(string text) + { + if (CurrentChat.Value == null) + return; + + var parameters = text.Split(new[] { ' ' }, 2); + string command = parameters[0]; + string content = parameters.Length == 2 ? parameters[1] : string.Empty; + + switch (command) + { + case "me": + if (string.IsNullOrWhiteSpace(content)) + { + CurrentChat.Value.AddNewMessages(new ErrorMessage("Usage: /me [action]")); + break; + } + PostMessage(content, true); + break; + + case "help": + CurrentChat.Value.AddNewMessages(new InfoMessage("Supported commands: /help, /me [action]")); + break; + + default: + CurrentChat.Value.AddNewMessages(new ErrorMessage($@"""/{command}"" is not supported! For a list of supported commands see /help")); + break; + } + } + + private void fetchNewMessages() + { + if (fetchChannelMsgReq == null) + fetchNewChannelMessages(); + } + + private void fetchNewChannelMessages() + { + fetchChannelMsgReq = new GetChannelMessagesRequest(JoinedChannels, lastChannelMsgId); + + fetchChannelMsgReq.Success += messages => + { + handleChannelMessages(messages); + lastChannelMsgId = messages.LastOrDefault()?.Id ?? lastChannelMsgId; + fetchChannelMsgReq = null; + }; + fetchChannelMsgReq.Failure += exception => Logger.Error(exception, "Fetching channel messages failed."); + + api.Queue(fetchChannelMsgReq); + } + + private void handleChannelMessages(IEnumerable messages) + { + var channels = JoinedChannels.ToList(); + + foreach (var group in messages.GroupBy(m => m.TargetId)) + channels.Find(c => c.Id == group.Key)?.AddNewMessages(group.ToArray()); + } + + private void initializeDefaultChannels() + { + var req = new ListChannelsRequest(); + + req.Success += channels => + { + channels.Where(channel => AvailableChannels.All(c => c.ChatID != channel.ChatID)) + .ForEach(channel => AvailableChannels.Add(channel)); + + channels.Where(channel => defaultChannels.Contains(channel.Name)) + .Where(channel => JoinedChannels.All(c => c.ChatID != channel.ChatID)) + .ForEach(channel => JoinedChannels.Add(channel)); + + fetchNewMessages(); + }; + req.Failure += error => Logger.Error(error, "Fetching channels failed"); + + api.Queue(req); + } + + public void APIStateChanged(APIAccess api, APIState state) + { + this.api = api ?? throw new ArgumentNullException(nameof(api)); + + switch (state) + { + case APIState.Online: + if (JoinedChannels.Count == 0) + initializeDefaultChannels(); + fetchMessagesScheduleder = scheduler.AddDelayed(fetchNewMessages, 1000, true); + break; + default: + fetchChannelMsgReq?.Cancel(); + fetchMessagesScheduleder?.Cancel(); + break; + } + } + } +} diff --git a/osu.Game/Online/Chat/Message.cs b/osu.Game/Online/Chat/Message.cs index df3753da6a..d1d1f1b55b 100644 --- a/osu.Game/Online/Chat/Message.cs +++ b/osu.Game/Online/Chat/Message.cs @@ -22,7 +22,7 @@ namespace osu.Game.Online.Chat public TargetType TargetType; [JsonProperty(@"target_id")] - public int TargetId; + public long TargetId; [JsonProperty(@"is_action")] public bool IsAction; diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 89447b8ed6..1b55418c7b 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -29,6 +29,7 @@ using osu.Game.Overlays.Notifications; using osu.Game.Rulesets; using osu.Game.Screens.Play; using osu.Game.Input.Bindings; +using osu.Game.Online.Chat; using osu.Game.Rulesets.Mods; using osu.Game.Skinning; using OpenTK.Graphics; @@ -142,12 +143,6 @@ namespace osu.Game private ScheduledDelegate scoreLoad; - /// - /// Open chat to a channel matching the provided name, if present. - /// - /// The name of the channel. - public void OpenChannel(string channelName) => chat.OpenChannel(chat.AvailableChannels.Find(c => c.Name == channelName)); - /// /// Show a beatmap set as an overlay. /// diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 54a279e977..d247bc74ff 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -28,6 +28,7 @@ using osu.Game.Graphics.Textures; using osu.Game.Input; using osu.Game.Input.Bindings; using osu.Game.IO; +using osu.Game.Online.Chat; using osu.Game.Rulesets; using osu.Game.Rulesets.Scoring; using osu.Game.Skinning; @@ -112,6 +113,11 @@ namespace osu.Game dependencies.Cache(api); dependencies.CacheAs(api); + var chatManager = new ChatManager(Scheduler); + api.Register(chatManager); + + dependencies.Cache(chatManager); + 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)); diff --git a/osu.Game/Overlays/Chat/ChatLine.cs b/osu.Game/Overlays/Chat/ChatLine.cs index dd41dd5428..eb1ab9ef26 100644 --- a/osu.Game/Overlays/Chat/ChatLine.cs +++ b/osu.Game/Overlays/Chat/ChatLine.cs @@ -81,6 +81,8 @@ namespace osu.Game.Overlays.Chat Padding = new MarginPadding { Left = padding, Right = padding }; } + private ChatManager chatManager; + private Message message; private OsuSpriteText username; private LinkFlowContainer contentFlow; @@ -104,9 +106,9 @@ namespace osu.Game.Overlays.Chat } [BackgroundDependencyLoader(true)] - private void load(OsuColour colours, ChatOverlay chat) + private void load(OsuColour colours, ChatManager chatManager) { - this.chat = chat; + this.chatManager = chatManager; customUsernameColour = colours.ChatBlue; } @@ -215,8 +217,6 @@ namespace osu.Game.Overlays.Chat FinishTransforms(true); } - private ChatOverlay chat; - private void updateMessageContent() { this.FadeTo(message is LocalEchoMessage ? 0.4f : 1.0f, 500, Easing.OutQuint); @@ -226,7 +226,7 @@ namespace osu.Game.Overlays.Chat username.Text = $@"{message.Sender.Username}" + (senderHasBackground || message.IsAction ? "" : ":"); // remove non-existent channels from the link list - message.Links.RemoveAll(link => link.Action == LinkAction.OpenChannel && chat?.AvailableChannels.Any(c => c.Name == link.Argument) != true); + message.Links.RemoveAll(link => link.Action == LinkAction.OpenChannel && chatManager?.AvailableChannels.Any(c => c.Name == link.Argument) != true); contentFlow.Clear(); contentFlow.AddLinks(message.DisplayContent, message.Links); diff --git a/osu.Game/Overlays/Chat/DrawableChannel.cs b/osu.Game/Overlays/Chat/DrawableChat.cs similarity index 80% rename from osu.Game/Overlays/Chat/DrawableChannel.cs rename to osu.Game/Overlays/Chat/DrawableChat.cs index ac41b2f157..0efcf1ac00 100644 --- a/osu.Game/Overlays/Chat/DrawableChannel.cs +++ b/osu.Game/Overlays/Chat/DrawableChat.cs @@ -15,15 +15,15 @@ using osu.Game.Online.Chat; namespace osu.Game.Overlays.Chat { - public class DrawableChannel : Container + public class DrawableChat : Container { - public readonly ChannelChat Channel; + public readonly ChatBase Chat; private readonly ChatLineContainer flow; private readonly ScrollContainer scroll; - public DrawableChannel(ChannelChat channel) + public DrawableChat(ChatBase chat) { - Channel = channel; + Chat = chat; RelativeSizeAxes = Axes.Both; @@ -50,15 +50,15 @@ namespace osu.Game.Overlays.Chat } }; - Channel.NewMessagesArrived += newMessagesArrived; - Channel.MessageRemoved += messageRemoved; - Channel.PendingMessageResolved += pendingMessageResolved; + Chat.NewMessagesArrived += newMessagesArrived; + Chat.MessageRemoved += messageRemoved; + Chat.PendingMessageResolved += pendingMessageResolved; } [BackgroundDependencyLoader] private void load() { - newMessagesArrived(Channel.Messages); + newMessagesArrived(Chat.Messages); } protected override void LoadComplete() @@ -71,15 +71,15 @@ namespace osu.Game.Overlays.Chat { base.Dispose(isDisposing); - Channel.NewMessagesArrived -= newMessagesArrived; - Channel.MessageRemoved -= messageRemoved; - Channel.PendingMessageResolved -= pendingMessageResolved; + Chat.NewMessagesArrived -= newMessagesArrived; + Chat.MessageRemoved -= messageRemoved; + Chat.PendingMessageResolved -= pendingMessageResolved; } private void newMessagesArrived(IEnumerable newMessages) { - // Add up to last Channel.MAX_HISTORY messages - var displayMessages = newMessages.Skip(Math.Max(0, newMessages.Count() - ChannelChat.MAX_HISTORY)); + // Add up to last ChatBase.MAX_HISTORY messages + var displayMessages = newMessages.Skip(Math.Max(0, newMessages.Count() - ChatBase.MAX_HISTORY)); flow.AddRange(displayMessages.Select(m => new ChatLine(m))); @@ -89,7 +89,7 @@ namespace osu.Game.Overlays.Chat scrollToEnd(); var staleMessages = flow.Children.Where(c => c.LifetimeEnd == double.MaxValue).ToArray(); - int count = staleMessages.Length - ChannelChat.MAX_HISTORY; + int count = staleMessages.Length - ChatBase.MAX_HISTORY; for (int i = 0; i < count; i++) { diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 8b3031b9e7..855a631f6b 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -1,10 +1,9 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System; using System.Collections.Generic; +using System.Collections.Specialized; using System.Diagnostics; -using System.Linq; using OpenTK; using OpenTK.Graphics; using osu.Framework.Allocation; @@ -16,41 +15,36 @@ using osu.Framework.Graphics.Transforms; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input; using osu.Framework.MathUtils; -using osu.Framework.Threading; using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; -using osu.Game.Online.API.Requests; using osu.Game.Online.Chat; using osu.Game.Overlays.Chat; namespace osu.Game.Overlays { - public class ChatOverlay : OsuFocusedOverlayContainer, IOnlineComponent + public class ChatOverlay : OsuFocusedOverlayContainer { private const float textbox_height = 60; private const float channel_selection_min_height = 0.3f; - private ScheduledDelegate messageRequest; + private ChatManager chatManager; - private readonly Container currentChannelContainer; + private readonly Container currentChannelContainer; + private readonly List loadedChannels = new List(); private readonly LoadingAnimation loading; private readonly FocusedTextBox textbox; - private APIAccess api; - private const int transition_length = 500; public const float DEFAULT_HEIGHT = 0.4f; public const float TAB_AREA_HEIGHT = 50; - private GetChannelMessagesRequest fetchReq; - private readonly ChatTabControl channelTabs; private readonly Container chatContainer; @@ -60,10 +54,10 @@ namespace osu.Game.Overlays public Bindable ChatHeight { get; set; } - public List AvailableChannels { get; private set; } = new List(); 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 ChatOverlay() @@ -110,7 +104,7 @@ namespace osu.Game.Overlays { RelativeSizeAxes = Axes.Both, }, - currentChannelContainer = new Container + currentChannelContainer = new Container { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding @@ -163,7 +157,7 @@ namespace osu.Game.Overlays channelTabs = new ChatTabControl { RelativeSizeAxes = Axes.Both, - OnRequestLeave = removeChannel, + OnRequestLeave = channel => chatManager.JoinedChannels.Remove(channel), }, } }, @@ -171,7 +165,7 @@ namespace osu.Game.Overlays }, }; - channelTabs.Current.ValueChanged += newChannel => CurrentChannel = newChannel; + channelTabs.Current.ValueChanged += newChannel => chatManager.CurrentChat.Value = newChannel; channelTabs.ChannelSelectorActive.ValueChanged += value => channelSelection.State = value ? Visibility.Visible : Visibility.Hidden; channelSelection.StateChanged += state => { @@ -186,13 +180,97 @@ namespace osu.Game.Overlays else textbox.HoldFocus = true; }; + channelSelection.OnRequestJoin = channel => + { + if (!chatManager.JoinedChannels.Contains(channel)) + chatManager.JoinedChannels.Add(channel); + }; + channelSelection.OnRequestLeave = channel => chatManager.JoinedChannels.Remove(channel); + } + + private void availableChannelsChanged(object sender, NotifyCollectionChangedEventArgs args) + { + channelSelection.Sections = new[] + { + new ChannelSection + { + Header = "All Channels", + Channels = chatManager.AvailableChannels, + }, + }; + } + + private void joinedChannelsChanged(object sender, NotifyCollectionChangedEventArgs args) + { + switch (args.Action) + { + case NotifyCollectionChangedAction.Add: + foreach (ChannelChat newChannel in args.NewItems) + { + channelTabs.AddItem(newChannel); + newChannel.Joined.Value = true; + if (chatManager.CurrentChat.Value == null) + { + chatManager.CurrentChat.Value = newChannel; + } + + } + break; + case NotifyCollectionChangedAction.Remove: + foreach (ChannelChat removedChannel in args.OldItems) + { + channelTabs.RemoveItem(removedChannel); + loadedChannels.Remove(loadedChannels.Find(c => c.Chat == removedChannel )); + removedChannel.Joined.Value = false; + if (chatManager.CurrentChat.Value == removedChannel) + chatManager.CurrentChat.Value = null; + } + break; + } + } + + private void currentChatChanged(ChatBase chat) + { + if (chat == null) + { + textbox.Current.Disabled = true; + currentChannelContainer.Clear(false); + return; + } + + textbox.Current.Disabled = chat.ReadOnly; + + if (chat is ChannelChat channelChat) + channelTabs.Current.Value = channelChat; + + var loaded = loadedChannels.Find(d => d.Chat == chat); + if (loaded == null) + { + currentChannelContainer.FadeOut(500, Easing.OutQuint); + loading.Show(); + + loaded = new DrawableChat(chat); + loadedChannels.Add(loaded); + LoadComponentAsync(loaded, l => + { + loading.Hide(); + + + currentChannelContainer.Clear(false); + currentChannelContainer.Add(loaded); + currentChannelContainer.FadeIn(500, Easing.OutQuint); + }); + } + else + { + currentChannelContainer.Clear(false); + currentChannelContainer.Add(loaded); + } } private double startDragChatHeight; private bool isDragging; - public void OpenChannel(ChannelChat channel) => addChannel(channel); - protected override bool OnDragStart(InputState state) { isDragging = tabsArea.IsHovered; @@ -229,19 +307,6 @@ namespace osu.Game.Overlays return base.OnDragEnd(state); } - public void APIStateChanged(APIAccess api, APIState state) - { - switch (state) - { - case APIState.Online: - initializeChannels(); - break; - default: - messageRequest?.Cancel(); - break; - } - } - public override bool AcceptsFocus => true; protected override void OnFocus(InputState state) @@ -270,10 +335,9 @@ namespace osu.Game.Overlays } [BackgroundDependencyLoader] - private void load(APIAccess api, OsuConfigManager config, OsuColour colours) + private void load(APIAccess api, OsuConfigManager config, OsuColour colours, ChatManager chatManager) { - this.api = api; - api.Register(this); + api.Register(chatManager); ChatHeight = config.GetBindable(OsuSetting.ChatDisplayHeight); ChatHeight.ValueChanged += h => @@ -285,253 +349,27 @@ namespace osu.Game.Overlays ChatHeight.TriggerChange(); chatBackground.Colour = colours.ChatBlue; - } - - private long? lastMessageId; - - private readonly List careChannels = new List(); - - private readonly List loadedChannels = new List(); - - private void initializeChannels() - { loading.Show(); - messageRequest?.Cancel(); - - ListChannelsRequest req = new ListChannelsRequest(); - req.Success += delegate (List channels) - { - AvailableChannels = channels; - - Scheduler.Add(delegate - { - 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; - channelSelection.Sections = new[] - { - new ChannelSection - { - Header = "All Channels", - Channels = channels, - }, - }; - }); - - messageRequest = Scheduler.AddDelayed(fetchNewMessages, 1000, true); - }; - - api.Queue(req); - } - - private ChannelChat currentChannel; - - protected ChannelChat CurrentChannel - { - get - { - return currentChannel; - } - - set - { - if (currentChannel == value) return; - - if (value == null) - { - currentChannel = null; - textbox.Current.Disabled = true; - currentChannelContainer.Clear(false); - return; - } - - currentChannel = value; - - textbox.Current.Disabled = currentChannel.ReadOnly; - channelTabs.Current.Value = value; - - var loaded = loadedChannels.Find(d => d.Channel == value); - if (loaded == null) - { - currentChannelContainer.FadeOut(500, Easing.OutQuint); - loading.Show(); - - loaded = new DrawableChannel(currentChannel); - loadedChannels.Add(loaded); - LoadComponentAsync(loaded, l => - { - if (currentChannel.Messages.Any()) - loading.Hide(); - - currentChannelContainer.Clear(false); - currentChannelContainer.Add(loaded); - currentChannelContainer.FadeIn(500, Easing.OutQuint); - }); - } - else - { - currentChannelContainer.Clear(false); - currentChannelContainer.Add(loaded); - } - } - } - - private void addChannel(ChannelChat channel) - { - if (channel == null) return; - - // ReSharper disable once AccessToModifiedClosure - var existing = careChannels.Find(c => c.Id == channel.Id); - - if (existing != null) - { - // if we already have this channel loaded, we don't want to make a second one. - channel = existing; - } - else - { - careChannels.Add(channel); - channelTabs.AddItem(channel); - } - - // let's fetch a small number of messages to bring us up-to-date with the backlog. - fetchInitialMessages(channel); - - if (CurrentChannel == null) - CurrentChannel = channel; - - channel.Joined.Value = true; - } - - private void removeChannel(ChannelChat channel) - { - if (channel == null) return; - - if (channel == CurrentChannel) CurrentChannel = null; - - careChannels.Remove(channel); - loadedChannels.Remove(loadedChannels.Find(c => c.Channel == channel)); - channelTabs.RemoveItem(channel); - - channel.Joined.Value = false; - } - - private void fetchInitialMessages(ChannelChat channel) - { - var req = new GetChannelMessagesRequest(new List { channel }, null); - - req.Success += delegate (List messages) - { - loading.Hide(); - channel.AddNewMessages(messages.ToArray()); - Debug.Write("success!"); - }; - req.Failure += delegate - { - Debug.Write("failure!"); - }; - - api.Queue(req); - } - - private void fetchNewMessages() - { - if (fetchReq != null) return; - - fetchReq = new GetChannelMessagesRequest(careChannels, lastMessageId); - - fetchReq.Success += delegate (List messages) - { - 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()); - - lastMessageId = messages.LastOrDefault()?.Id ?? lastMessageId; - - Debug.Write("success!"); - fetchReq = null; - }; - - fetchReq.Failure += delegate - { - Debug.Write("failure!"); - fetchReq = null; - }; - - api.Queue(fetchReq); + this.chatManager = chatManager; + chatManager.CurrentChat.ValueChanged += currentChatChanged; + chatManager.JoinedChannels.CollectionChanged += joinedChannelsChanged; + chatManager.AvailableChannels.CollectionChanged += availableChannelsChanged; } private void postMessage(TextBox textbox, bool newText) { - var postText = textbox.Text; + var text = textbox.Text.Trim(); + + if (string.IsNullOrWhiteSpace(text)) + return; + + if (text[0] == '/') + chatManager.PostCommand(text.Substring(1)); + else + chatManager.PostMessage(text); textbox.Text = string.Empty; - - if (string.IsNullOrWhiteSpace(postText)) - return; - - var target = currentChannel; - - if (target == null) return; - - if (!api.IsLoggedIn) - { - target.AddNewMessages(new ErrorMessage("Please sign in to participate in chat!")); - return; - } - - bool isAction = false; - - if (postText[0] == '/') - { - string[] parameters = postText.Substring(1).Split(new[] { ' ' }, 2); - string command = parameters[0]; - string content = parameters.Length == 2 ? parameters[1] : string.Empty; - - switch (command) - { - case "me": - - if (string.IsNullOrWhiteSpace(content)) - { - currentChannel.AddNewMessages(new ErrorMessage("Usage: /me [action]")); - return; - } - - isAction = true; - postText = content; - break; - - case "help": - currentChannel.AddNewMessages(new InfoMessage("Supported commands: /help, /me [action]")); - return; - - default: - currentChannel.AddNewMessages(new ErrorMessage($@"""/{command}"" is not supported! For a list of supported commands see /help")); - return; - } - } - - var message = new LocalEchoMessage - { - Sender = api.LocalUser.Value, - Timestamp = DateTimeOffset.Now, - TargetType = TargetType.Channel, //TODO: read this from channel - TargetId = target.Id, - IsAction = isAction, - Content = postText - }; - - var req = new PostMessageRequest(message); - - target.AddLocalEcho(message); - req.Failure += e => target.ReplaceMessage(message, null); - req.Success += m => target.ReplaceMessage(message, m); - - api.Queue(req); } private void transformChatHeightTo(double newChatHeight, double duration = 0, Easing easing = Easing.None) From a48ccb56038b0daf80fa76abd634b6b1915b10e9 Mon Sep 17 00:00:00 2001 From: miterosan Date: Sun, 8 Apr 2018 22:12:57 +0200 Subject: [PATCH 005/155] Implement Private chat --- .../API/Requests/GetUserMessagesRequest.cs | 30 +++ osu.Game/Online/Chat/ChatManager.cs | 79 ++++++- osu.Game/Online/Chat/UserChat.cs | 23 ++ osu.Game/OsuGame.cs | 1 - ...ChatTabControl.cs => ChannelTabControl.cs} | 11 +- .../Overlays/Chat/ChatTabItemCloseButton.cs | 55 +++++ osu.Game/Overlays/Chat/UserChatTabControl.cs | 51 +++++ osu.Game/Overlays/Chat/UserChatTabItem.cs | 201 ++++++++++++++++++ osu.Game/Overlays/ChatOverlay.cs | 37 +++- 9 files changed, 480 insertions(+), 8 deletions(-) create mode 100644 osu.Game/Online/API/Requests/GetUserMessagesRequest.cs create mode 100644 osu.Game/Online/Chat/UserChat.cs rename osu.Game/Overlays/Chat/{ChatTabControl.cs => ChannelTabControl.cs} (95%) create mode 100644 osu.Game/Overlays/Chat/ChatTabItemCloseButton.cs create mode 100644 osu.Game/Overlays/Chat/UserChatTabControl.cs create mode 100644 osu.Game/Overlays/Chat/UserChatTabItem.cs diff --git a/osu.Game/Online/API/Requests/GetUserMessagesRequest.cs b/osu.Game/Online/API/Requests/GetUserMessagesRequest.cs new file mode 100644 index 0000000000..ef9871c5d2 --- /dev/null +++ b/osu.Game/Online/API/Requests/GetUserMessagesRequest.cs @@ -0,0 +1,30 @@ +// 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 osu.Framework.IO.Network; +using osu.Game.Online.Chat; + +namespace osu.Game.Online.API.Requests +{ + public class GetUserMessagesRequest : APIRequest> + { + private long? since; + + public GetUserMessagesRequest(long? sinceId = null) + { + since = sinceId; + } + + protected override WebRequest CreateWebRequest() + { + var request = base.CreateWebRequest(); + if (since.HasValue) + request.AddParameter(@"since", since.Value.ToString()); + + return request; + } + + protected override string Target => @"chat/messages/private"; + } +} diff --git a/osu.Game/Online/Chat/ChatManager.cs b/osu.Game/Online/Chat/ChatManager.cs index 69620c8f53..f8c1e53ad8 100644 --- a/osu.Game/Online/Chat/ChatManager.cs +++ b/osu.Game/Online/Chat/ChatManager.cs @@ -11,6 +11,7 @@ using osu.Framework.Logging; using osu.Framework.Threading; using osu.Game.Online.API; using osu.Game.Online.API.Requests; +using osu.Game.Users; namespace osu.Game.Online.Chat { @@ -39,12 +40,18 @@ namespace osu.Game.Online.Chat /// The channels available for the player to join /// public ObservableCollection AvailableChannels { get; } = new ObservableCollection(); + /// + /// The user chats opened. + /// + public ObservableCollection OpenedUserChats { get; } = new ObservableCollection(); private APIAccess api; private readonly Scheduler scheduler; private ScheduledDelegate fetchMessagesScheduleder; private GetChannelMessagesRequest fetchChannelMsgReq; + private GetUserMessagesRequest fetchUserMsgReq; private long? lastChannelMsgId; + private long? lastUserMsgId; public ChatManager(Scheduler scheduler) { @@ -55,8 +62,7 @@ namespace osu.Game.Online.Chat private void currentChatChanged(ChatBase chatBase) { if (chatBase is ChannelChat channel && !JoinedChannels.Contains(channel)) - JoinedChannels.Add(channel); - + JoinedChannels.Add(channel); } /// @@ -127,6 +133,63 @@ namespace osu.Game.Online.Chat { if (fetchChannelMsgReq == null) fetchNewChannelMessages(); + + if (fetchUserMsgReq == null) + fetchNewUserMessages(); + } + + private void fetchNewUserMessages() + { + fetchUserMsgReq = new GetUserMessagesRequest(lastUserMsgId); + + fetchUserMsgReq.Success += messages => + { + handleUserMessages(messages); + lastUserMsgId = messages.LastOrDefault()?.Id ?? lastUserMsgId; + fetchUserMsgReq = null; + }; + fetchUserMsgReq.Failure += exception => Logger.Error(exception, "Fetching user messages failed."); + + api.Queue(fetchUserMsgReq); + } + + private void handleUserMessages(IEnumerable messages) + { + var outgoingMessages = messages.Where(m => m.Sender.Id == api.LocalUser.Value.Id); + var outgoingMessagesGroups = outgoingMessages.GroupBy(m => m.TargetId); + var incomingMessagesGroups = messages.Except(outgoingMessages).GroupBy(m => m.UserId); + + foreach (var messageGroup in incomingMessagesGroups) + { + var targetUser = messageGroup.First().Sender; + var chat = OpenedUserChats.FirstOrDefault(c => c.User.Id == targetUser.Id); + + if (chat == null) + { + chat = new UserChat(targetUser); + OpenedUserChats.Add(chat); + } + + chat.AddNewMessages(messageGroup.ToArray()); + var outgoingTargetMessages = outgoingMessagesGroups.FirstOrDefault(g => g.Key == targetUser.Id); + chat.AddNewMessages(outgoingTargetMessages.ToArray()); + } + + var withoutReplyGroups = outgoingMessagesGroups.Where(g => OpenedUserChats.All(m => m.ChatID != g.Key)); + + foreach (var withoutReplyGroup in withoutReplyGroups) + { + var getUserRequest = new GetUserRequest(withoutReplyGroup.First().TargetId); + getUserRequest.Success += user => + { + var chat = new UserChat(user); + + chat.AddNewMessages(withoutReplyGroup.ToArray()); + OpenedUserChats.Add(chat); + }; + + api.Queue(getUserRequest); + } } private void fetchNewChannelMessages() @@ -135,6 +198,8 @@ namespace osu.Game.Online.Chat fetchChannelMsgReq.Success += messages => { + if (messages == null) + return; handleChannelMessages(messages); lastChannelMsgId = messages.LastOrDefault()?.Id ?? lastChannelMsgId; fetchChannelMsgReq = null; @@ -163,7 +228,13 @@ namespace osu.Game.Online.Chat channels.Where(channel => defaultChannels.Contains(channel.Name)) .Where(channel => JoinedChannels.All(c => c.ChatID != channel.ChatID)) - .ForEach(channel => JoinedChannels.Add(channel)); + .ForEach(channel => + { + JoinedChannels.Add(channel); + var fetchInitialMsgReq = new GetChannelMessagesRequest(new[] {channel}, null); + fetchInitialMsgReq.Success += handleChannelMessages; + api.Queue(fetchInitialMsgReq); + }); fetchNewMessages(); }; @@ -185,7 +256,9 @@ namespace osu.Game.Online.Chat break; default: fetchChannelMsgReq?.Cancel(); + fetchChannelMsgReq = null; fetchMessagesScheduleder?.Cancel(); + break; } } diff --git a/osu.Game/Online/Chat/UserChat.cs b/osu.Game/Online/Chat/UserChat.cs new file mode 100644 index 0000000000..2cbb38dad8 --- /dev/null +++ b/osu.Game/Online/Chat/UserChat.cs @@ -0,0 +1,23 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using osu.Game.Users; + +namespace osu.Game.Online.Chat +{ + public class UserChat : ChatBase + { + public User User { get; } + + public UserChat(User user, Message[] messages = null) + { + User = user ?? throw new ArgumentNullException(nameof(user)); + + if (messages != null) AddNewMessages(messages); + } + + public override TargetType Target => TargetType.User; + public override long ChatID => User.Id; + } +} diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 1b55418c7b..cc942a1e32 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -29,7 +29,6 @@ using osu.Game.Overlays.Notifications; using osu.Game.Rulesets; using osu.Game.Screens.Play; using osu.Game.Input.Bindings; -using osu.Game.Online.Chat; using osu.Game.Rulesets.Mods; using osu.Game.Skinning; using OpenTK.Graphics; diff --git a/osu.Game/Overlays/Chat/ChatTabControl.cs b/osu.Game/Overlays/Chat/ChannelTabControl.cs similarity index 95% rename from osu.Game/Overlays/Chat/ChatTabControl.cs rename to osu.Game/Overlays/Chat/ChannelTabControl.cs index e495faf944..bf15aa51e9 100644 --- a/osu.Game/Overlays/Chat/ChatTabControl.cs +++ b/osu.Game/Overlays/Chat/ChannelTabControl.cs @@ -21,7 +21,7 @@ using osu.Game.Graphics.Containers; namespace osu.Game.Overlays.Chat { - public class ChatTabControl : OsuTabControl + public class ChannelTabControl : OsuTabControl { private const float shear_width = 10; @@ -31,7 +31,7 @@ namespace osu.Game.Overlays.Chat private readonly ChannelTabItem.ChannelSelectorTabItem selectorTab; - public ChatTabControl() + public ChannelTabControl() { TabContainer.Margin = new MarginPadding { Left = 50 }; TabContainer.Spacing = new Vector2(-shear_width, 0); @@ -51,6 +51,13 @@ namespace osu.Game.Overlays.Chat ChannelSelectorActive.BindTo(selectorTab.Active); } + public void DeselectAll() + { + if (SelectedTab != null) + SelectedTab.Active.Value = false; + SelectedTab = null; + } + protected override void AddTabItem(TabItem item, bool addToDropdown = true) { if (item != selectorTab && TabContainer.GetLayoutPosition(selectorTab) < float.MaxValue) diff --git a/osu.Game/Overlays/Chat/ChatTabItemCloseButton.cs b/osu.Game/Overlays/Chat/ChatTabItemCloseButton.cs new file mode 100644 index 0000000000..e87396356a --- /dev/null +++ b/osu.Game/Overlays/Chat/ChatTabItemCloseButton.cs @@ -0,0 +1,55 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics; +using osu.Framework.Input; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using OpenTK; +using OpenTK.Graphics; + +namespace osu.Game.Overlays.Chat +{ + public class ChatTabItemCloseButton : OsuClickableContainer + { + private readonly SpriteIcon icon; + + public ChatTabItemCloseButton() + { + Size = new Vector2(20); + + Child = icon = new SpriteIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Scale = new Vector2(0.75f), + Icon = FontAwesome.fa_close, + RelativeSizeAxes = Axes.Both, + }; + } + + protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) + { + icon.ScaleTo(0.5f, 1000, Easing.OutQuint); + return base.OnMouseDown(state, args); + } + + protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) + { + icon.ScaleTo(0.75f, 1000, Easing.OutElastic); + return base.OnMouseUp(state, args); + } + + protected override bool OnHover(InputState state) + { + icon.FadeColour(Color4.Red, 200, Easing.OutQuint); + return base.OnHover(state); + } + + protected override void OnHoverLost(InputState state) + { + icon.FadeColour(Color4.White, 200, Easing.OutQuint); + base.OnHoverLost(state); + } + } +} diff --git a/osu.Game/Overlays/Chat/UserChatTabControl.cs b/osu.Game/Overlays/Chat/UserChatTabControl.cs new file mode 100644 index 0000000000..73dee8f714 --- /dev/null +++ b/osu.Game/Overlays/Chat/UserChatTabControl.cs @@ -0,0 +1,51 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Graphics.UserInterface; +using osu.Game.Online.Chat; +using OpenTK; + +namespace osu.Game.Overlays.Chat +{ + public class UserChatTabControl : OsuTabControl + { + protected override TabItem CreateTabItem(UserChat value) => new UserChatTabItem(value) { OnRequestClose = tabCloseRequested }; + + public Action OnRequestLeave; + + public UserChatTabControl() + { + TabContainer.Spacing = new Vector2(-10, 0); + TabContainer.Masking = false; + } + + protected override void AddTabItem(TabItem item, bool addToDropdown = true) + { + base.AddTabItem(item, addToDropdown); + + if (SelectedTab == null) + SelectTab(item); + } + + private void tabCloseRequested(TabItem priv) + { + int totalTabs = TabContainer.Count -1; // account for selectorTab + int currentIndex = MathHelper.Clamp(TabContainer.IndexOf(priv), 1, totalTabs); + + if (priv == SelectedTab && totalTabs > 1) + // Select the tab after tab-to-be-removed's index, or the tab before if current == last + SelectTab(TabContainer[currentIndex == totalTabs ? currentIndex - 1 : currentIndex + 1]); + + OnRequestLeave?.Invoke(priv.Value); + } + + public void DeselectAll() + { + if (SelectedTab != null) + SelectedTab.Active.Value = false; + SelectedTab = null; + } + } +} diff --git a/osu.Game/Overlays/Chat/UserChatTabItem.cs b/osu.Game/Overlays/Chat/UserChatTabItem.cs new file mode 100644 index 0000000000..1426a1ac32 --- /dev/null +++ b/osu.Game/Overlays/Chat/UserChatTabItem.cs @@ -0,0 +1,201 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Online.Chat; +using osu.Game.Screens.Menu; +using osu.Game.Users; +using OpenTK; +using OpenTK.Graphics; + +namespace osu.Game.Overlays.Chat +{ + public class UserChatTabItem : TabItem + { + private static readonly Vector2 shear = new Vector2(1f / 5f, 0); + + public override bool IsRemovable => true; + + private readonly Box highlightBox; + private readonly Container backgroundContainer; + private readonly Box backgroundBox; + private readonly OsuSpriteText username; + private readonly ChatTabItemCloseButton closeButton; + + public UserChatTabItem(UserChat value) + : base(value) + { + AutoSizeAxes = Axes.X; + RelativeSizeAxes = Axes.Y; + Origin = Anchor.BottomRight; + Anchor = Anchor.BottomRight; + EdgeEffect = deactivateEdgeEffect; + Masking = false; + Shear = shear; + + Children = new Drawable[] + { + new Container() + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + backgroundBox = new Box + { + RelativeSizeAxes = Axes.Both, + Origin = Anchor.BottomLeft, + Anchor = Anchor.BottomLeft, + EdgeSmoothness = new Vector2(1, 0), + }, + } + }, + highlightBox = new Box + { + Width = 5, + BypassAutoSizeAxes = Axes.X, + Alpha = 0, + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + EdgeSmoothness = new Vector2(1, 0), + RelativeSizeAxes = Axes.Y, + Colour = new OsuColour().Yellow + }, + new Container + { + Masking = true, + AutoSizeAxes = Axes.X, + RelativeSizeAxes = Axes.Y, + Child = new FlowContainerWithOrigin + { + AutoSizeAxes = Axes.X, + RelativeSizeAxes = Axes.Y, + X = -5, + Direction = FillDirection.Horizontal, + Origin = Anchor.TopLeft, + Anchor = Anchor.TopLeft, + Shear = -shear, + + Children = new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + Margin = new MarginPadding + { + Horizontal = 5 + }, + Origin = Anchor.BottomLeft, + Anchor = Anchor.BottomLeft, + Children = new Drawable[] + { + + new SpriteIcon + { + Icon = FontAwesome.fa_eercast, + Origin = Anchor.Centre, + Scale = new Vector2(1.2f), + X = -5, + Y = 5, + Anchor = Anchor.Centre, + Colour = new OsuColour().BlueDarker, + RelativeSizeAxes = Axes.Both, + }, + new CircularContainer + { + RelativeSizeAxes = Axes.Y, + Scale = new Vector2(0.95f), + AutoSizeAxes = Axes.X, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Masking = true, + Child = new Avatar(value.User) + { + Size = new Vector2(ChatOverlay.TAB_AREA_HEIGHT), + } + }, + } + }, + username = new OsuSpriteText + { + Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreLeft, + Text = value.User.Username, + Margin = new MarginPadding(1), + TextSize = 18, + }, + closeButton = new ChatTabItemCloseButton + { + Height = 1, + Origin = Anchor.BottomLeft, + Anchor = Anchor.BottomLeft, + RelativeSizeAxes = Axes.Y, + + Action = delegate + { + if (IsRemovable) OnRequestClose?.Invoke(this); + }, + }, + } + } + } + }; + } + + public Action OnRequestClose; + + private readonly EdgeEffectParameters activateEdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Radius = 30, + Colour = Color4.Black.Opacity(0.3f), + }; + + protected override void OnActivated() + { + const int activate_length = 1000; + + backgroundBox.ResizeHeightTo(1.1f, activate_length, Easing.OutQuint); + highlightBox.ResizeHeightTo(1.1f, activate_length, Easing.OutQuint); + highlightBox.FadeIn(activate_length, Easing.OutQuint); + username.FadeIn(activate_length, Easing.OutQuint); + username.ScaleTo(new Vector2(1, 1), activate_length, Easing.OutQuint); + closeButton.ScaleTo(new Vector2(1, 1), activate_length, Easing.OutQuint); + closeButton.FadeIn(activate_length, Easing.OutQuint); + TweenEdgeEffectTo(activateEdgeEffect, activate_length); + } + + private readonly EdgeEffectParameters deactivateEdgeEffect = new EdgeEffectParameters + { + Colour = Color4.Black.Opacity(0.0f), + }; + + protected override void OnDeactivated() + { + const int deactivate_length = 500; + + backgroundBox.ResizeHeightTo(1, deactivate_length, Easing.OutQuint); + highlightBox.ResizeHeightTo(1, deactivate_length, Easing.OutQuint); + highlightBox.FadeOut(deactivate_length, Easing.OutQuint); + username.FadeOut(deactivate_length, Easing.OutQuint); + username.ScaleTo(new Vector2(0, 1), deactivate_length, Easing.OutQuint); + closeButton.FadeOut(deactivate_length, Easing.OutQuint); + closeButton.ScaleTo(new Vector2(0, 1), deactivate_length, Easing.OutQuint); + TweenEdgeEffectTo(deactivateEdgeEffect, deactivate_length); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + backgroundBox.Colour = Value.User.Colour != null ? OsuColour.FromHex(Value.User.Colour) : colours.BlueDark; + } + } +} diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 855a631f6b..251e4a2be0 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -45,7 +45,8 @@ namespace osu.Game.Overlays public const float TAB_AREA_HEIGHT = 50; - private readonly ChatTabControl channelTabs; + private readonly ChannelTabControl channelTabs; + private readonly UserChatTabControl userTabs; private readonly Container chatContainer; private readonly Container tabsArea; @@ -154,17 +155,23 @@ namespace osu.Game.Overlays RelativeSizeAxes = Axes.Both, Colour = Color4.Black, }, - channelTabs = new ChatTabControl + channelTabs = new ChannelTabControl { RelativeSizeAxes = Axes.Both, OnRequestLeave = channel => chatManager.JoinedChannels.Remove(channel), }, + userTabs = new UserChatTabControl + { + RelativeSizeAxes = Axes.Both, + OnRequestLeave = privateChat => chatManager.OpenedUserChats.Remove(privateChat), + } } }, }, }, }; + userTabs.Current.ValueChanged += user => chatManager.CurrentChat.Value = user; channelTabs.Current.ValueChanged += newChannel => chatManager.CurrentChat.Value = newChannel; channelTabs.ChannelSelectorActive.ValueChanged += value => channelSelection.State = value ? Visibility.Visible : Visibility.Hidden; channelSelection.StateChanged += state => @@ -241,7 +248,16 @@ namespace osu.Game.Overlays textbox.Current.Disabled = chat.ReadOnly; if (chat is ChannelChat channelChat) + { channelTabs.Current.Value = channelChat; + userTabs.DeselectAll(); + } + + if (chat is UserChat userChat) + { + userTabs.Current.Value = userChat; + channelTabs.DeselectAll(); + } var loaded = loadedChannels.Find(d => d.Chat == chat); if (loaded == null) @@ -355,6 +371,23 @@ namespace osu.Game.Overlays chatManager.CurrentChat.ValueChanged += currentChatChanged; chatManager.JoinedChannels.CollectionChanged += joinedChannelsChanged; chatManager.AvailableChannels.CollectionChanged += availableChannelsChanged; + chatManager.OpenedUserChats.CollectionChanged += openedUserChatsChanged; + } + + private void openedUserChatsChanged(object sender, NotifyCollectionChangedEventArgs args) + { + switch (args.Action) + { + case NotifyCollectionChangedAction.Add: + userTabs.AddItem(args.NewItems[0] as UserChat); + break; + case NotifyCollectionChangedAction.Remove: + userTabs.RemoveItem(args.OldItems[0] as UserChat); + break; + case NotifyCollectionChangedAction.Reset: + userTabs.Clear(); + break; + } } private void postMessage(TextBox textbox, bool newText) From 4b7ffd09d92b1829add2ba32e35ac49de43b7374 Mon Sep 17 00:00:00 2001 From: miterosan Date: Sun, 8 Apr 2018 22:18:29 +0200 Subject: [PATCH 006/155] Trim whitespace --- osu.Game/Online/Chat/ChatManager.cs | 2 +- osu.Game/Overlays/Chat/UserChatTabItem.cs | 2 +- osu.Game/Overlays/ChatOverlay.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Online/Chat/ChatManager.cs b/osu.Game/Online/Chat/ChatManager.cs index f8c1e53ad8..4001bbcf6f 100644 --- a/osu.Game/Online/Chat/ChatManager.cs +++ b/osu.Game/Online/Chat/ChatManager.cs @@ -61,7 +61,7 @@ namespace osu.Game.Online.Chat private void currentChatChanged(ChatBase chatBase) { - if (chatBase is ChannelChat channel && !JoinedChannels.Contains(channel)) + if (chatBase is ChannelChat channel && !JoinedChannels.Contains(channel)) JoinedChannels.Add(channel); } diff --git a/osu.Game/Overlays/Chat/UserChatTabItem.cs b/osu.Game/Overlays/Chat/UserChatTabItem.cs index 1426a1ac32..4169f5a77e 100644 --- a/osu.Game/Overlays/Chat/UserChatTabItem.cs +++ b/osu.Game/Overlays/Chat/UserChatTabItem.cs @@ -29,7 +29,7 @@ namespace osu.Game.Overlays.Chat private readonly Box backgroundBox; private readonly OsuSpriteText username; private readonly ChatTabItemCloseButton closeButton; - + public UserChatTabItem(UserChat value) : base(value) { diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 251e4a2be0..273a2ea926 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -220,7 +220,7 @@ namespace osu.Game.Overlays { chatManager.CurrentChat.Value = newChannel; } - + } break; case NotifyCollectionChangedAction.Remove: From 0a207e00d52f1068cd841d37f100152e0b047295 Mon Sep 17 00:00:00 2001 From: miterosan Date: Sun, 8 Apr 2018 22:24:55 +0200 Subject: [PATCH 007/155] Trim whilespace --- osu.Game/Online/Chat/ChatManager.cs | 2 +- osu.Game/Overlays/Chat/UserChatTabItem.cs | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/osu.Game/Online/Chat/ChatManager.cs b/osu.Game/Online/Chat/ChatManager.cs index 4001bbcf6f..9657ca3d96 100644 --- a/osu.Game/Online/Chat/ChatManager.cs +++ b/osu.Game/Online/Chat/ChatManager.cs @@ -62,7 +62,7 @@ namespace osu.Game.Online.Chat private void currentChatChanged(ChatBase chatBase) { if (chatBase is ChannelChat channel && !JoinedChannels.Contains(channel)) - JoinedChannels.Add(channel); + JoinedChannels.Add(channel); } /// diff --git a/osu.Game/Overlays/Chat/UserChatTabItem.cs b/osu.Game/Overlays/Chat/UserChatTabItem.cs index 4169f5a77e..8e6d06db46 100644 --- a/osu.Game/Overlays/Chat/UserChatTabItem.cs +++ b/osu.Game/Overlays/Chat/UserChatTabItem.cs @@ -40,7 +40,6 @@ namespace osu.Game.Overlays.Chat EdgeEffect = deactivateEdgeEffect; Masking = false; Shear = shear; - Children = new Drawable[] { new Container() @@ -82,7 +81,6 @@ namespace osu.Game.Overlays.Chat Origin = Anchor.TopLeft, Anchor = Anchor.TopLeft, Shear = -shear, - Children = new Drawable[] { new Container @@ -97,7 +95,6 @@ namespace osu.Game.Overlays.Chat Anchor = Anchor.BottomLeft, Children = new Drawable[] { - new SpriteIcon { Icon = FontAwesome.fa_eercast, @@ -138,13 +135,12 @@ namespace osu.Game.Overlays.Chat Origin = Anchor.BottomLeft, Anchor = Anchor.BottomLeft, RelativeSizeAxes = Axes.Y, - Action = delegate { if (IsRemovable) OnRequestClose?.Invoke(this); }, }, - } + } } } }; From 2a314f052a15410e5c3f8665eb2767d7d5764314 Mon Sep 17 00:00:00 2001 From: miterosan Date: Sun, 8 Apr 2018 22:28:50 +0200 Subject: [PATCH 008/155] Trim more whitespace --- osu.Game/Online/Chat/ChatManager.cs | 2 +- osu.Game/Overlays/ChatOverlay.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Online/Chat/ChatManager.cs b/osu.Game/Online/Chat/ChatManager.cs index 9657ca3d96..210a6cd43b 100644 --- a/osu.Game/Online/Chat/ChatManager.cs +++ b/osu.Game/Online/Chat/ChatManager.cs @@ -222,7 +222,7 @@ namespace osu.Game.Online.Chat var req = new ListChannelsRequest(); req.Success += channels => - { + { channels.Where(channel => AvailableChannels.All(c => c.ChatID != channel.ChatID)) .ForEach(channel => AvailableChannels.Add(channel)); diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 273a2ea926..bc6ec72e14 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -225,7 +225,7 @@ namespace osu.Game.Overlays break; case NotifyCollectionChangedAction.Remove: foreach (ChannelChat removedChannel in args.OldItems) - { + { channelTabs.RemoveItem(removedChannel); loadedChannels.Remove(loadedChannels.Find(c => c.Chat == removedChannel )); removedChannel.Joined.Value = false; @@ -371,7 +371,7 @@ namespace osu.Game.Overlays chatManager.CurrentChat.ValueChanged += currentChatChanged; chatManager.JoinedChannels.CollectionChanged += joinedChannelsChanged; chatManager.AvailableChannels.CollectionChanged += availableChannelsChanged; - chatManager.OpenedUserChats.CollectionChanged += openedUserChatsChanged; + chatManager.OpenedUserChats.CollectionChanged += openedUserChatsChanged; } private void openedUserChatsChanged(object sender, NotifyCollectionChangedEventArgs args) From aa26ea483d557287c2c6d9eddc4bbbf9fd25d801 Mon Sep 17 00:00:00 2001 From: miterosan Date: Sun, 8 Apr 2018 22:43:01 +0200 Subject: [PATCH 009/155] remove using, remove empty agrument list --- osu.Game/Online/Chat/ChatManager.cs | 1 - osu.Game/Overlays/Chat/UserChatTabItem.cs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Online/Chat/ChatManager.cs b/osu.Game/Online/Chat/ChatManager.cs index 210a6cd43b..dc7b8d129a 100644 --- a/osu.Game/Online/Chat/ChatManager.cs +++ b/osu.Game/Online/Chat/ChatManager.cs @@ -11,7 +11,6 @@ using osu.Framework.Logging; using osu.Framework.Threading; using osu.Game.Online.API; using osu.Game.Online.API.Requests; -using osu.Game.Users; namespace osu.Game.Online.Chat { diff --git a/osu.Game/Overlays/Chat/UserChatTabItem.cs b/osu.Game/Overlays/Chat/UserChatTabItem.cs index 8e6d06db46..9886a2ba3d 100644 --- a/osu.Game/Overlays/Chat/UserChatTabItem.cs +++ b/osu.Game/Overlays/Chat/UserChatTabItem.cs @@ -42,7 +42,7 @@ namespace osu.Game.Overlays.Chat Shear = shear; Children = new Drawable[] { - new Container() + new Container { RelativeSizeAxes = Axes.Both, Children = new Drawable[] From 5512d58c1d33b9b9dcb3e89a6eb3f0772330df51 Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 9 Apr 2018 21:06:05 +0200 Subject: [PATCH 010/155] Remove the sealed modifier --- osu.Game/Online/Chat/ChatManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/ChatManager.cs b/osu.Game/Online/Chat/ChatManager.cs index dc7b8d129a..50895287a8 100644 --- a/osu.Game/Online/Chat/ChatManager.cs +++ b/osu.Game/Online/Chat/ChatManager.cs @@ -17,7 +17,7 @@ namespace osu.Game.Online.Chat /// /// Manages everything chat related /// - public sealed class ChatManager : IOnlineComponent + public class ChatManager : IOnlineComponent { /// /// The channels the player joins on startup From 96bacaf13fae358d4d28b7702407faf89060c001 Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 9 Apr 2018 21:06:28 +0200 Subject: [PATCH 011/155] Allow the ChatLinkTestcase to work again --- osu.Game.Tests/Visual/TestCaseChatLink.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseChatLink.cs b/osu.Game.Tests/Visual/TestCaseChatLink.cs index 4f85779bce..6f57312d84 100644 --- a/osu.Game.Tests/Visual/TestCaseChatLink.cs +++ b/osu.Game.Tests/Visual/TestCaseChatLink.cs @@ -54,12 +54,14 @@ namespace osu.Game.Tests.Visual private void load(OsuColour colours, IAPIProvider api) { linkColour = colours.Blue; - dependencies.Cache(new ChatOverlay()); var chatManager = new ChatManager(Scheduler); - api.Register(chatManager); + chatManager.AvailableChannels.Add(new ChannelChat { Name = "#english"}); + chatManager.AvailableChannels.Add(new ChannelChat { Name = "#japanese" }); dependencies.Cache(chatManager); + dependencies.Cache(new ChatOverlay()); + testLinksGeneral(); testEcho(); } From 762b4412e5ed98f1eacfd26b49540cea51a711b1 Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 9 Apr 2018 22:29:48 +0200 Subject: [PATCH 012/155] Convert if to switch --- osu.Game/Overlays/ChatOverlay.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index bc6ec72e14..0935293058 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -247,16 +247,16 @@ namespace osu.Game.Overlays textbox.Current.Disabled = chat.ReadOnly; - if (chat is ChannelChat channelChat) + switch (chat) { - channelTabs.Current.Value = channelChat; - userTabs.DeselectAll(); - } - - if (chat is UserChat userChat) - { - userTabs.Current.Value = userChat; - channelTabs.DeselectAll(); + case ChannelChat channelChat: + channelTabs.Current.Value = channelChat; + userTabs.DeselectAll(); + break; + case UserChat userChat: + userTabs.Current.Value = userChat; + channelTabs.DeselectAll(); + break; } var loaded = loadedChannels.Find(d => d.Chat == chat); From 85f736ae893ab434d7c11ce224c2aa5b97bf19a5 Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 9 Apr 2018 23:14:39 +0200 Subject: [PATCH 013/155] Allow opening a new chat with right click on User Allow faster viewing of the usertab using lasy loading --- osu.Game/Online/Chat/ChatManager.cs | 56 ++++++++++++++++++----- osu.Game/Online/Chat/UserChat.cs | 25 ++++++++-- osu.Game/Overlays/Chat/ChatLine.cs | 7 ++- osu.Game/Overlays/Chat/UserChatTabItem.cs | 12 ++++- osu.Game/Overlays/ChatOverlay.cs | 29 ++++++------ 5 files changed, 96 insertions(+), 33 deletions(-) diff --git a/osu.Game/Online/Chat/ChatManager.cs b/osu.Game/Online/Chat/ChatManager.cs index 50895287a8..ba11ff9019 100644 --- a/osu.Game/Online/Chat/ChatManager.cs +++ b/osu.Game/Online/Chat/ChatManager.cs @@ -11,6 +11,7 @@ using osu.Framework.Logging; using osu.Framework.Threading; using osu.Game.Online.API; using osu.Game.Online.API.Requests; +using osu.Game.Users; namespace osu.Game.Online.Chat { @@ -52,6 +53,40 @@ namespace osu.Game.Online.Chat private long? lastChannelMsgId; private long? lastUserMsgId; + public void OpenChannelChat(string name) + { + if (name == null) + throw new ArgumentNullException(nameof(name)); + + CurrentChat.Value = AvailableChannels.FirstOrDefault(c => c.Name == name) + ?? throw new ArgumentException($"Channel {name} was not found."); + } + + public void OpenUserChat(long userId) + { + var chat = OpenedUserChats.FirstOrDefault(c => c.ChatID == userId); + + if (chat == null) + { + chat = new UserChat(new User + { + Id = userId + }); + chat.RequestDetails(api); + } + + CurrentChat.Value = chat; + } + + public void OpenUserChat(User user) + { + if (user == null) + throw new ArgumentNullException(nameof(user)); + + CurrentChat.Value = OpenedUserChats.FirstOrDefault(c => c.ChatID == user.Id) + ?? new UserChat(user); + } + public ChatManager(Scheduler scheduler) { this.scheduler = scheduler ?? throw new ArgumentNullException(nameof(scheduler)); @@ -62,6 +97,9 @@ namespace osu.Game.Online.Chat { if (chatBase is ChannelChat channel && !JoinedChannels.Contains(channel)) JoinedChannels.Add(channel); + + if (chatBase is UserChat userChat && !OpenedUserChats.Contains(userChat)) + OpenedUserChats.Add(userChat); } /// @@ -171,23 +209,19 @@ namespace osu.Game.Online.Chat chat.AddNewMessages(messageGroup.ToArray()); var outgoingTargetMessages = outgoingMessagesGroups.FirstOrDefault(g => g.Key == targetUser.Id); - chat.AddNewMessages(outgoingTargetMessages.ToArray()); + if (outgoingTargetMessages != null) + chat.AddNewMessages(outgoingTargetMessages.ToArray()); } var withoutReplyGroups = outgoingMessagesGroups.Where(g => OpenedUserChats.All(m => m.ChatID != g.Key)); foreach (var withoutReplyGroup in withoutReplyGroups) - { - var getUserRequest = new GetUserRequest(withoutReplyGroup.First().TargetId); - getUserRequest.Success += user => - { - var chat = new UserChat(user); + { + var chat = new UserChat(new User {Id = withoutReplyGroup.First().TargetId }); - chat.AddNewMessages(withoutReplyGroup.ToArray()); - OpenedUserChats.Add(chat); - }; - - api.Queue(getUserRequest); + chat.AddNewMessages(withoutReplyGroup.ToArray()); + OpenedUserChats.Add(chat); + chat.RequestDetails(api); } } diff --git a/osu.Game/Online/Chat/UserChat.cs b/osu.Game/Online/Chat/UserChat.cs index 2cbb38dad8..77d8b53214 100644 --- a/osu.Game/Online/Chat/UserChat.cs +++ b/osu.Game/Online/Chat/UserChat.cs @@ -2,13 +2,20 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using osu.Framework.Logging; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; using osu.Game.Users; namespace osu.Game.Online.Chat { public class UserChat : ChatBase { - public User User { get; } + public User User { get; private set; } + public override TargetType Target => TargetType.User; + public override long ChatID => User.Id; + + public Action DetailsArrived; public UserChat(User user, Message[] messages = null) { @@ -17,7 +24,19 @@ namespace osu.Game.Online.Chat if (messages != null) AddNewMessages(messages); } - public override TargetType Target => TargetType.User; - public override long ChatID => User.Id; + public void RequestDetails(IAPIProvider api) + { + if (api == null) + throw new ArgumentNullException(nameof(api)); + + var req = new GetUserRequest(User.Id); + req.Success += user => + { + User = user; + DetailsArrived?.Invoke(user); + }; + req.Failure += exception => Logger.Error(exception, $"Requesting details for user with Id:{User.Id} failed."); + api.Queue(req); + } } } diff --git a/osu.Game/Overlays/Chat/ChatLine.cs b/osu.Game/Overlays/Chat/ChatLine.cs index eb1ab9ef26..19ad452943 100644 --- a/osu.Game/Overlays/Chat/ChatLine.cs +++ b/osu.Game/Overlays/Chat/ChatLine.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 System.Linq; using OpenTK; using OpenTK.Graphics; @@ -236,20 +237,24 @@ namespace osu.Game.Overlays.Chat { private readonly User sender; + private Action startChatAction; + public MessageSender(User sender) { this.sender = sender; } [BackgroundDependencyLoader(true)] - private void load(UserProfileOverlay profile) + private void load(UserProfileOverlay profile, ChatManager chatManager) { Action = () => profile?.ShowUser(sender); + startChatAction = () => chatManager?.OpenUserChat(sender); } public MenuItem[] ContextMenuItems => new MenuItem[] { new OsuMenuItem("View Profile", MenuItemType.Highlighted, Action), + new OsuMenuItem("Start Chat", MenuItemType.Highlighted, startChatAction), }; } } diff --git a/osu.Game/Overlays/Chat/UserChatTabItem.cs b/osu.Game/Overlays/Chat/UserChatTabItem.cs index 9886a2ba3d..24a4c11784 100644 --- a/osu.Game/Overlays/Chat/UserChatTabItem.cs +++ b/osu.Game/Overlays/Chat/UserChatTabItem.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Online.API; using osu.Game.Online.Chat; using osu.Game.Screens.Menu; using osu.Game.Users; @@ -21,7 +22,7 @@ namespace osu.Game.Overlays.Chat public class UserChatTabItem : TabItem { private static readonly Vector2 shear = new Vector2(1f / 5f, 0); - + private readonly UserChat chat; public override bool IsRemovable => true; private readonly Box highlightBox; @@ -33,6 +34,7 @@ namespace osu.Game.Overlays.Chat public UserChatTabItem(UserChat value) : base(value) { + chat = value; AutoSizeAxes = Axes.X; RelativeSizeAxes = Axes.Y; Origin = Anchor.BottomRight; @@ -189,9 +191,15 @@ namespace osu.Game.Overlays.Chat } [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load(OsuColour colours, IAPIProvider api) { backgroundBox.Colour = Value.User.Colour != null ? OsuColour.FromHex(Value.User.Colour) : colours.BlueDark; + + if (chat.User.Username == null || chat.User.Id < 1) + { + chat.DetailsArrived += arrivedUser => { Scheduler.Add(() => { username.Text = arrivedUser.Username; }); }; + chat.RequestDetails(api); + } } } } diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 0935293058..bcda27e022 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -217,10 +217,10 @@ namespace osu.Game.Overlays channelTabs.AddItem(newChannel); newChannel.Joined.Value = true; if (chatManager.CurrentChat.Value == null) - { chatManager.CurrentChat.Value = newChannel; - } + if (chatManager.CurrentChat.Value == newChannel) + channelTabs.Current.Value = newChannel; } break; case NotifyCollectionChangedAction.Remove: @@ -247,17 +247,8 @@ namespace osu.Game.Overlays textbox.Current.Disabled = chat.ReadOnly; - switch (chat) - { - case ChannelChat channelChat: - channelTabs.Current.Value = channelChat; - userTabs.DeselectAll(); - break; - case UserChat userChat: - userTabs.Current.Value = userChat; - channelTabs.DeselectAll(); - break; - } + userTabs.DeselectAll(); + channelTabs.DeselectAll(); var loaded = loadedChannels.Find(d => d.Chat == chat); if (loaded == null) @@ -271,7 +262,6 @@ namespace osu.Game.Overlays { loading.Hide(); - currentChannelContainer.Clear(false); currentChannelContainer.Add(loaded); currentChannelContainer.FadeIn(500, Easing.OutQuint); @@ -379,10 +369,17 @@ namespace osu.Game.Overlays switch (args.Action) { case NotifyCollectionChangedAction.Add: - userTabs.AddItem(args.NewItems[0] as UserChat); + foreach (UserChat chat in args.NewItems) + { + userTabs.AddItem(args.NewItems[0] as UserChat); + + if (chatManager.CurrentChat.Value == chat) + userTabs.Current.Value = chat; + } break; case NotifyCollectionChangedAction.Remove: - userTabs.RemoveItem(args.OldItems[0] as UserChat); + foreach (UserChat chat in args.OldItems) + userTabs.RemoveItem(chat); break; case NotifyCollectionChangedAction.Reset: userTabs.Clear(); From 39ecc3d31d007cce178a86eb4ffa5c4b9979b1a3 Mon Sep 17 00:00:00 2001 From: miterosan Date: Wed, 11 Apr 2018 18:23:09 +0200 Subject: [PATCH 014/155] Add Test Case, improve displaying the avatar, use a chatTabControl instead of putting both in ChatOverlay, readd shadow. Requires osu-framework for a fix --- .../Visual/TestCaseChatTabControl.cs | 96 ++++++++++++++++++ osu.Game/Online/Chat/ChatManager.cs | 5 +- osu.Game/Online/Chat/UserChat.cs | 2 + osu.Game/Overlays/Chat/ChatTabControl.cs | 99 +++++++++++++++++++ osu.Game/Overlays/Chat/DrawableChat.cs | 2 +- ...serChatTabControl.cs => UserTabControl.cs} | 14 ++- .../{UserChatTabItem.cs => UserTabItem.cs} | 31 +++--- osu.Game/Overlays/ChatOverlay.cs | 69 ++++++------- 8 files changed, 263 insertions(+), 55 deletions(-) create mode 100644 osu.Game.Tests/Visual/TestCaseChatTabControl.cs create mode 100644 osu.Game/Overlays/Chat/ChatTabControl.cs rename osu.Game/Overlays/Chat/{UserChatTabControl.cs => UserTabControl.cs} (78%) rename osu.Game/Overlays/Chat/{UserChatTabItem.cs => UserTabItem.cs} (86%) diff --git a/osu.Game.Tests/Visual/TestCaseChatTabControl.cs b/osu.Game.Tests/Visual/TestCaseChatTabControl.cs new file mode 100644 index 0000000000..0b7a66ccf2 --- /dev/null +++ b/osu.Game.Tests/Visual/TestCaseChatTabControl.cs @@ -0,0 +1,96 @@ + +using System; +using System.Collections.Generic; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.MathUtils; +using osu.Game.Online.Chat; +using osu.Game.Overlays.Chat; +using osu.Game.Users; +using OpenTK.Graphics; + +namespace osu.Game.Tests.Visual +{ + public class TestCaseChatTabControl : OsuTestCase + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(ChatTabControl), + typeof(ChannelTabControl), + typeof(UserTabControl), + + }; + + private readonly ChatTabControl chatTabControl; + private readonly SpriteText currentText; + + public TestCaseChatTabControl() + { + Add(new Container + { + RelativeSizeAxes = Axes.X, + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Children = new Drawable[] + { + chatTabControl = new ChatTabControl + { + RelativeSizeAxes = Axes.X, + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Height = 50 + }, + new Box + { + Colour = Color4.Black.Opacity(0.1f), + RelativeSizeAxes = Axes.X, + Height = 50, + Depth = -1, + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + } + } + }); + + Add(new Container() + { + Origin = Anchor.TopLeft, + Anchor = Anchor.TopLeft, + Children = new Drawable[] + { + currentText = new SpriteText + { + Text = "Currently selected chat: " + } + } + }); + + chatTabControl.OnRequestLeave += chat => chatTabControl.RemoveItem(chat); + chatTabControl.Current.ValueChanged += chat => currentText.Text = "Currently selected chat: " + chat.ToString(); + + AddStep("Add random user", () => addUser(RNG.Next(100000), RNG.Next().ToString())); + AddRepeatStep("3 random users", () => addUser(RNG.Next(100000), RNG.Next().ToString()), 3); + AddStep("Add random channel", () => addChannel(RNG.Next().ToString())); + } + + private void addUser(long id, string name) + { + chatTabControl.AddItem(new UserChat(new User + { + Id = id, + Username = name + })); + } + + private void addChannel(string name) + { + this.chatTabControl.AddItem(new ChannelChat + { + Name = name + }); + } + } +} diff --git a/osu.Game/Online/Chat/ChatManager.cs b/osu.Game/Online/Chat/ChatManager.cs index ba11ff9019..ebfdbb3650 100644 --- a/osu.Game/Online/Chat/ChatManager.cs +++ b/osu.Game/Online/Chat/ChatManager.cs @@ -7,6 +7,7 @@ using System.Collections.ObjectModel; using System.Linq; using osu.Framework.Configuration; using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Framework.Graphics; using osu.Framework.Logging; using osu.Framework.Threading; using osu.Game.Online.API; @@ -18,7 +19,7 @@ namespace osu.Game.Online.Chat /// /// Manages everything chat related /// - public class ChatManager : IOnlineComponent + public class ChatManager : Component, IOnlineComponent { /// /// The channels the player joins on startup @@ -217,7 +218,7 @@ namespace osu.Game.Online.Chat foreach (var withoutReplyGroup in withoutReplyGroups) { - var chat = new UserChat(new User {Id = withoutReplyGroup.First().TargetId }); + var chat = new UserChat(new User { Id = withoutReplyGroup.First().TargetId }); chat.AddNewMessages(withoutReplyGroup.ToArray()); OpenedUserChats.Add(chat); diff --git a/osu.Game/Online/Chat/UserChat.cs b/osu.Game/Online/Chat/UserChat.cs index 77d8b53214..902d4eee11 100644 --- a/osu.Game/Online/Chat/UserChat.cs +++ b/osu.Game/Online/Chat/UserChat.cs @@ -38,5 +38,7 @@ namespace osu.Game.Online.Chat req.Failure += exception => Logger.Error(exception, $"Requesting details for user with Id:{User.Id} failed."); api.Queue(req); } + + public override string ToString() => User.Username ?? User.Id.ToString(); } } diff --git a/osu.Game/Overlays/Chat/ChatTabControl.cs b/osu.Game/Overlays/Chat/ChatTabControl.cs new file mode 100644 index 0000000000..8ec60d5e8d --- /dev/null +++ b/osu.Game/Overlays/Chat/ChatTabControl.cs @@ -0,0 +1,99 @@ +using System; +using osu.Framework.Configuration; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Online.Chat; + +namespace osu.Game.Overlays.Chat +{ + public class ChatTabControl : Container, IHasCurrentValue + { + public readonly ChannelTabControl channelTabControl; + private readonly UserTabControl userTabControl; + + public Bindable Current { get; } = new Bindable(); + public Action OnRequestLeave; + public Action OnRequestChannelSelection; + + public ChatTabControl() + { + Masking = false; + + Children = new Drawable[] + { + channelTabControl = new ChannelTabControl + { + Width = 0.5f, + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + RelativeSizeAxes = Axes.Both, + OnRequestLeave = chat => OnRequestLeave?.Invoke(chat) + }, + userTabControl = new UserTabControl + { + Width = 0.5f, + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + RelativeSizeAxes = Axes.Both, + OnRequestLeave = chat => OnRequestLeave?.Invoke(chat) + }, + }; + + Current.ValueChanged += currentTabChanged; + channelTabControl.Current.ValueChanged += chat => + { + if (chat != null) + Current.Value = chat; + }; + userTabControl.Current.ValueChanged += chat => + { + if (chat != null) + Current.Value = chat; + }; + } + + private void currentTabChanged(ChatBase tab) + { + switch (tab) + { + case UserChat userChat: + userTabControl.Current.Value = userChat; + channelTabControl.Current.Value = null; + break; + case ChannelChat channelChat: + channelTabControl.Current.Value = channelChat; + userTabControl.Current.Value = null; + break; + } + } + + public void AddItem(ChatBase chat) + { + switch (chat) + { + case UserChat userChat: + userTabControl.AddItem(userChat); + break; + case ChannelChat channelChat: + channelTabControl.AddItem(channelChat); + break; + } + } + + public void RemoveItem(ChatBase chat) + { + switch (chat) + { + case UserChat userChat: + userTabControl.RemoveItem(userChat); + Current.Value = null; + break; + case ChannelChat channelChat: + channelTabControl.RemoveItem(channelChat); + Current.Value = null; + break; + } + } + } +} diff --git a/osu.Game/Overlays/Chat/DrawableChat.cs b/osu.Game/Overlays/Chat/DrawableChat.cs index 0efcf1ac00..4ebdc4bd31 100644 --- a/osu.Game/Overlays/Chat/DrawableChat.cs +++ b/osu.Game/Overlays/Chat/DrawableChat.cs @@ -58,7 +58,7 @@ namespace osu.Game.Overlays.Chat [BackgroundDependencyLoader] private void load() { - newMessagesArrived(Chat.Messages); + Scheduler.Add(() => newMessagesArrived(Chat.Messages)); } protected override void LoadComplete() diff --git a/osu.Game/Overlays/Chat/UserChatTabControl.cs b/osu.Game/Overlays/Chat/UserTabControl.cs similarity index 78% rename from osu.Game/Overlays/Chat/UserChatTabControl.cs rename to osu.Game/Overlays/Chat/UserTabControl.cs index 73dee8f714..cf1caaf4df 100644 --- a/osu.Game/Overlays/Chat/UserChatTabControl.cs +++ b/osu.Game/Overlays/Chat/UserTabControl.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using osu.Framework.Graphics; using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics.UserInterface; using osu.Game.Online.Chat; @@ -9,16 +10,22 @@ using OpenTK; namespace osu.Game.Overlays.Chat { - public class UserChatTabControl : OsuTabControl + public class UserTabControl : OsuTabControl { - protected override TabItem CreateTabItem(UserChat value) => new UserChatTabItem(value) { OnRequestClose = tabCloseRequested }; + protected override TabItem CreateTabItem(UserChat value) => new UserTabItem(value) { OnRequestClose = tabCloseRequested }; + + protected override Dropdown CreateDropdown() => null; public Action OnRequestLeave; - public UserChatTabControl() + public UserTabControl() { TabContainer.Spacing = new Vector2(-10, 0); TabContainer.Masking = false; + Margin = new MarginPadding + { + Right = 10 + }; } protected override void AddTabItem(TabItem item, bool addToDropdown = true) @@ -46,6 +53,7 @@ namespace osu.Game.Overlays.Chat if (SelectedTab != null) SelectedTab.Active.Value = false; SelectedTab = null; + } } } diff --git a/osu.Game/Overlays/Chat/UserChatTabItem.cs b/osu.Game/Overlays/Chat/UserTabItem.cs similarity index 86% rename from osu.Game/Overlays/Chat/UserChatTabItem.cs rename to osu.Game/Overlays/Chat/UserTabItem.cs index 24a4c11784..e8031d60b9 100644 --- a/osu.Game/Overlays/Chat/UserChatTabItem.cs +++ b/osu.Game/Overlays/Chat/UserTabItem.cs @@ -19,7 +19,7 @@ using OpenTK.Graphics; namespace osu.Game.Overlays.Chat { - public class UserChatTabItem : TabItem + public class UserTabItem : TabItem { private static readonly Vector2 shear = new Vector2(1f / 5f, 0); private readonly UserChat chat; @@ -29,18 +29,19 @@ namespace osu.Game.Overlays.Chat private readonly Container backgroundContainer; private readonly Box backgroundBox; private readonly OsuSpriteText username; + private readonly Avatar avatarContainer; private readonly ChatTabItemCloseButton closeButton; - public UserChatTabItem(UserChat value) + public UserTabItem(UserChat value) : base(value) { chat = value; AutoSizeAxes = Axes.X; - RelativeSizeAxes = Axes.Y; + Height = 50; Origin = Anchor.BottomRight; Anchor = Anchor.BottomRight; - EdgeEffect = deactivateEdgeEffect; - Masking = false; + EdgeEffect = activateEdgeEffect; + Masking = true; Shear = shear; Children = new Drawable[] { @@ -116,7 +117,11 @@ namespace osu.Game.Overlays.Chat Anchor = Anchor.Centre, Origin = Anchor.Centre, Masking = true, - Child = new Avatar(value.User) + Child = new DelayedLoadWrapper(new Avatar(value.User) + { + Size = new Vector2(ChatOverlay.TAB_AREA_HEIGHT), + OnLoadComplete = d => d.FadeInFromZero(300, Easing.OutQuint), + }) { Size = new Vector2(ChatOverlay.TAB_AREA_HEIGHT), } @@ -136,6 +141,10 @@ namespace osu.Game.Overlays.Chat Height = 1, Origin = Anchor.BottomLeft, Anchor = Anchor.BottomLeft, + Margin = new MarginPadding + { + Right = 5 + }, RelativeSizeAxes = Axes.Y, Action = delegate { @@ -148,13 +157,13 @@ namespace osu.Game.Overlays.Chat }; } - public Action OnRequestClose; + public Action OnRequestClose; private readonly EdgeEffectParameters activateEdgeEffect = new EdgeEffectParameters { Type = EdgeEffectType.Shadow, - Radius = 30, - Colour = Color4.Black.Opacity(0.3f), + Radius = 15, + Colour = Color4.Black.Opacity(0.4f), }; protected override void OnActivated() @@ -168,7 +177,7 @@ namespace osu.Game.Overlays.Chat username.ScaleTo(new Vector2(1, 1), activate_length, Easing.OutQuint); closeButton.ScaleTo(new Vector2(1, 1), activate_length, Easing.OutQuint); closeButton.FadeIn(activate_length, Easing.OutQuint); - TweenEdgeEffectTo(activateEdgeEffect, activate_length); + // TweenEdgeEffectTo(activateEdgeEffect, activate_length); } private readonly EdgeEffectParameters deactivateEdgeEffect = new EdgeEffectParameters @@ -187,7 +196,7 @@ namespace osu.Game.Overlays.Chat username.ScaleTo(new Vector2(0, 1), deactivate_length, Easing.OutQuint); closeButton.FadeOut(deactivate_length, Easing.OutQuint); closeButton.ScaleTo(new Vector2(0, 1), deactivate_length, Easing.OutQuint); - TweenEdgeEffectTo(deactivateEdgeEffect, deactivate_length); + // TweenEdgeEffectTo(deactivateEdgeEffect, deactivate_length); } [BackgroundDependencyLoader] diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index bcda27e022..801cb894d4 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -32,7 +32,7 @@ namespace osu.Game.Overlays private ChatManager chatManager; - private readonly Container currentChannelContainer; + private readonly Container currentChatContainer; private readonly List loadedChannels = new List(); private readonly LoadingAnimation loading; @@ -45,8 +45,7 @@ namespace osu.Game.Overlays public const float TAB_AREA_HEIGHT = 50; - private readonly ChannelTabControl channelTabs; - private readonly UserChatTabControl userTabs; + private readonly ChatTabControl chatTabControl; private readonly Container chatContainer; private readonly Container tabsArea; @@ -105,7 +104,7 @@ namespace osu.Game.Overlays { RelativeSizeAxes = Axes.Both, }, - currentChannelContainer = new Container + currentChatContainer = new Container { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding @@ -155,15 +154,16 @@ namespace osu.Game.Overlays RelativeSizeAxes = Axes.Both, Colour = Color4.Black, }, - channelTabs = new ChannelTabControl + chatTabControl = new ChatTabControl { RelativeSizeAxes = Axes.Both, - OnRequestLeave = channel => chatManager.JoinedChannels.Remove(channel), - }, - userTabs = new UserChatTabControl - { - RelativeSizeAxes = Axes.Both, - OnRequestLeave = privateChat => chatManager.OpenedUserChats.Remove(privateChat), + OnRequestLeave = chat => + { + if (chat is ChannelChat channelChat) + chatManager.JoinedChannels.Remove(channelChat); + if (chat is UserChat userChat) + chatManager.OpenedUserChats.Remove(userChat); + } } } }, @@ -171,12 +171,11 @@ namespace osu.Game.Overlays }, }; - userTabs.Current.ValueChanged += user => chatManager.CurrentChat.Value = user; - channelTabs.Current.ValueChanged += newChannel => chatManager.CurrentChat.Value = newChannel; - channelTabs.ChannelSelectorActive.ValueChanged += value => channelSelection.State = value ? Visibility.Visible : Visibility.Hidden; + chatTabControl.Current.ValueChanged += chat => chatManager.CurrentChat.Value = chat; + chatTabControl.channelTabControl.ChannelSelectorActive.ValueChanged += value => channelSelection.State = value ? Visibility.Visible : Visibility.Hidden; channelSelection.StateChanged += state => { - channelTabs.ChannelSelectorActive.Value = state == Visibility.Visible; + chatTabControl.channelTabControl.ChannelSelectorActive.Value = state == Visibility.Visible; if (state == Visibility.Visible) { @@ -214,19 +213,16 @@ namespace osu.Game.Overlays case NotifyCollectionChangedAction.Add: foreach (ChannelChat newChannel in args.NewItems) { - channelTabs.AddItem(newChannel); + chatTabControl.AddItem(newChannel); newChannel.Joined.Value = true; - if (chatManager.CurrentChat.Value == null) - chatManager.CurrentChat.Value = newChannel; - - if (chatManager.CurrentChat.Value == newChannel) - channelTabs.Current.Value = newChannel; + //if (chatManager.CurrentChat.Value == null) + // chatManager.CurrentChat.Value = newChannel; } break; case NotifyCollectionChangedAction.Remove: foreach (ChannelChat removedChannel in args.OldItems) { - channelTabs.RemoveItem(removedChannel); + chatTabControl.RemoveItem(removedChannel); loadedChannels.Remove(loadedChannels.Find(c => c.Chat == removedChannel )); removedChannel.Joined.Value = false; if (chatManager.CurrentChat.Value == removedChannel) @@ -241,19 +237,19 @@ namespace osu.Game.Overlays if (chat == null) { textbox.Current.Disabled = true; - currentChannelContainer.Clear(false); + currentChatContainer.Clear(false); + chatTabControl.Current.Value = null; return; } textbox.Current.Disabled = chat.ReadOnly; - - userTabs.DeselectAll(); - channelTabs.DeselectAll(); + + Scheduler.Add(() => chatTabControl.Current.Value = chat); var loaded = loadedChannels.Find(d => d.Chat == chat); if (loaded == null) { - currentChannelContainer.FadeOut(500, Easing.OutQuint); + currentChatContainer.FadeOut(500, Easing.OutQuint); loading.Show(); loaded = new DrawableChat(chat); @@ -262,15 +258,15 @@ namespace osu.Game.Overlays { loading.Hide(); - currentChannelContainer.Clear(false); - currentChannelContainer.Add(loaded); - currentChannelContainer.FadeIn(500, Easing.OutQuint); + currentChatContainer.Clear(false); + currentChatContainer.Add(loaded); + currentChatContainer.FadeIn(500, Easing.OutQuint); }); } else { - currentChannelContainer.Clear(false); - currentChannelContainer.Add(loaded); + currentChatContainer.Clear(false); + currentChatContainer.Add(loaded); } } @@ -371,18 +367,15 @@ namespace osu.Game.Overlays case NotifyCollectionChangedAction.Add: foreach (UserChat chat in args.NewItems) { - userTabs.AddItem(args.NewItems[0] as UserChat); + chatTabControl.AddItem(args.NewItems[0] as UserChat); if (chatManager.CurrentChat.Value == chat) - userTabs.Current.Value = chat; + chatTabControl.Current.Value = chat; } break; case NotifyCollectionChangedAction.Remove: foreach (UserChat chat in args.OldItems) - userTabs.RemoveItem(chat); - break; - case NotifyCollectionChangedAction.Reset: - userTabs.Clear(); + chatTabControl.RemoveItem(chat); break; } } From 3860594f40973f704077b5ce92fe3726f13899f1 Mon Sep 17 00:00:00 2001 From: miterosan Date: Wed, 11 Apr 2018 20:01:57 +0200 Subject: [PATCH 015/155] Rename everything into channel and remove everything chat --- osu.Game.Tests/Visual/TestCaseChatLink.cs | 6 +- .../Visual/TestCaseChatTabControl.cs | 4 +- .../Graphics/Containers/LinkFlowContainer.cs | 6 +- .../API/Requests/GetChannelMessagesRequest.cs | 10 +- .../API/Requests/ListChannelsRequest.cs | 2 +- .../Online/Chat/{ChatBase.cs => Channel.cs} | 68 +++++++--- osu.Game/Online/Chat/ChannelChat.cs | 31 ----- .../{ChatManager.cs => ChannelManager.cs} | 119 ++++++++---------- osu.Game/Online/Chat/UserChat.cs | 44 ------- osu.Game/OsuGameBase.cs | 2 +- osu.Game/Overlays/Chat/ChannelListItem.cs | 8 +- osu.Game/Overlays/Chat/ChannelSection.cs | 2 +- .../Overlays/Chat/ChannelSelectionOverlay.cs | 4 +- osu.Game/Overlays/Chat/ChannelTabControl.cs | 27 ++-- osu.Game/Overlays/Chat/ChatLine.cs | 8 +- osu.Game/Overlays/Chat/ChatTabControl.cs | 80 ++++++------ osu.Game/Overlays/Chat/DrawableChat.cs | 8 +- osu.Game/Overlays/Chat/UserTabControl.cs | 25 ++-- osu.Game/Overlays/Chat/UserTabItem.cs | 32 ++--- osu.Game/Overlays/ChatOverlay.cs | 56 ++------- 20 files changed, 232 insertions(+), 310 deletions(-) rename osu.Game/Online/Chat/{ChatBase.cs => Channel.cs} (64%) delete mode 100644 osu.Game/Online/Chat/ChannelChat.cs rename osu.Game/Online/Chat/{ChatManager.cs => ChannelManager.cs} (67%) delete mode 100644 osu.Game/Online/Chat/UserChat.cs diff --git a/osu.Game.Tests/Visual/TestCaseChatLink.cs b/osu.Game.Tests/Visual/TestCaseChatLink.cs index 6f57312d84..66a28c5ee8 100644 --- a/osu.Game.Tests/Visual/TestCaseChatLink.cs +++ b/osu.Game.Tests/Visual/TestCaseChatLink.cs @@ -55,9 +55,9 @@ namespace osu.Game.Tests.Visual { linkColour = colours.Blue; - var chatManager = new ChatManager(Scheduler); - chatManager.AvailableChannels.Add(new ChannelChat { Name = "#english"}); - chatManager.AvailableChannels.Add(new ChannelChat { Name = "#japanese" }); + var chatManager = new ChannelManager(Scheduler); + chatManager.AvailableChannels.Add(new Channel { Name = "#english"}); + chatManager.AvailableChannels.Add(new Channel { Name = "#japanese" }); dependencies.Cache(chatManager); dependencies.Cache(new ChatOverlay()); diff --git a/osu.Game.Tests/Visual/TestCaseChatTabControl.cs b/osu.Game.Tests/Visual/TestCaseChatTabControl.cs index 0b7a66ccf2..ae7c6e2751 100644 --- a/osu.Game.Tests/Visual/TestCaseChatTabControl.cs +++ b/osu.Game.Tests/Visual/TestCaseChatTabControl.cs @@ -78,7 +78,7 @@ namespace osu.Game.Tests.Visual private void addUser(long id, string name) { - chatTabControl.AddItem(new UserChat(new User + chatTabControl.AddItem(new Channel(new User { Id = id, Username = name @@ -87,7 +87,7 @@ namespace osu.Game.Tests.Visual private void addChannel(string name) { - this.chatTabControl.AddItem(new ChannelChat + this.chatTabControl.AddItem(new Channel { Name = name }); diff --git a/osu.Game/Graphics/Containers/LinkFlowContainer.cs b/osu.Game/Graphics/Containers/LinkFlowContainer.cs index 627efbda76..aee2eb4597 100644 --- a/osu.Game/Graphics/Containers/LinkFlowContainer.cs +++ b/osu.Game/Graphics/Containers/LinkFlowContainer.cs @@ -23,11 +23,11 @@ namespace osu.Game.Graphics.Containers public override bool HandleMouseInput => true; private OsuGame game; - private ChatManager chatManager; + private ChannelManager chatManager; private Action showNotImplementedError; [BackgroundDependencyLoader(true)] - private void load(OsuGame game, NotificationOverlay notifications, ChatManager chatManager) + private void load(OsuGame game, NotificationOverlay notifications, ChannelManager chatManager) { // will be null in tests this.game = game; @@ -82,7 +82,7 @@ namespace osu.Game.Graphics.Containers case LinkAction.OpenChannel: var channel = chatManager.AvailableChannels.FirstOrDefault(c => c.Name == linkArgument); if (channel != null) - chatManager.CurrentChat.Value = channel; + chatManager.CurrentChannel.Value = channel; break; case LinkAction.OpenEditorTimestamp: case LinkAction.JoinMultiplayerMatch: diff --git a/osu.Game/Online/API/Requests/GetChannelMessagesRequest.cs b/osu.Game/Online/API/Requests/GetChannelMessagesRequest.cs index d463af6c25..c323cf0ff8 100644 --- a/osu.Game/Online/API/Requests/GetChannelMessagesRequest.cs +++ b/osu.Game/Online/API/Requests/GetChannelMessagesRequest.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 System.Collections.Generic; using System.Linq; using osu.Framework.IO.Network; @@ -10,11 +11,16 @@ namespace osu.Game.Online.API.Requests { public class GetChannelMessagesRequest : APIRequest> { - private readonly IEnumerable channels; + private readonly IEnumerable channels; private long? since; - public GetChannelMessagesRequest(IEnumerable channels, long? sinceId) + public GetChannelMessagesRequest(IEnumerable channels, long? sinceId) { + if (channels == null) + throw new ArgumentNullException(nameof(channels)); + if (channels.Any(c => c.Target != TargetType.Channel)) + throw new ArgumentException("All channels in the argument channels must have the targettype Channel"); + this.channels = channels; since = sinceId; } diff --git a/osu.Game/Online/API/Requests/ListChannelsRequest.cs b/osu.Game/Online/API/Requests/ListChannelsRequest.cs index 97ed3d3cbc..b387af9694 100644 --- a/osu.Game/Online/API/Requests/ListChannelsRequest.cs +++ b/osu.Game/Online/API/Requests/ListChannelsRequest.cs @@ -6,7 +6,7 @@ using osu.Game.Online.Chat; namespace osu.Game.Online.API.Requests { - public class ListChannelsRequest : APIRequest> + public class ListChannelsRequest : APIRequest> { protected override string Target => @"chat/channels"; } diff --git a/osu.Game/Online/Chat/ChatBase.cs b/osu.Game/Online/Chat/Channel.cs similarity index 64% rename from osu.Game/Online/Chat/ChatBase.cs rename to osu.Game/Online/Chat/Channel.cs index 969d2c0f1f..fdaa690e9a 100644 --- a/osu.Game/Online/Chat/ChatBase.cs +++ b/osu.Game/Online/Chat/Channel.cs @@ -1,22 +1,55 @@ -// 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; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Linq; +using Newtonsoft.Json; using osu.Framework.Configuration; using osu.Framework.Lists; +using osu.Game.Users; namespace osu.Game.Online.Chat { - public abstract class ChatBase + public class Channel { public const int MAX_HISTORY = 300; - public bool ReadOnly { get; } = false; - public abstract TargetType Target { get; } - public abstract long ChatID { get; } - public Bindable Joined = new Bindable(); + [JsonProperty(@"name")] + public string Name; + + [JsonProperty(@"description")] + public string Topic; + + [JsonProperty(@"type")] + public string Type; + + [JsonProperty(@"channel_id")] + public long Id; + + [JsonConstructor] + public Channel() + { + } + + /// + /// Contructs a privatechannel + /// TODO this class needs to be serialized from something like channels/private, instead of creating from a contructor + /// + /// The user + public Channel(User user) + { + Target = TargetType.User; + Name = user.Username; + Id = user.Id; + JoinedUsers.Add(user); + } + + /// + /// Contains every joined user except yourself + /// + public ObservableCollection JoinedUsers = new ObservableCollection(); public readonly SortedList Messages = new SortedList(Comparer.Default); private readonly List pendingMessages = new List(); @@ -24,6 +57,10 @@ namespace osu.Game.Online.Chat public event Action PendingMessageResolved; public event Action MessageRemoved; + public Bindable Joined = new Bindable(); + public TargetType Target { get; set; } + public bool ReadOnly { get; set; } + public void AddLocalEcho(LocalEchoMessage message) { pendingMessages.Add(message); @@ -43,16 +80,8 @@ namespace osu.Game.Online.Chat NewMessagesArrived?.Invoke(messages); } - private void purgeOldMessages() - { - // never purge local echos - int messageCount = Messages.Count - pendingMessages.Count; - if (messageCount > MAX_HISTORY) - Messages.RemoveRange(0, messageCount - MAX_HISTORY); - } - /// - /// Replace or remove a message from the chat. + /// Replace or remove a message from the channel. /// /// The local echo message (client-side). /// The response message, or null if the message became invalid. @@ -81,5 +110,14 @@ namespace osu.Game.Online.Chat PendingMessageResolved?.Invoke(echo, final); } + private void purgeOldMessages() + { + // never purge local echos + int messageCount = Messages.Count - pendingMessages.Count; + if (messageCount > MAX_HISTORY) + Messages.RemoveRange(0, messageCount - MAX_HISTORY); + } + + public override string ToString() => Name; } } diff --git a/osu.Game/Online/Chat/ChannelChat.cs b/osu.Game/Online/Chat/ChannelChat.cs deleted file mode 100644 index fb24806294..0000000000 --- a/osu.Game/Online/Chat/ChannelChat.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using Newtonsoft.Json; - -namespace osu.Game.Online.Chat -{ - public class ChannelChat : ChatBase - { - [JsonProperty(@"name")] - public string Name; - - [JsonProperty(@"description")] - public string Topic; - - [JsonProperty(@"type")] - public string Type; - - [JsonProperty(@"channel_id")] - public int Id; - - [JsonConstructor] - public ChannelChat() - { - } - - public override string ToString() => Name; - public override long ChatID => Id; - public override TargetType Target => TargetType.Channel; - } -} diff --git a/osu.Game/Online/Chat/ChatManager.cs b/osu.Game/Online/Chat/ChannelManager.cs similarity index 67% rename from osu.Game/Online/Chat/ChatManager.cs rename to osu.Game/Online/Chat/ChannelManager.cs index ebfdbb3650..e7ffb60f04 100644 --- a/osu.Game/Online/Chat/ChatManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -17,9 +17,9 @@ using osu.Game.Users; namespace osu.Game.Online.Chat { /// - /// Manages everything chat related + /// Manages everything channel related /// - public class ChatManager : Component, IOnlineComponent + public class ChannelManager : Component, IOnlineComponent { /// /// The channels the player joins on startup @@ -30,21 +30,17 @@ namespace osu.Game.Online.Chat }; /// - /// The currently opened chat + /// The currently opened channel /// - public Bindable CurrentChat { get; } = new Bindable(); + public Bindable CurrentChannel { get; } = new Bindable(); /// /// The Channels the player has joined /// - public ObservableCollection JoinedChannels { get; } = new ObservableCollection(); + public ObservableCollection JoinedChannels { get; } = new ObservableCollection(); /// /// The channels available for the player to join /// - public ObservableCollection AvailableChannels { get; } = new ObservableCollection(); - /// - /// The user chats opened. - /// - public ObservableCollection OpenedUserChats { get; } = new ObservableCollection(); + public ObservableCollection AvailableChannels { get; } = new ObservableCollection(); private APIAccess api; private readonly Scheduler scheduler; @@ -54,68 +50,49 @@ namespace osu.Game.Online.Chat private long? lastChannelMsgId; private long? lastUserMsgId; - public void OpenChannelChat(string name) + public void OpenChannel(string name) { if (name == null) throw new ArgumentNullException(nameof(name)); - CurrentChat.Value = AvailableChannels.FirstOrDefault(c => c.Name == name) + CurrentChannel.Value = AvailableChannels.FirstOrDefault(c => c.Name == name) ?? throw new ArgumentException($"Channel {name} was not found."); } - public void OpenUserChat(long userId) - { - var chat = OpenedUserChats.FirstOrDefault(c => c.ChatID == userId); - - if (chat == null) - { - chat = new UserChat(new User - { - Id = userId - }); - chat.RequestDetails(api); - } - - CurrentChat.Value = chat; - } - - public void OpenUserChat(User user) + public void OpenUserChannel(User user) { if (user == null) throw new ArgumentNullException(nameof(user)); - CurrentChat.Value = OpenedUserChats.FirstOrDefault(c => c.ChatID == user.Id) - ?? new UserChat(user); + CurrentChannel.Value = JoinedChannels.FirstOrDefault(c => c.Target == TargetType.User && c.Id == user.Id) + ?? new Channel(user); } - public ChatManager(Scheduler scheduler) + public ChannelManager(Scheduler scheduler) { this.scheduler = scheduler ?? throw new ArgumentNullException(nameof(scheduler)); - CurrentChat.ValueChanged += currentChatChanged; + CurrentChannel.ValueChanged += currentChannelChanged; } - private void currentChatChanged(ChatBase chatBase) + private void currentChannelChanged(Channel channel) { - if (chatBase is ChannelChat channel && !JoinedChannels.Contains(channel)) + if (!JoinedChannels.Contains(channel)) JoinedChannels.Add(channel); - - if (chatBase is UserChat userChat && !OpenedUserChats.Contains(userChat)) - OpenedUserChats.Add(userChat); } /// - /// Posts a message to the currently opened chat. + /// Posts a message to the currently opened channel. /// /// The message text that is going to be posted /// Is true if the message is an action, e.g.: user is currently eating public void PostMessage(string text, bool isAction = false) { - if (CurrentChat.Value == null) + if (CurrentChannel.Value == null) return; if (!api.IsLoggedIn) { - CurrentChat.Value.AddNewMessages(new ErrorMessage("Please sign in to participate in chat!")); + CurrentChannel.Value.AddNewMessages(new ErrorMessage("Please sign in to participate in chat!")); return; } @@ -123,23 +100,23 @@ namespace osu.Game.Online.Chat { Sender = api.LocalUser.Value, Timestamp = DateTimeOffset.Now, - TargetType = CurrentChat.Value.Target, - TargetId = CurrentChat.Value.ChatID, + TargetType = CurrentChannel.Value.Target, + TargetId = CurrentChannel.Value.Id, IsAction = isAction, Content = text }; - CurrentChat.Value.AddLocalEcho(message); + CurrentChannel.Value.AddLocalEcho(message); var req = new PostMessageRequest(message); - req.Failure += e => CurrentChat.Value?.ReplaceMessage(message, null); - req.Success += m => CurrentChat.Value?.ReplaceMessage(message, m); + req.Failure += e => CurrentChannel.Value?.ReplaceMessage(message, null); + req.Success += m => CurrentChannel.Value?.ReplaceMessage(message, m); api.Queue(req); } public void PostCommand(string text) { - if (CurrentChat.Value == null) + if (CurrentChannel.Value == null) return; var parameters = text.Split(new[] { ' ' }, 2); @@ -151,18 +128,18 @@ namespace osu.Game.Online.Chat case "me": if (string.IsNullOrWhiteSpace(content)) { - CurrentChat.Value.AddNewMessages(new ErrorMessage("Usage: /me [action]")); + CurrentChannel.Value.AddNewMessages(new ErrorMessage("Usage: /me [action]")); break; } PostMessage(content, true); break; case "help": - CurrentChat.Value.AddNewMessages(new InfoMessage("Supported commands: /help, /me [action]")); + CurrentChannel.Value.AddNewMessages(new InfoMessage("Supported commands: /help, /me [action]")); break; default: - CurrentChat.Value.AddNewMessages(new ErrorMessage($@"""/{command}"" is not supported! For a list of supported commands see /help")); + CurrentChannel.Value.AddNewMessages(new ErrorMessage($@"""/{command}"" is not supported! For a list of supported commands see /help")); break; } } @@ -193,6 +170,8 @@ namespace osu.Game.Online.Chat private void handleUserMessages(IEnumerable messages) { + var joinedUserChannels = JoinedChannels.Where(c => c.Target == TargetType.User).ToList(); + var outgoingMessages = messages.Where(m => m.Sender.Id == api.LocalUser.Value.Id); var outgoingMessagesGroups = outgoingMessages.GroupBy(m => m.TargetId); var incomingMessagesGroups = messages.Except(outgoingMessages).GroupBy(m => m.UserId); @@ -200,35 +179,43 @@ namespace osu.Game.Online.Chat foreach (var messageGroup in incomingMessagesGroups) { var targetUser = messageGroup.First().Sender; - var chat = OpenedUserChats.FirstOrDefault(c => c.User.Id == targetUser.Id); + var channel = joinedUserChannels.FirstOrDefault(c => c.Id == targetUser.Id); - if (chat == null) + if (channel == null) { - chat = new UserChat(targetUser); - OpenedUserChats.Add(chat); + channel = new Channel(targetUser); + JoinedChannels.Add(channel); + joinedUserChannels.Add(channel); } - chat.AddNewMessages(messageGroup.ToArray()); + channel.AddNewMessages(messageGroup.ToArray()); var outgoingTargetMessages = outgoingMessagesGroups.FirstOrDefault(g => g.Key == targetUser.Id); if (outgoingTargetMessages != null) - chat.AddNewMessages(outgoingTargetMessages.ToArray()); + channel.AddNewMessages(outgoingTargetMessages.ToArray()); } - var withoutReplyGroups = outgoingMessagesGroups.Where(g => OpenedUserChats.All(m => m.ChatID != g.Key)); + var withoutReplyGroups = outgoingMessagesGroups.Where(g => joinedUserChannels.All(m => m.Id != g.Key)); foreach (var withoutReplyGroup in withoutReplyGroups) { - var chat = new UserChat(new User { Id = withoutReplyGroup.First().TargetId }); + var userReq = new GetUserRequest(withoutReplyGroup.First().TargetId); - chat.AddNewMessages(withoutReplyGroup.ToArray()); - OpenedUserChats.Add(chat); - chat.RequestDetails(api); + userReq.Failure += exception => Logger.Error(exception, "Failed to get user informations."); + userReq.Success += user => + { + var channel = new Channel(user); + + channel.AddNewMessages(withoutReplyGroup.ToArray()); + JoinedChannels.Add(channel); + }; + + api.Queue(userReq); } } private void fetchNewChannelMessages() { - fetchChannelMsgReq = new GetChannelMessagesRequest(JoinedChannels, lastChannelMsgId); + fetchChannelMsgReq = new GetChannelMessagesRequest(JoinedChannels.Where(c => c.Target == TargetType.Channel), lastChannelMsgId); fetchChannelMsgReq.Success += messages => { @@ -257,22 +244,24 @@ namespace osu.Game.Online.Chat req.Success += channels => { - channels.Where(channel => AvailableChannels.All(c => c.ChatID != channel.ChatID)) + channels.Where(channel => AvailableChannels.All(c => c.Id != channel.Id)) .ForEach(channel => AvailableChannels.Add(channel)); channels.Where(channel => defaultChannels.Contains(channel.Name)) - .Where(channel => JoinedChannels.All(c => c.ChatID != channel.ChatID)) + .Where(channel => JoinedChannels.All(c => c.Id != channel.Id)) .ForEach(channel => { JoinedChannels.Add(channel); + var fetchInitialMsgReq = new GetChannelMessagesRequest(new[] {channel}, null); fetchInitialMsgReq.Success += handleChannelMessages; + fetchInitialMsgReq.Failure += exception => Logger.Error(exception, "Failed to fetch inital messages."); api.Queue(fetchInitialMsgReq); }); fetchNewMessages(); }; - req.Failure += error => Logger.Error(error, "Fetching channels failed"); + req.Failure += error => Logger.Error(error, "Fetching channel list failed"); api.Queue(req); } diff --git a/osu.Game/Online/Chat/UserChat.cs b/osu.Game/Online/Chat/UserChat.cs deleted file mode 100644 index 902d4eee11..0000000000 --- a/osu.Game/Online/Chat/UserChat.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System; -using osu.Framework.Logging; -using osu.Game.Online.API; -using osu.Game.Online.API.Requests; -using osu.Game.Users; - -namespace osu.Game.Online.Chat -{ - public class UserChat : ChatBase - { - public User User { get; private set; } - public override TargetType Target => TargetType.User; - public override long ChatID => User.Id; - - public Action DetailsArrived; - - public UserChat(User user, Message[] messages = null) - { - User = user ?? throw new ArgumentNullException(nameof(user)); - - if (messages != null) AddNewMessages(messages); - } - - public void RequestDetails(IAPIProvider api) - { - if (api == null) - throw new ArgumentNullException(nameof(api)); - - var req = new GetUserRequest(User.Id); - req.Success += user => - { - User = user; - DetailsArrived?.Invoke(user); - }; - req.Failure += exception => Logger.Error(exception, $"Requesting details for user with Id:{User.Id} failed."); - api.Queue(req); - } - - public override string ToString() => User.Username ?? User.Id.ToString(); - } -} diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index d247bc74ff..6b4cb731d7 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -113,7 +113,7 @@ namespace osu.Game dependencies.Cache(api); dependencies.CacheAs(api); - var chatManager = new ChatManager(Scheduler); + var chatManager = new ChannelManager(Scheduler); api.Register(chatManager); dependencies.Cache(chatManager); diff --git a/osu.Game/Overlays/Chat/ChannelListItem.cs b/osu.Game/Overlays/Chat/ChannelListItem.cs index 9625c715d2..19418c63a8 100644 --- a/osu.Game/Overlays/Chat/ChannelListItem.cs +++ b/osu.Game/Overlays/Chat/ChannelListItem.cs @@ -24,7 +24,7 @@ namespace osu.Game.Overlays.Chat private const float text_size = 15; private const float transition_duration = 100; - private readonly ChannelChat channel; + private readonly Channel channel; private readonly Bindable joinedBind = new Bindable(); private readonly OsuSpriteText name; @@ -44,10 +44,10 @@ namespace osu.Game.Overlays.Chat } } - public Action OnRequestJoin; - public Action OnRequestLeave; + public Action OnRequestJoin; + public Action OnRequestLeave; - public ChannelListItem(ChannelChat channel) + public ChannelListItem(Channel channel) { this.channel = channel; diff --git a/osu.Game/Overlays/Chat/ChannelSection.cs b/osu.Game/Overlays/Chat/ChannelSection.cs index 6bec82f505..132891bcc0 100644 --- a/osu.Game/Overlays/Chat/ChannelSection.cs +++ b/osu.Game/Overlays/Chat/ChannelSection.cs @@ -33,7 +33,7 @@ namespace osu.Game.Overlays.Chat set { header.Text = value.ToUpper(); } } - public IEnumerable Channels + public IEnumerable Channels { set { ChannelFlow.ChildrenEnumerable = value.Select(c => new ChannelListItem(c)); } } diff --git a/osu.Game/Overlays/Chat/ChannelSelectionOverlay.cs b/osu.Game/Overlays/Chat/ChannelSelectionOverlay.cs index 598e1fe527..3684c47e40 100644 --- a/osu.Game/Overlays/Chat/ChannelSelectionOverlay.cs +++ b/osu.Game/Overlays/Chat/ChannelSelectionOverlay.cs @@ -32,8 +32,8 @@ namespace osu.Game.Overlays.Chat private readonly SearchTextBox search; private readonly SearchContainer sectionsFlow; - public Action OnRequestJoin; - public Action OnRequestLeave; + public Action OnRequestJoin; + public Action OnRequestLeave; public IEnumerable Sections { diff --git a/osu.Game/Overlays/Chat/ChannelTabControl.cs b/osu.Game/Overlays/Chat/ChannelTabControl.cs index bf15aa51e9..6fb0bf92a4 100644 --- a/osu.Game/Overlays/Chat/ChannelTabControl.cs +++ b/osu.Game/Overlays/Chat/ChannelTabControl.cs @@ -21,11 +21,11 @@ using osu.Game.Graphics.Containers; namespace osu.Game.Overlays.Chat { - public class ChannelTabControl : OsuTabControl + public class ChannelTabControl : OsuTabControl { private const float shear_width = 10; - public Action OnRequestLeave; + public Action OnRequestLeave; public readonly Bindable ChannelSelectorActive = new Bindable(); @@ -46,19 +46,12 @@ namespace osu.Game.Overlays.Chat Margin = new MarginPadding(10), }); - AddTabItem(selectorTab = new ChannelTabItem.ChannelSelectorTabItem(new ChannelChat { Name = "+" })); + AddTabItem(selectorTab = new ChannelTabItem.ChannelSelectorTabItem(new Channel { Name = "+" })); ChannelSelectorActive.BindTo(selectorTab.Active); } - public void DeselectAll() - { - if (SelectedTab != null) - SelectedTab.Active.Value = false; - SelectedTab = null; - } - - protected override void AddTabItem(TabItem item, bool addToDropdown = true) + protected override void AddTabItem(TabItem item, bool addToDropdown = true) { if (item != selectorTab && TabContainer.GetLayoutPosition(selectorTab) < float.MaxValue) // performTabSort might've made selectorTab's position wonky, fix it @@ -70,9 +63,9 @@ namespace osu.Game.Overlays.Chat SelectTab(item); } - protected override TabItem CreateTabItem(ChannelChat value) => new ChannelTabItem(value) { OnRequestClose = tabCloseRequested }; + protected override TabItem CreateTabItem(Channel value) => new ChannelTabItem(value) { OnRequestClose = tabCloseRequested }; - protected override void SelectTab(TabItem tab) + protected override void SelectTab(TabItem tab) { if (tab is ChannelTabItem.ChannelSelectorTabItem) { @@ -85,7 +78,7 @@ namespace osu.Game.Overlays.Chat base.SelectTab(tab); } - private void tabCloseRequested(TabItem tab) + private void tabCloseRequested(TabItem tab) { int totalTabs = TabContainer.Count - 1; // account for selectorTab int currentIndex = MathHelper.Clamp(TabContainer.IndexOf(tab), 1, totalTabs); @@ -100,7 +93,7 @@ namespace osu.Game.Overlays.Chat OnRequestLeave?.Invoke(tab.Value); } - private class ChannelTabItem : TabItem + private class ChannelTabItem : TabItem { private Color4 backgroundInactive; private Color4 backgroundHover; @@ -182,7 +175,7 @@ namespace osu.Game.Overlays.Chat updateState(); } - public ChannelTabItem(ChannelChat value) : base(value) + public ChannelTabItem(Channel value) : base(value) { Width = 150; @@ -314,7 +307,7 @@ namespace osu.Game.Overlays.Chat { public override bool IsRemovable => false; - public ChannelSelectorTabItem(ChannelChat value) : base(value) + public ChannelSelectorTabItem(Channel value) : base(value) { Depth = float.MaxValue; Width = 45; diff --git a/osu.Game/Overlays/Chat/ChatLine.cs b/osu.Game/Overlays/Chat/ChatLine.cs index 19ad452943..b020e13c38 100644 --- a/osu.Game/Overlays/Chat/ChatLine.cs +++ b/osu.Game/Overlays/Chat/ChatLine.cs @@ -82,7 +82,7 @@ namespace osu.Game.Overlays.Chat Padding = new MarginPadding { Left = padding, Right = padding }; } - private ChatManager chatManager; + private ChannelManager chatManager; private Message message; private OsuSpriteText username; @@ -107,7 +107,7 @@ namespace osu.Game.Overlays.Chat } [BackgroundDependencyLoader(true)] - private void load(OsuColour colours, ChatManager chatManager) + private void load(OsuColour colours, ChannelManager chatManager) { this.chatManager = chatManager; customUsernameColour = colours.ChatBlue; @@ -245,10 +245,10 @@ namespace osu.Game.Overlays.Chat } [BackgroundDependencyLoader(true)] - private void load(UserProfileOverlay profile, ChatManager chatManager) + private void load(UserProfileOverlay profile, ChannelManager chatManager) { Action = () => profile?.ShowUser(sender); - startChatAction = () => chatManager?.OpenUserChat(sender); + startChatAction = () => chatManager?.OpenUserChannel(sender); } public MenuItem[] ContextMenuItems => new MenuItem[] diff --git a/osu.Game/Overlays/Chat/ChatTabControl.cs b/osu.Game/Overlays/Chat/ChatTabControl.cs index 8ec60d5e8d..fe6945523f 100644 --- a/osu.Game/Overlays/Chat/ChatTabControl.cs +++ b/osu.Game/Overlays/Chat/ChatTabControl.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -7,14 +8,13 @@ using osu.Game.Online.Chat; namespace osu.Game.Overlays.Chat { - public class ChatTabControl : Container, IHasCurrentValue + public class ChatTabControl : Container, IHasCurrentValue { - public readonly ChannelTabControl channelTabControl; - private readonly UserTabControl userTabControl; + public readonly ChannelTabControl ChannelTabControl; + public readonly UserTabControl UserTabControl; - public Bindable Current { get; } = new Bindable(); - public Action OnRequestLeave; - public Action OnRequestChannelSelection; + public Bindable Current { get; } = new Bindable(); + public Action OnRequestLeave; public ChatTabControl() { @@ -22,76 +22,80 @@ namespace osu.Game.Overlays.Chat Children = new Drawable[] { - channelTabControl = new ChannelTabControl + ChannelTabControl = new ChannelTabControl { Width = 0.5f, Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, RelativeSizeAxes = Axes.Both, - OnRequestLeave = chat => OnRequestLeave?.Invoke(chat) + OnRequestLeave = channel => OnRequestLeave?.Invoke(channel) }, - userTabControl = new UserTabControl + UserTabControl = new UserTabControl { Width = 0.5f, Anchor = Anchor.BottomRight, Origin = Anchor.BottomRight, RelativeSizeAxes = Axes.Both, - OnRequestLeave = chat => OnRequestLeave?.Invoke(chat) + OnRequestLeave = channel => OnRequestLeave?.Invoke(channel) }, }; Current.ValueChanged += currentTabChanged; - channelTabControl.Current.ValueChanged += chat => + ChannelTabControl.Current.ValueChanged += channel => { - if (chat != null) - Current.Value = chat; + if (channel != null) + Current.Value = channel; }; - userTabControl.Current.ValueChanged += chat => + UserTabControl.Current.ValueChanged += channel => { - if (chat != null) - Current.Value = chat; + if (channel != null) + Current.Value = channel; }; } - private void currentTabChanged(ChatBase tab) + private void currentTabChanged(Channel channel) { - switch (tab) + switch (channel.Target) { - case UserChat userChat: - userTabControl.Current.Value = userChat; - channelTabControl.Current.Value = null; + case TargetType.User: + UserTabControl.Current.Value = channel; + ChannelTabControl.Current.Value = null; break; - case ChannelChat channelChat: - channelTabControl.Current.Value = channelChat; - userTabControl.Current.Value = null; + case TargetType.Channel: + ChannelTabControl.Current.Value = channel; + UserTabControl.Current.Value = null; break; } } - public void AddItem(ChatBase chat) + public void AddItem(Channel channel) { - switch (chat) + switch (channel.Target) { - case UserChat userChat: - userTabControl.AddItem(userChat); + case TargetType.User: + UserTabControl.AddItem(channel); break; - case ChannelChat channelChat: - channelTabControl.AddItem(channelChat); + case TargetType.Channel: + ChannelTabControl.AddItem(channel); break; } } - public void RemoveItem(ChatBase chat) + public void RemoveItem(Channel channel) { - switch (chat) + Channel nextSelectedChannel = null; + + switch (channel.Target) { - case UserChat userChat: - userTabControl.RemoveItem(userChat); - Current.Value = null; + case TargetType.User: + UserTabControl.RemoveItem(channel); + if (Current.Value == channel) + Current.Value = UserTabControl.Items.FirstOrDefault() ?? ChannelTabControl.Items.FirstOrDefault(); break; - case ChannelChat channelChat: - channelTabControl.RemoveItem(channelChat); - Current.Value = null; + case TargetType.Channel: + ChannelTabControl.RemoveItem(channel); + if (Current.Value == channel) + Current.Value = ChannelTabControl.Items.FirstOrDefault() ?? UserTabControl.Items.FirstOrDefault(); break; } } diff --git a/osu.Game/Overlays/Chat/DrawableChat.cs b/osu.Game/Overlays/Chat/DrawableChat.cs index 4ebdc4bd31..5e9f399779 100644 --- a/osu.Game/Overlays/Chat/DrawableChat.cs +++ b/osu.Game/Overlays/Chat/DrawableChat.cs @@ -17,11 +17,11 @@ namespace osu.Game.Overlays.Chat { public class DrawableChat : Container { - public readonly ChatBase Chat; + public readonly Channel Chat; private readonly ChatLineContainer flow; private readonly ScrollContainer scroll; - public DrawableChat(ChatBase chat) + public DrawableChat(Channel chat) { Chat = chat; @@ -79,7 +79,7 @@ namespace osu.Game.Overlays.Chat private void newMessagesArrived(IEnumerable newMessages) { // Add up to last ChatBase.MAX_HISTORY messages - var displayMessages = newMessages.Skip(Math.Max(0, newMessages.Count() - ChatBase.MAX_HISTORY)); + var displayMessages = newMessages.Skip(Math.Max(0, newMessages.Count() - Channel.MAX_HISTORY)); flow.AddRange(displayMessages.Select(m => new ChatLine(m))); @@ -89,7 +89,7 @@ namespace osu.Game.Overlays.Chat scrollToEnd(); var staleMessages = flow.Children.Where(c => c.LifetimeEnd == double.MaxValue).ToArray(); - int count = staleMessages.Length - ChatBase.MAX_HISTORY; + int count = staleMessages.Length - Channel.MAX_HISTORY; for (int i = 0; i < count; i++) { diff --git a/osu.Game/Overlays/Chat/UserTabControl.cs b/osu.Game/Overlays/Chat/UserTabControl.cs index cf1caaf4df..99fc095331 100644 --- a/osu.Game/Overlays/Chat/UserTabControl.cs +++ b/osu.Game/Overlays/Chat/UserTabControl.cs @@ -10,13 +10,16 @@ using OpenTK; namespace osu.Game.Overlays.Chat { - public class UserTabControl : OsuTabControl + public class UserTabControl : OsuTabControl { - protected override TabItem CreateTabItem(UserChat value) => new UserTabItem(value) { OnRequestClose = tabCloseRequested }; + protected override TabItem CreateTabItem(Channel value) + { + if (value.Target != TargetType.User) + throw new ArgumentException("Argument value needs to have the targettype user."); + return new UserTabItem(value) { OnRequestClose = tabCloseRequested }; + } - protected override Dropdown CreateDropdown() => null; - - public Action OnRequestLeave; + public Action OnRequestLeave; public UserTabControl() { @@ -28,7 +31,7 @@ namespace osu.Game.Overlays.Chat }; } - protected override void AddTabItem(TabItem item, bool addToDropdown = true) + protected override void AddTabItem(TabItem item, bool addToDropdown = true) { base.AddTabItem(item, addToDropdown); @@ -36,7 +39,7 @@ namespace osu.Game.Overlays.Chat SelectTab(item); } - private void tabCloseRequested(TabItem priv) + private void tabCloseRequested(TabItem priv) { int totalTabs = TabContainer.Count -1; // account for selectorTab int currentIndex = MathHelper.Clamp(TabContainer.IndexOf(priv), 1, totalTabs); @@ -47,13 +50,5 @@ namespace osu.Game.Overlays.Chat OnRequestLeave?.Invoke(priv.Value); } - - public void DeselectAll() - { - if (SelectedTab != null) - SelectedTab.Active.Value = false; - SelectedTab = null; - - } } } diff --git a/osu.Game/Overlays/Chat/UserTabItem.cs b/osu.Game/Overlays/Chat/UserTabItem.cs index e8031d60b9..de6ff466df 100644 --- a/osu.Game/Overlays/Chat/UserTabItem.cs +++ b/osu.Game/Overlays/Chat/UserTabItem.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -19,10 +20,10 @@ using OpenTK.Graphics; namespace osu.Game.Overlays.Chat { - public class UserTabItem : TabItem + public class UserTabItem : TabItem { private static readonly Vector2 shear = new Vector2(1f / 5f, 0); - private readonly UserChat chat; + private readonly Channel channel; public override bool IsRemovable => true; private readonly Box highlightBox; @@ -32,10 +33,13 @@ namespace osu.Game.Overlays.Chat private readonly Avatar avatarContainer; private readonly ChatTabItemCloseButton closeButton; - public UserTabItem(UserChat value) + public UserTabItem(Channel value) : base(value) { - chat = value; + if (value.Target != TargetType.User) + throw new ArgumentException("Argument value needs to have the targettype user!"); + + channel = value; AutoSizeAxes = Axes.X; Height = 50; Origin = Anchor.BottomRight; @@ -117,7 +121,7 @@ namespace osu.Game.Overlays.Chat Anchor = Anchor.Centre, Origin = Anchor.Centre, Masking = true, - Child = new DelayedLoadWrapper(new Avatar(value.User) + Child = new DelayedLoadWrapper(new Avatar(value.JoinedUsers.First()) { Size = new Vector2(ChatOverlay.TAB_AREA_HEIGHT), OnLoadComplete = d => d.FadeInFromZero(300, Easing.OutQuint), @@ -132,7 +136,7 @@ namespace osu.Game.Overlays.Chat { Origin = Anchor.CentreLeft, Anchor = Anchor.CentreLeft, - Text = value.User.Username, + Text = value.Name, Margin = new MarginPadding(1), TextSize = 18, }, @@ -177,12 +181,14 @@ namespace osu.Game.Overlays.Chat username.ScaleTo(new Vector2(1, 1), activate_length, Easing.OutQuint); closeButton.ScaleTo(new Vector2(1, 1), activate_length, Easing.OutQuint); closeButton.FadeIn(activate_length, Easing.OutQuint); - // TweenEdgeEffectTo(activateEdgeEffect, activate_length); + TweenEdgeEffectTo(activateEdgeEffect, activate_length); } private readonly EdgeEffectParameters deactivateEdgeEffect = new EdgeEffectParameters { - Colour = Color4.Black.Opacity(0.0f), + Type = EdgeEffectType.Shadow, + Radius = 10, + Colour = Color4.Black.Opacity(0.2f), }; protected override void OnDeactivated() @@ -196,19 +202,15 @@ namespace osu.Game.Overlays.Chat username.ScaleTo(new Vector2(0, 1), deactivate_length, Easing.OutQuint); closeButton.FadeOut(deactivate_length, Easing.OutQuint); closeButton.ScaleTo(new Vector2(0, 1), deactivate_length, Easing.OutQuint); - // TweenEdgeEffectTo(deactivateEdgeEffect, deactivate_length); + TweenEdgeEffectTo(deactivateEdgeEffect, deactivate_length); } [BackgroundDependencyLoader] private void load(OsuColour colours, IAPIProvider api) { - backgroundBox.Colour = Value.User.Colour != null ? OsuColour.FromHex(Value.User.Colour) : colours.BlueDark; + var user = Value.JoinedUsers.First(); - if (chat.User.Username == null || chat.User.Id < 1) - { - chat.DetailsArrived += arrivedUser => { Scheduler.Add(() => { username.Text = arrivedUser.Username; }); }; - chat.RequestDetails(api); - } + backgroundBox.Colour = user.Colour != null ? OsuColour.FromHex(user.Colour) : colours.BlueDark; } } } diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 801cb894d4..33c22550a8 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -30,7 +30,7 @@ namespace osu.Game.Overlays private const float textbox_height = 60; private const float channel_selection_min_height = 0.3f; - private ChatManager chatManager; + private ChannelManager chatManager; private readonly Container currentChatContainer; private readonly List loadedChannels = new List(); @@ -157,13 +157,7 @@ namespace osu.Game.Overlays chatTabControl = new ChatTabControl { RelativeSizeAxes = Axes.Both, - OnRequestLeave = chat => - { - if (chat is ChannelChat channelChat) - chatManager.JoinedChannels.Remove(channelChat); - if (chat is UserChat userChat) - chatManager.OpenedUserChats.Remove(userChat); - } + OnRequestLeave = channel => chatManager.JoinedChannels.Remove(channel) } } }, @@ -171,11 +165,11 @@ namespace osu.Game.Overlays }, }; - chatTabControl.Current.ValueChanged += chat => chatManager.CurrentChat.Value = chat; - chatTabControl.channelTabControl.ChannelSelectorActive.ValueChanged += value => channelSelection.State = value ? Visibility.Visible : Visibility.Hidden; + chatTabControl.Current.ValueChanged += chat => chatManager.CurrentChannel.Value = chat; + chatTabControl.ChannelTabControl.ChannelSelectorActive.ValueChanged += value => channelSelection.State = value ? Visibility.Visible : Visibility.Hidden; channelSelection.StateChanged += state => { - chatTabControl.channelTabControl.ChannelSelectorActive.Value = state == Visibility.Visible; + chatTabControl.ChannelTabControl.ChannelSelectorActive.Value = state == Visibility.Visible; if (state == Visibility.Visible) { @@ -211,28 +205,24 @@ namespace osu.Game.Overlays switch (args.Action) { case NotifyCollectionChangedAction.Add: - foreach (ChannelChat newChannel in args.NewItems) + foreach (Channel newChannel in args.NewItems) { chatTabControl.AddItem(newChannel); newChannel.Joined.Value = true; - //if (chatManager.CurrentChat.Value == null) - // chatManager.CurrentChat.Value = newChannel; } break; case NotifyCollectionChangedAction.Remove: - foreach (ChannelChat removedChannel in args.OldItems) + foreach (Channel removedChannel in args.OldItems) { chatTabControl.RemoveItem(removedChannel); loadedChannels.Remove(loadedChannels.Find(c => c.Chat == removedChannel )); removedChannel.Joined.Value = false; - if (chatManager.CurrentChat.Value == removedChannel) - chatManager.CurrentChat.Value = null; } break; } } - private void currentChatChanged(ChatBase chat) + private void currentChatChanged(Channel chat) { if (chat == null) { @@ -243,8 +233,9 @@ namespace osu.Game.Overlays } textbox.Current.Disabled = chat.ReadOnly; - - Scheduler.Add(() => chatTabControl.Current.Value = chat); + + if (chatTabControl.Current.Value != chat) + Scheduler.Add(() => chatTabControl.Current.Value = chat); var loaded = loadedChannels.Find(d => d.Chat == chat); if (loaded == null) @@ -337,7 +328,7 @@ namespace osu.Game.Overlays } [BackgroundDependencyLoader] - private void load(APIAccess api, OsuConfigManager config, OsuColour colours, ChatManager chatManager) + private void load(APIAccess api, OsuConfigManager config, OsuColour colours, ChannelManager chatManager) { api.Register(chatManager); @@ -354,30 +345,9 @@ namespace osu.Game.Overlays loading.Show(); this.chatManager = chatManager; - chatManager.CurrentChat.ValueChanged += currentChatChanged; + chatManager.CurrentChannel.ValueChanged += currentChatChanged; chatManager.JoinedChannels.CollectionChanged += joinedChannelsChanged; chatManager.AvailableChannels.CollectionChanged += availableChannelsChanged; - chatManager.OpenedUserChats.CollectionChanged += openedUserChatsChanged; - } - - private void openedUserChatsChanged(object sender, NotifyCollectionChangedEventArgs args) - { - switch (args.Action) - { - case NotifyCollectionChangedAction.Add: - foreach (UserChat chat in args.NewItems) - { - chatTabControl.AddItem(args.NewItems[0] as UserChat); - - if (chatManager.CurrentChat.Value == chat) - chatTabControl.Current.Value = chat; - } - break; - case NotifyCollectionChangedAction.Remove: - foreach (UserChat chat in args.OldItems) - chatTabControl.RemoveItem(chat); - break; - } } private void postMessage(TextBox textbox, bool newText) From 697b551f3ed16ea37b3e2422db1d22ad437ae231 Mon Sep 17 00:00:00 2001 From: miterosan Date: Wed, 11 Apr 2018 20:27:33 +0200 Subject: [PATCH 016/155] Fix Selected tab beeing choosen multiple times --- osu.Game/Overlays/Chat/ChannelTabControl.cs | 3 --- osu.Game/Overlays/Chat/ChatTabControl.cs | 2 ++ osu.Game/Overlays/Chat/UserTabControl.cs | 8 -------- osu.Game/Overlays/Chat/UserTabItem.cs | 2 ++ 4 files changed, 4 insertions(+), 11 deletions(-) diff --git a/osu.Game/Overlays/Chat/ChannelTabControl.cs b/osu.Game/Overlays/Chat/ChannelTabControl.cs index 6fb0bf92a4..9c07294a50 100644 --- a/osu.Game/Overlays/Chat/ChannelTabControl.cs +++ b/osu.Game/Overlays/Chat/ChannelTabControl.cs @@ -58,9 +58,6 @@ namespace osu.Game.Overlays.Chat TabContainer.SetLayoutPosition(selectorTab, float.MaxValue); base.AddTabItem(item, addToDropdown); - - if (SelectedTab == null) - SelectTab(item); } protected override TabItem CreateTabItem(Channel value) => new ChannelTabItem(value) { OnRequestClose = tabCloseRequested }; diff --git a/osu.Game/Overlays/Chat/ChatTabControl.cs b/osu.Game/Overlays/Chat/ChatTabControl.cs index fe6945523f..fe2ec65827 100644 --- a/osu.Game/Overlays/Chat/ChatTabControl.cs +++ b/osu.Game/Overlays/Chat/ChatTabControl.cs @@ -79,6 +79,8 @@ namespace osu.Game.Overlays.Chat ChannelTabControl.AddItem(channel); break; } + + } public void RemoveItem(Channel channel) diff --git a/osu.Game/Overlays/Chat/UserTabControl.cs b/osu.Game/Overlays/Chat/UserTabControl.cs index 99fc095331..5e23b4c2eb 100644 --- a/osu.Game/Overlays/Chat/UserTabControl.cs +++ b/osu.Game/Overlays/Chat/UserTabControl.cs @@ -31,14 +31,6 @@ namespace osu.Game.Overlays.Chat }; } - protected override void AddTabItem(TabItem item, bool addToDropdown = true) - { - base.AddTabItem(item, addToDropdown); - - if (SelectedTab == null) - SelectTab(item); - } - private void tabCloseRequested(TabItem priv) { int totalTabs = TabContainer.Count -1; // account for selectorTab diff --git a/osu.Game/Overlays/Chat/UserTabItem.cs b/osu.Game/Overlays/Chat/UserTabItem.cs index de6ff466df..aaf0a7b295 100644 --- a/osu.Game/Overlays/Chat/UserTabItem.cs +++ b/osu.Game/Overlays/Chat/UserTabItem.cs @@ -139,12 +139,14 @@ namespace osu.Game.Overlays.Chat Text = value.Name, Margin = new MarginPadding(1), TextSize = 18, + Alpha = 0, }, closeButton = new ChatTabItemCloseButton { Height = 1, Origin = Anchor.BottomLeft, Anchor = Anchor.BottomLeft, + Alpha = 0, Margin = new MarginPadding { Right = 5 From 2056258defe93beb973a9a7fa49cce1e4971d480 Mon Sep 17 00:00:00 2001 From: miterosan Date: Wed, 11 Apr 2018 20:31:16 +0200 Subject: [PATCH 017/155] Fix code sanity --- osu.Game.Tests/Visual/TestCaseChatTabControl.cs | 4 +++- osu.Game/Online/Chat/ChannelManager.cs | 2 +- osu.Game/Overlays/Chat/ChatTabControl.cs | 7 ++++--- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseChatTabControl.cs b/osu.Game.Tests/Visual/TestCaseChatTabControl.cs index ae7c6e2751..8318f89217 100644 --- a/osu.Game.Tests/Visual/TestCaseChatTabControl.cs +++ b/osu.Game.Tests/Visual/TestCaseChatTabControl.cs @@ -1,4 +1,6 @@ - +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + using System; using System.Collections.Generic; using osu.Framework.Extensions.Color4Extensions; diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index e7ffb60f04..f67e42dfdb 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -197,7 +197,7 @@ namespace osu.Game.Online.Chat var withoutReplyGroups = outgoingMessagesGroups.Where(g => joinedUserChannels.All(m => m.Id != g.Key)); foreach (var withoutReplyGroup in withoutReplyGroups) - { + { var userReq = new GetUserRequest(withoutReplyGroup.First().TargetId); userReq.Failure += exception => Logger.Error(exception, "Failed to get user informations."); diff --git a/osu.Game/Overlays/Chat/ChatTabControl.cs b/osu.Game/Overlays/Chat/ChatTabControl.cs index fe2ec65827..5d33843f97 100644 --- a/osu.Game/Overlays/Chat/ChatTabControl.cs +++ b/osu.Game/Overlays/Chat/ChatTabControl.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; using System.Linq; using osu.Framework.Configuration; using osu.Framework.Graphics; @@ -79,8 +82,6 @@ namespace osu.Game.Overlays.Chat ChannelTabControl.AddItem(channel); break; } - - } public void RemoveItem(Channel channel) From c2020742b2dbc5b3ced0a2b4fc1acb1f03798945 Mon Sep 17 00:00:00 2001 From: miterosan Date: Wed, 11 Apr 2018 20:37:51 +0200 Subject: [PATCH 018/155] Actually use the fact that ChannelManager is now a component --- osu.Game/Online/Chat/ChannelManager.cs | 28 +++++++++++++++++--------- osu.Game/OsuGameBase.cs | 5 +---- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index f67e42dfdb..2d75881910 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; +using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; @@ -19,24 +20,28 @@ namespace osu.Game.Online.Chat /// /// Manages everything channel related /// - public class ChannelManager : Component, IOnlineComponent + public class ChannelManager : Component, IOnlineComponent, { /// /// The channels the player joins on startup /// private readonly string[] defaultChannels = { - @"#lazer", @"#osu", @"#lobby" + @"#lazer", + @"#osu", + @"#lobby" }; /// /// The currently opened channel /// public Bindable CurrentChannel { get; } = new Bindable(); + /// /// The Channels the player has joined /// public ObservableCollection JoinedChannels { get; } = new ObservableCollection(); + /// /// The channels available for the player to join /// @@ -56,7 +61,7 @@ namespace osu.Game.Online.Chat throw new ArgumentNullException(nameof(name)); CurrentChannel.Value = AvailableChannels.FirstOrDefault(c => c.Name == name) - ?? throw new ArgumentException($"Channel {name} was not found."); + ?? throw new ArgumentException($"Channel {name} was not found."); } public void OpenUserChannel(User user) @@ -65,12 +70,11 @@ namespace osu.Game.Online.Chat throw new ArgumentNullException(nameof(user)); CurrentChannel.Value = JoinedChannels.FirstOrDefault(c => c.Target == TargetType.User && c.Id == user.Id) - ?? new Channel(user); + ?? new Channel(user); } - public ChannelManager(Scheduler scheduler) + public ChannelManager() { - this.scheduler = scheduler ?? throw new ArgumentNullException(nameof(scheduler)); CurrentChannel.ValueChanged += currentChannelChanged; } @@ -131,6 +135,7 @@ namespace osu.Game.Online.Chat CurrentChannel.Value.AddNewMessages(new ErrorMessage("Usage: /me [action]")); break; } + PostMessage(content, true); break; @@ -253,7 +258,7 @@ namespace osu.Game.Online.Chat { JoinedChannels.Add(channel); - var fetchInitialMsgReq = new GetChannelMessagesRequest(new[] {channel}, null); + var fetchInitialMsgReq = new GetChannelMessagesRequest(new[] { channel }, null); fetchInitialMsgReq.Success += handleChannelMessages; fetchInitialMsgReq.Failure += exception => Logger.Error(exception, "Failed to fetch inital messages."); api.Queue(fetchInitialMsgReq); @@ -268,8 +273,6 @@ namespace osu.Game.Online.Chat public void APIStateChanged(APIAccess api, APIState state) { - this.api = api ?? throw new ArgumentNullException(nameof(api)); - switch (state) { case APIState.Online: @@ -285,5 +288,12 @@ namespace osu.Game.Online.Chat break; } } + + [BackgroundDependencyLoader] + private void load(IAPIProvider api) + { + this.api = this.api; + api.Register(this); + } } } diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 6b4cb731d7..613755ea5d 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -113,10 +113,7 @@ namespace osu.Game dependencies.Cache(api); dependencies.CacheAs(api); - var chatManager = new ChannelManager(Scheduler); - api.Register(chatManager); - - dependencies.Cache(chatManager); + dependencies.Cache(new ChannelManager()); dependencies.Cache(RulesetStore = new RulesetStore(contextFactory)); dependencies.Cache(FileStore = new FileStore(contextFactory, Host.Storage)); From 499ecd3843e0b8c92bb3ccbde9f6ae081f3a3746 Mon Sep 17 00:00:00 2001 From: miterosan Date: Wed, 11 Apr 2018 20:44:35 +0200 Subject: [PATCH 019/155] Fix the warnings --- osu.Game.Tests/Visual/TestCaseChatTabControl.cs | 6 +++--- osu.Game/Overlays/Chat/UserTabItem.cs | 5 +---- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseChatTabControl.cs b/osu.Game.Tests/Visual/TestCaseChatTabControl.cs index 8318f89217..77cc62cbbd 100644 --- a/osu.Game.Tests/Visual/TestCaseChatTabControl.cs +++ b/osu.Game.Tests/Visual/TestCaseChatTabControl.cs @@ -27,10 +27,10 @@ namespace osu.Game.Tests.Visual }; private readonly ChatTabControl chatTabControl; - private readonly SpriteText currentText; public TestCaseChatTabControl() { + SpriteText currentText; Add(new Container { RelativeSizeAxes = Axes.X, @@ -57,7 +57,7 @@ namespace osu.Game.Tests.Visual } }); - Add(new Container() + Add(new Container { Origin = Anchor.TopLeft, Anchor = Anchor.TopLeft, @@ -89,7 +89,7 @@ namespace osu.Game.Tests.Visual private void addChannel(string name) { - this.chatTabControl.AddItem(new Channel + chatTabControl.AddItem(new Channel { Name = name }); diff --git a/osu.Game/Overlays/Chat/UserTabItem.cs b/osu.Game/Overlays/Chat/UserTabItem.cs index aaf0a7b295..3dfec0b7ea 100644 --- a/osu.Game/Overlays/Chat/UserTabItem.cs +++ b/osu.Game/Overlays/Chat/UserTabItem.cs @@ -11,7 +11,6 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -using osu.Game.Online.API; using osu.Game.Online.Chat; using osu.Game.Screens.Menu; using osu.Game.Users; @@ -23,7 +22,6 @@ namespace osu.Game.Overlays.Chat public class UserTabItem : TabItem { private static readonly Vector2 shear = new Vector2(1f / 5f, 0); - private readonly Channel channel; public override bool IsRemovable => true; private readonly Box highlightBox; @@ -39,7 +37,6 @@ namespace osu.Game.Overlays.Chat if (value.Target != TargetType.User) throw new ArgumentException("Argument value needs to have the targettype user!"); - channel = value; AutoSizeAxes = Axes.X; Height = 50; Origin = Anchor.BottomRight; @@ -208,7 +205,7 @@ namespace osu.Game.Overlays.Chat } [BackgroundDependencyLoader] - private void load(OsuColour colours, IAPIProvider api) + private void load(OsuColour colours) { var user = Value.JoinedUsers.First(); From a5e0311253e1d12015a3b61816ed734fcd51d7d9 Mon Sep 17 00:00:00 2001 From: miterosan Date: Wed, 11 Apr 2018 20:53:35 +0200 Subject: [PATCH 020/155] Trim whitespaces --- osu.Game.Tests/Visual/TestCaseChatLink.cs | 4 ++-- osu.Game/Online/Chat/ChannelManager.cs | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseChatLink.cs b/osu.Game.Tests/Visual/TestCaseChatLink.cs index 66a28c5ee8..e79e52c890 100644 --- a/osu.Game.Tests/Visual/TestCaseChatLink.cs +++ b/osu.Game.Tests/Visual/TestCaseChatLink.cs @@ -51,11 +51,11 @@ namespace osu.Game.Tests.Visual } [BackgroundDependencyLoader] - private void load(OsuColour colours, IAPIProvider api) + private void load(OsuColour colours) { linkColour = colours.Blue; - var chatManager = new ChannelManager(Scheduler); + var chatManager = new ChannelManager(); chatManager.AvailableChannels.Add(new Channel { Name = "#english"}); chatManager.AvailableChannels.Add(new Channel { Name = "#japanese" }); dependencies.Cache(chatManager); diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 2d75881910..ea4d746bac 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -20,7 +20,7 @@ namespace osu.Game.Online.Chat /// /// Manages everything channel related /// - public class ChannelManager : Component, IOnlineComponent, + public class ChannelManager : Component, IOnlineComponent { /// /// The channels the player joins on startup @@ -284,7 +284,6 @@ namespace osu.Game.Online.Chat fetchChannelMsgReq?.Cancel(); fetchChannelMsgReq = null; fetchMessagesScheduleder?.Cancel(); - break; } } From b997f0f3fa58ffd2bee84516a41f2f8ff6b92438 Mon Sep 17 00:00:00 2001 From: miterosan Date: Wed, 11 Apr 2018 21:09:38 +0200 Subject: [PATCH 021/155] Remove not needed using --- osu.Game.Tests/Visual/TestCaseChatLink.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Tests/Visual/TestCaseChatLink.cs b/osu.Game.Tests/Visual/TestCaseChatLink.cs index e79e52c890..cf2e0081f6 100644 --- a/osu.Game.Tests/Visual/TestCaseChatLink.cs +++ b/osu.Game.Tests/Visual/TestCaseChatLink.cs @@ -15,7 +15,6 @@ using System.Linq; using NUnit.Framework; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; -using osu.Game.Online.API; using osu.Game.Overlays; namespace osu.Game.Tests.Visual From e39f5a1adfe887f80f95f5fcbe367f3ea70f6b2d Mon Sep 17 00:00:00 2001 From: miterosan Date: Thu, 12 Apr 2018 23:19:13 +0200 Subject: [PATCH 022/155] Rename var chatmanager -> channelManager Apply requested changes --- .../Visual/TestCaseChatTabControl.cs | 3 +- .../Graphics/Containers/LinkFlowContainer.cs | 17 ++++++---- ...ssagesRequest.cs => GetMessagesRequest.cs} | 4 +-- ...equest.cs => GetPrivateMessagesRequest.cs} | 4 +-- osu.Game/Online/Chat/Channel.cs | 2 +- osu.Game/Online/Chat/ChannelManager.cs | 34 +++++++++---------- osu.Game/Overlays/ChatOverlay.cs | 30 ++++++++-------- 7 files changed, 48 insertions(+), 46 deletions(-) rename osu.Game/Online/API/Requests/{GetChannelMessagesRequest.cs => GetMessagesRequest.cs} (86%) rename osu.Game/Online/API/Requests/{GetUserMessagesRequest.cs => GetPrivateMessagesRequest.cs} (81%) diff --git a/osu.Game.Tests/Visual/TestCaseChatTabControl.cs b/osu.Game.Tests/Visual/TestCaseChatTabControl.cs index 77cc62cbbd..0e0a44ba5d 100644 --- a/osu.Game.Tests/Visual/TestCaseChatTabControl.cs +++ b/osu.Game.Tests/Visual/TestCaseChatTabControl.cs @@ -22,8 +22,7 @@ namespace osu.Game.Tests.Visual { typeof(ChatTabControl), typeof(ChannelTabControl), - typeof(UserTabControl), - + typeof(UserTabControl) }; private readonly ChatTabControl chatTabControl; diff --git a/osu.Game/Graphics/Containers/LinkFlowContainer.cs b/osu.Game/Graphics/Containers/LinkFlowContainer.cs index aee2eb4597..45feab3076 100644 --- a/osu.Game/Graphics/Containers/LinkFlowContainer.cs +++ b/osu.Game/Graphics/Containers/LinkFlowContainer.cs @@ -23,15 +23,15 @@ namespace osu.Game.Graphics.Containers public override bool HandleMouseInput => true; private OsuGame game; - private ChannelManager chatManager; + private ChannelManager channelManager; private Action showNotImplementedError; [BackgroundDependencyLoader(true)] - private void load(OsuGame game, NotificationOverlay notifications, ChannelManager chatManager) + private void load(OsuGame game, NotificationOverlay notifications, ChannelManager channelManager) { // will be null in tests this.game = game; - this.chatManager = chatManager; + this.channelManager = channelManager; showNotImplementedError = () => notifications?.Post(new SimpleNotification { Text = @"This link type is not yet supported!", @@ -80,9 +80,14 @@ namespace osu.Game.Graphics.Containers game?.ShowBeatmapSet(setId); break; case LinkAction.OpenChannel: - var channel = chatManager.AvailableChannels.FirstOrDefault(c => c.Name == linkArgument); - if (channel != null) - chatManager.CurrentChannel.Value = channel; + try + { + channelManager.OpenChannel(linkArgument); + } + catch (ArgumentException) + { + //channel was not found + } break; case LinkAction.OpenEditorTimestamp: case LinkAction.JoinMultiplayerMatch: diff --git a/osu.Game/Online/API/Requests/GetChannelMessagesRequest.cs b/osu.Game/Online/API/Requests/GetMessagesRequest.cs similarity index 86% rename from osu.Game/Online/API/Requests/GetChannelMessagesRequest.cs rename to osu.Game/Online/API/Requests/GetMessagesRequest.cs index c323cf0ff8..d2c9169c51 100644 --- a/osu.Game/Online/API/Requests/GetChannelMessagesRequest.cs +++ b/osu.Game/Online/API/Requests/GetMessagesRequest.cs @@ -9,12 +9,12 @@ using osu.Game.Online.Chat; namespace osu.Game.Online.API.Requests { - public class GetChannelMessagesRequest : APIRequest> + public class GetMessagesRequest : APIRequest> { private readonly IEnumerable channels; private long? since; - public GetChannelMessagesRequest(IEnumerable channels, long? sinceId) + public GetMessagesRequest(IEnumerable channels, long? sinceId) { if (channels == null) throw new ArgumentNullException(nameof(channels)); diff --git a/osu.Game/Online/API/Requests/GetUserMessagesRequest.cs b/osu.Game/Online/API/Requests/GetPrivateMessagesRequest.cs similarity index 81% rename from osu.Game/Online/API/Requests/GetUserMessagesRequest.cs rename to osu.Game/Online/API/Requests/GetPrivateMessagesRequest.cs index ef9871c5d2..9ff70f8580 100644 --- a/osu.Game/Online/API/Requests/GetUserMessagesRequest.cs +++ b/osu.Game/Online/API/Requests/GetPrivateMessagesRequest.cs @@ -7,11 +7,11 @@ using osu.Game.Online.Chat; namespace osu.Game.Online.API.Requests { - public class GetUserMessagesRequest : APIRequest> + public class GetPrivateMessagesRequest : APIRequest> { private long? since; - public GetUserMessagesRequest(long? sinceId = null) + public GetPrivateMessagesRequest(long? sinceId = null) { since = sinceId; } diff --git a/osu.Game/Online/Chat/Channel.cs b/osu.Game/Online/Chat/Channel.cs index fdaa690e9a..93b26363ed 100644 --- a/osu.Game/Online/Chat/Channel.cs +++ b/osu.Game/Online/Chat/Channel.cs @@ -34,7 +34,7 @@ namespace osu.Game.Online.Chat } /// - /// Contructs a privatechannel + /// Contructs a private channel /// TODO this class needs to be serialized from something like channels/private, instead of creating from a contructor /// /// The user diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index ea4d746bac..e5fe3fb56e 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -50,8 +50,8 @@ namespace osu.Game.Online.Chat private APIAccess api; private readonly Scheduler scheduler; private ScheduledDelegate fetchMessagesScheduleder; - private GetChannelMessagesRequest fetchChannelMsgReq; - private GetUserMessagesRequest fetchUserMsgReq; + private GetMessagesRequest fetchMsgReq; + private GetPrivateMessagesRequest fetchPrivateMsgReq; private long? lastChannelMsgId; private long? lastUserMsgId; @@ -151,26 +151,26 @@ namespace osu.Game.Online.Chat private void fetchNewMessages() { - if (fetchChannelMsgReq == null) + if (fetchMsgReq == null) fetchNewChannelMessages(); - if (fetchUserMsgReq == null) + if (fetchPrivateMsgReq == null) fetchNewUserMessages(); } private void fetchNewUserMessages() { - fetchUserMsgReq = new GetUserMessagesRequest(lastUserMsgId); + fetchPrivateMsgReq = new GetPrivateMessagesRequest(lastUserMsgId); - fetchUserMsgReq.Success += messages => + fetchPrivateMsgReq.Success += messages => { handleUserMessages(messages); lastUserMsgId = messages.LastOrDefault()?.Id ?? lastUserMsgId; - fetchUserMsgReq = null; + fetchPrivateMsgReq = null; }; - fetchUserMsgReq.Failure += exception => Logger.Error(exception, "Fetching user messages failed."); + fetchPrivateMsgReq.Failure += exception => Logger.Error(exception, "Fetching user messages failed."); - api.Queue(fetchUserMsgReq); + api.Queue(fetchPrivateMsgReq); } private void handleUserMessages(IEnumerable messages) @@ -220,19 +220,19 @@ namespace osu.Game.Online.Chat private void fetchNewChannelMessages() { - fetchChannelMsgReq = new GetChannelMessagesRequest(JoinedChannels.Where(c => c.Target == TargetType.Channel), lastChannelMsgId); + fetchMsgReq = new GetMessagesRequest(JoinedChannels.Where(c => c.Target == TargetType.Channel), lastChannelMsgId); - fetchChannelMsgReq.Success += messages => + fetchMsgReq.Success += messages => { if (messages == null) return; handleChannelMessages(messages); lastChannelMsgId = messages.LastOrDefault()?.Id ?? lastChannelMsgId; - fetchChannelMsgReq = null; + fetchMsgReq = null; }; - fetchChannelMsgReq.Failure += exception => Logger.Error(exception, "Fetching channel messages failed."); + fetchMsgReq.Failure += exception => Logger.Error(exception, "Fetching channel messages failed."); - api.Queue(fetchChannelMsgReq); + api.Queue(fetchMsgReq); } private void handleChannelMessages(IEnumerable messages) @@ -258,7 +258,7 @@ namespace osu.Game.Online.Chat { JoinedChannels.Add(channel); - var fetchInitialMsgReq = new GetChannelMessagesRequest(new[] { channel }, null); + var fetchInitialMsgReq = new GetMessagesRequest(new[] { channel }, null); fetchInitialMsgReq.Success += handleChannelMessages; fetchInitialMsgReq.Failure += exception => Logger.Error(exception, "Failed to fetch inital messages."); api.Queue(fetchInitialMsgReq); @@ -281,8 +281,8 @@ namespace osu.Game.Online.Chat fetchMessagesScheduleder = scheduler.AddDelayed(fetchNewMessages, 1000, true); break; default: - fetchChannelMsgReq?.Cancel(); - fetchChannelMsgReq = null; + fetchMsgReq?.Cancel(); + fetchMsgReq = null; fetchMessagesScheduleder?.Cancel(); break; } diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 33c22550a8..8b405ec980 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -30,7 +30,7 @@ namespace osu.Game.Overlays private const float textbox_height = 60; private const float channel_selection_min_height = 0.3f; - private ChannelManager chatManager; + private ChannelManager channelManager; private readonly Container currentChatContainer; private readonly List loadedChannels = new List(); @@ -157,7 +157,7 @@ namespace osu.Game.Overlays chatTabControl = new ChatTabControl { RelativeSizeAxes = Axes.Both, - OnRequestLeave = channel => chatManager.JoinedChannels.Remove(channel) + OnRequestLeave = channel => channelManager.JoinedChannels.Remove(channel) } } }, @@ -165,7 +165,7 @@ namespace osu.Game.Overlays }, }; - chatTabControl.Current.ValueChanged += chat => chatManager.CurrentChannel.Value = chat; + chatTabControl.Current.ValueChanged += chat => channelManager.CurrentChannel.Value = chat; chatTabControl.ChannelTabControl.ChannelSelectorActive.ValueChanged += value => channelSelection.State = value ? Visibility.Visible : Visibility.Hidden; channelSelection.StateChanged += state => { @@ -182,10 +182,10 @@ namespace osu.Game.Overlays }; channelSelection.OnRequestJoin = channel => { - if (!chatManager.JoinedChannels.Contains(channel)) - chatManager.JoinedChannels.Add(channel); + if (!channelManager.JoinedChannels.Contains(channel)) + channelManager.JoinedChannels.Add(channel); }; - channelSelection.OnRequestLeave = channel => chatManager.JoinedChannels.Remove(channel); + channelSelection.OnRequestLeave = channel => channelManager.JoinedChannels.Remove(channel); } private void availableChannelsChanged(object sender, NotifyCollectionChangedEventArgs args) @@ -195,7 +195,7 @@ namespace osu.Game.Overlays new ChannelSection { Header = "All Channels", - Channels = chatManager.AvailableChannels, + Channels = channelManager.AvailableChannels, }, }; } @@ -328,10 +328,8 @@ namespace osu.Game.Overlays } [BackgroundDependencyLoader] - private void load(APIAccess api, OsuConfigManager config, OsuColour colours, ChannelManager chatManager) + private void load(OsuConfigManager config, OsuColour colours, ChannelManager channelManager) { - api.Register(chatManager); - ChatHeight = config.GetBindable(OsuSetting.ChatDisplayHeight); ChatHeight.ValueChanged += h => { @@ -344,10 +342,10 @@ namespace osu.Game.Overlays chatBackground.Colour = colours.ChatBlue; loading.Show(); - this.chatManager = chatManager; - chatManager.CurrentChannel.ValueChanged += currentChatChanged; - chatManager.JoinedChannels.CollectionChanged += joinedChannelsChanged; - chatManager.AvailableChannels.CollectionChanged += availableChannelsChanged; + this.channelManager = channelManager; + channelManager.CurrentChannel.ValueChanged += currentChatChanged; + channelManager.JoinedChannels.CollectionChanged += joinedChannelsChanged; + channelManager.AvailableChannels.CollectionChanged += availableChannelsChanged; } private void postMessage(TextBox textbox, bool newText) @@ -358,9 +356,9 @@ namespace osu.Game.Overlays return; if (text[0] == '/') - chatManager.PostCommand(text.Substring(1)); + channelManager.PostCommand(text.Substring(1)); else - chatManager.PostMessage(text); + channelManager.PostMessage(text); textbox.Text = string.Empty; } From a9f3885d28c0f8aaf37404fff5908c2d58b93a7a Mon Sep 17 00:00:00 2001 From: miterosan Date: Thu, 12 Apr 2018 23:29:23 +0200 Subject: [PATCH 023/155] Remove not needed using --- 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 8b405ec980..176c01620f 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -19,7 +19,6 @@ using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; -using osu.Game.Online.API; using osu.Game.Online.Chat; using osu.Game.Overlays.Chat; From 1b51da70af764574b89af8d8c0c1fa1ee74ea6d1 Mon Sep 17 00:00:00 2001 From: miterosan Date: Sat, 14 Apr 2018 13:23:16 +0200 Subject: [PATCH 024/155] Create an abstraction for APIMessagesRequest --- osu.Game/Online/API/APIMessagesRequest.cs | 28 +++++++++ .../Online/API/Requests/GetMessagesRequest.cs | 7 +-- .../API/Requests/GetPrivateMessagesRequest.cs | 17 +---- osu.Game/Online/Chat/ChannelManager.cs | 62 ++++++++++--------- 4 files changed, 65 insertions(+), 49 deletions(-) create mode 100644 osu.Game/Online/API/APIMessagesRequest.cs diff --git a/osu.Game/Online/API/APIMessagesRequest.cs b/osu.Game/Online/API/APIMessagesRequest.cs new file mode 100644 index 0000000000..e1be6cdb19 --- /dev/null +++ b/osu.Game/Online/API/APIMessagesRequest.cs @@ -0,0 +1,28 @@ +// 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 osu.Framework.IO.Network; +using osu.Game.Online.Chat; + +namespace osu.Game.Online.API +{ + public abstract class APIMessagesRequest : APIRequest> + { + private long? sinceId; + + protected APIMessagesRequest(long? sinceId) + { + this.sinceId = sinceId; + } + + protected override WebRequest CreateWebRequest() + { + var req = base.CreateWebRequest(); + + if (sinceId.HasValue) req.AddParameter(@"since", sinceId.Value.ToString()); + + return req; + } + } +} diff --git a/osu.Game/Online/API/Requests/GetMessagesRequest.cs b/osu.Game/Online/API/Requests/GetMessagesRequest.cs index d2c9169c51..cf6a0cb6fd 100644 --- a/osu.Game/Online/API/Requests/GetMessagesRequest.cs +++ b/osu.Game/Online/API/Requests/GetMessagesRequest.cs @@ -9,12 +9,11 @@ using osu.Game.Online.Chat; namespace osu.Game.Online.API.Requests { - public class GetMessagesRequest : APIRequest> + public class GetMessagesRequest : APIMessagesRequest { private readonly IEnumerable channels; - private long? since; - public GetMessagesRequest(IEnumerable channels, long? sinceId) + public GetMessagesRequest(IEnumerable channels, long? sinceId) : base(sinceId) { if (channels == null) throw new ArgumentNullException(nameof(channels)); @@ -22,7 +21,6 @@ namespace osu.Game.Online.API.Requests throw new ArgumentException("All channels in the argument channels must have the targettype Channel"); this.channels = channels; - since = sinceId; } protected override WebRequest CreateWebRequest() @@ -31,7 +29,6 @@ namespace osu.Game.Online.API.Requests var req = base.CreateWebRequest(); req.AddParameter(@"channels", channelString); - if (since.HasValue) req.AddParameter(@"since", since.Value.ToString()); return req; } diff --git a/osu.Game/Online/API/Requests/GetPrivateMessagesRequest.cs b/osu.Game/Online/API/Requests/GetPrivateMessagesRequest.cs index 9ff70f8580..b5d7bb06ee 100644 --- a/osu.Game/Online/API/Requests/GetPrivateMessagesRequest.cs +++ b/osu.Game/Online/API/Requests/GetPrivateMessagesRequest.cs @@ -1,28 +1,15 @@ // 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 osu.Framework.IO.Network; -using osu.Game.Online.Chat; - namespace osu.Game.Online.API.Requests { - public class GetPrivateMessagesRequest : APIRequest> + public class GetPrivateMessagesRequest : APIMessagesRequest { private long? since; public GetPrivateMessagesRequest(long? sinceId = null) + : base(sinceId) { - since = sinceId; - } - - protected override WebRequest CreateWebRequest() - { - var request = base.CreateWebRequest(); - if (since.HasValue) - request.AddParameter(@"since", since.Value.ToString()); - - return request; } protected override string Target => @"chat/messages/private"; diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index e5fe3fb56e..3709e42880 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -152,25 +152,46 @@ namespace osu.Game.Online.Chat private void fetchNewMessages() { if (fetchMsgReq == null) - fetchNewChannelMessages(); + fetchMessages( + () => new GetMessagesRequest(JoinedChannels.Where(c => c.Target == TargetType.Channel), lastChannelMsgId), + messages => + { + if (messages == null) + return; + handleChannelMessages(messages); + lastChannelMsgId = messages.LastOrDefault()?.Id ?? lastChannelMsgId; + fetchMsgReq = null; + } + ); + if (fetchPrivateMsgReq == null) - fetchNewUserMessages(); + fetchMessages( + () => new GetPrivateMessagesRequest(lastChannelMsgId), + messages => + { + if (messages == null) + return; + handleUserMessages(messages); + lastUserMsgId = messages.LastOrDefault()?.Id ?? lastUserMsgId; + fetchPrivateMsgReq = null; + } + ); } - private void fetchNewUserMessages() + private void fetchMessages(Func messagesRequest, Action> handler) { - fetchPrivateMsgReq = new GetPrivateMessagesRequest(lastUserMsgId); + if (messagesRequest == null) + throw new ArgumentNullException(nameof(messagesRequest)); + if (handler == null) + throw new ArgumentNullException(nameof(handler)); - fetchPrivateMsgReq.Success += messages => - { - handleUserMessages(messages); - lastUserMsgId = messages.LastOrDefault()?.Id ?? lastUserMsgId; - fetchPrivateMsgReq = null; - }; - fetchPrivateMsgReq.Failure += exception => Logger.Error(exception, "Fetching user messages failed."); + var messagesReq = messagesRequest.Invoke(); - api.Queue(fetchPrivateMsgReq); + messagesReq.Success += handler.Invoke; + messagesReq.Failure += exception => Logger.Error(exception, "Fetching messages failed."); + + api.Queue(messagesReq); } private void handleUserMessages(IEnumerable messages) @@ -218,23 +239,6 @@ namespace osu.Game.Online.Chat } } - private void fetchNewChannelMessages() - { - fetchMsgReq = new GetMessagesRequest(JoinedChannels.Where(c => c.Target == TargetType.Channel), lastChannelMsgId); - - fetchMsgReq.Success += messages => - { - if (messages == null) - return; - handleChannelMessages(messages); - lastChannelMsgId = messages.LastOrDefault()?.Id ?? lastChannelMsgId; - fetchMsgReq = null; - }; - fetchMsgReq.Failure += exception => Logger.Error(exception, "Fetching channel messages failed."); - - api.Queue(fetchMsgReq); - } - private void handleChannelMessages(IEnumerable messages) { var channels = JoinedChannels.ToList(); From 142e1b858707d2ce8f662e9b8ddb70cf2661a0c8 Mon Sep 17 00:00:00 2001 From: miterosan Date: Sat, 14 Apr 2018 13:32:48 +0200 Subject: [PATCH 025/155] update the line endings --- .../Visual/TestCaseChatTabControl.cs | 194 ++--- osu.Game/Online/API/APIMessagesRequest.cs | 56 +- .../API/Requests/GetPrivateMessagesRequest.cs | 34 +- osu.Game/Online/Chat/ChannelManager.cs | 604 ++++++++-------- osu.Game/Overlays/Chat/ChannelTabControl.cs | 662 +++++++++--------- .../Overlays/Chat/ChatTabItemCloseButton.cs | 110 +-- osu.Game/Overlays/Chat/UserTabControl.cs | 92 +-- osu.Game/Overlays/Chat/UserTabItem.cs | 430 ++++++------ 8 files changed, 1091 insertions(+), 1091 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseChatTabControl.cs b/osu.Game.Tests/Visual/TestCaseChatTabControl.cs index 0e0a44ba5d..ac5d59a74f 100644 --- a/osu.Game.Tests/Visual/TestCaseChatTabControl.cs +++ b/osu.Game.Tests/Visual/TestCaseChatTabControl.cs @@ -1,97 +1,97 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System; -using System.Collections.Generic; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osu.Framework.MathUtils; -using osu.Game.Online.Chat; -using osu.Game.Overlays.Chat; -using osu.Game.Users; -using OpenTK.Graphics; - -namespace osu.Game.Tests.Visual -{ - public class TestCaseChatTabControl : OsuTestCase - { - public override IReadOnlyList RequiredTypes => new[] - { - typeof(ChatTabControl), - typeof(ChannelTabControl), - typeof(UserTabControl) - }; - - private readonly ChatTabControl chatTabControl; - - public TestCaseChatTabControl() - { - SpriteText currentText; - Add(new Container - { - RelativeSizeAxes = Axes.X, - Origin = Anchor.Centre, - Anchor = Anchor.Centre, - Children = new Drawable[] - { - chatTabControl = new ChatTabControl - { - RelativeSizeAxes = Axes.X, - Origin = Anchor.Centre, - Anchor = Anchor.Centre, - Height = 50 - }, - new Box - { - Colour = Color4.Black.Opacity(0.1f), - RelativeSizeAxes = Axes.X, - Height = 50, - Depth = -1, - Origin = Anchor.Centre, - Anchor = Anchor.Centre, - } - } - }); - - Add(new Container - { - Origin = Anchor.TopLeft, - Anchor = Anchor.TopLeft, - Children = new Drawable[] - { - currentText = new SpriteText - { - Text = "Currently selected chat: " - } - } - }); - - chatTabControl.OnRequestLeave += chat => chatTabControl.RemoveItem(chat); - chatTabControl.Current.ValueChanged += chat => currentText.Text = "Currently selected chat: " + chat.ToString(); - - AddStep("Add random user", () => addUser(RNG.Next(100000), RNG.Next().ToString())); - AddRepeatStep("3 random users", () => addUser(RNG.Next(100000), RNG.Next().ToString()), 3); - AddStep("Add random channel", () => addChannel(RNG.Next().ToString())); - } - - private void addUser(long id, string name) - { - chatTabControl.AddItem(new Channel(new User - { - Id = id, - Username = name - })); - } - - private void addChannel(string name) - { - chatTabControl.AddItem(new Channel - { - Name = name - }); - } - } -} +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.MathUtils; +using osu.Game.Online.Chat; +using osu.Game.Overlays.Chat; +using osu.Game.Users; +using OpenTK.Graphics; + +namespace osu.Game.Tests.Visual +{ + public class TestCaseChatTabControl : OsuTestCase + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(ChatTabControl), + typeof(ChannelTabControl), + typeof(UserTabControl) + }; + + private readonly ChatTabControl chatTabControl; + + public TestCaseChatTabControl() + { + SpriteText currentText; + Add(new Container + { + RelativeSizeAxes = Axes.X, + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Children = new Drawable[] + { + chatTabControl = new ChatTabControl + { + RelativeSizeAxes = Axes.X, + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Height = 50 + }, + new Box + { + Colour = Color4.Black.Opacity(0.1f), + RelativeSizeAxes = Axes.X, + Height = 50, + Depth = -1, + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + } + } + }); + + Add(new Container + { + Origin = Anchor.TopLeft, + Anchor = Anchor.TopLeft, + Children = new Drawable[] + { + currentText = new SpriteText + { + Text = "Currently selected chat: " + } + } + }); + + chatTabControl.OnRequestLeave += chat => chatTabControl.RemoveItem(chat); + chatTabControl.Current.ValueChanged += chat => currentText.Text = "Currently selected chat: " + chat.ToString(); + + AddStep("Add random user", () => addUser(RNG.Next(100000), RNG.Next().ToString())); + AddRepeatStep("3 random users", () => addUser(RNG.Next(100000), RNG.Next().ToString()), 3); + AddStep("Add random channel", () => addChannel(RNG.Next().ToString())); + } + + private void addUser(long id, string name) + { + chatTabControl.AddItem(new Channel(new User + { + Id = id, + Username = name + })); + } + + private void addChannel(string name) + { + chatTabControl.AddItem(new Channel + { + Name = name + }); + } + } +} diff --git a/osu.Game/Online/API/APIMessagesRequest.cs b/osu.Game/Online/API/APIMessagesRequest.cs index e1be6cdb19..c957564771 100644 --- a/osu.Game/Online/API/APIMessagesRequest.cs +++ b/osu.Game/Online/API/APIMessagesRequest.cs @@ -1,28 +1,28 @@ -// 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 osu.Framework.IO.Network; -using osu.Game.Online.Chat; - -namespace osu.Game.Online.API -{ - public abstract class APIMessagesRequest : APIRequest> - { - private long? sinceId; - - protected APIMessagesRequest(long? sinceId) - { - this.sinceId = sinceId; - } - - protected override WebRequest CreateWebRequest() - { - var req = base.CreateWebRequest(); - - if (sinceId.HasValue) req.AddParameter(@"since", sinceId.Value.ToString()); - - return req; - } - } -} +// 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 osu.Framework.IO.Network; +using osu.Game.Online.Chat; + +namespace osu.Game.Online.API +{ + public abstract class APIMessagesRequest : APIRequest> + { + private long? sinceId; + + protected APIMessagesRequest(long? sinceId) + { + this.sinceId = sinceId; + } + + protected override WebRequest CreateWebRequest() + { + var req = base.CreateWebRequest(); + + if (sinceId.HasValue) req.AddParameter(@"since", sinceId.Value.ToString()); + + return req; + } + } +} diff --git a/osu.Game/Online/API/Requests/GetPrivateMessagesRequest.cs b/osu.Game/Online/API/Requests/GetPrivateMessagesRequest.cs index b5d7bb06ee..dddcbe8939 100644 --- a/osu.Game/Online/API/Requests/GetPrivateMessagesRequest.cs +++ b/osu.Game/Online/API/Requests/GetPrivateMessagesRequest.cs @@ -1,17 +1,17 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -namespace osu.Game.Online.API.Requests -{ - public class GetPrivateMessagesRequest : APIMessagesRequest - { - private long? since; - - public GetPrivateMessagesRequest(long? sinceId = null) - : base(sinceId) - { - } - - protected override string Target => @"chat/messages/private"; - } -} +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +namespace osu.Game.Online.API.Requests +{ + public class GetPrivateMessagesRequest : APIMessagesRequest + { + private long? since; + + public GetPrivateMessagesRequest(long? sinceId = null) + : base(sinceId) + { + } + + protected override string Target => @"chat/messages/private"; + } +} diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 3709e42880..069b88565d 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -1,302 +1,302 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using osu.Framework.Allocation; -using osu.Framework.Configuration; -using osu.Framework.Extensions.IEnumerableExtensions; -using osu.Framework.Graphics; -using osu.Framework.Logging; -using osu.Framework.Threading; -using osu.Game.Online.API; -using osu.Game.Online.API.Requests; -using osu.Game.Users; - -namespace osu.Game.Online.Chat -{ - /// - /// Manages everything channel related - /// - public class ChannelManager : Component, IOnlineComponent - { - /// - /// The channels the player joins on startup - /// - private readonly string[] defaultChannels = - { - @"#lazer", - @"#osu", - @"#lobby" - }; - - /// - /// The currently opened channel - /// - public Bindable CurrentChannel { get; } = new Bindable(); - - /// - /// The Channels the player has joined - /// - public ObservableCollection JoinedChannels { get; } = new ObservableCollection(); - - /// - /// The channels available for the player to join - /// - public ObservableCollection AvailableChannels { get; } = new ObservableCollection(); - - private APIAccess api; - private readonly Scheduler scheduler; - private ScheduledDelegate fetchMessagesScheduleder; - private GetMessagesRequest fetchMsgReq; - private GetPrivateMessagesRequest fetchPrivateMsgReq; - private long? lastChannelMsgId; - private long? lastUserMsgId; - - public void OpenChannel(string name) - { - if (name == null) - throw new ArgumentNullException(nameof(name)); - - CurrentChannel.Value = AvailableChannels.FirstOrDefault(c => c.Name == name) - ?? throw new ArgumentException($"Channel {name} was not found."); - } - - public void OpenUserChannel(User user) - { - if (user == null) - throw new ArgumentNullException(nameof(user)); - - CurrentChannel.Value = JoinedChannels.FirstOrDefault(c => c.Target == TargetType.User && c.Id == user.Id) - ?? new Channel(user); - } - - public ChannelManager() - { - CurrentChannel.ValueChanged += currentChannelChanged; - } - - private void currentChannelChanged(Channel channel) - { - if (!JoinedChannels.Contains(channel)) - JoinedChannels.Add(channel); - } - - /// - /// Posts a message to the currently opened channel. - /// - /// The message text that is going to be posted - /// Is true if the message is an action, e.g.: user is currently eating - public void PostMessage(string text, bool isAction = false) - { - if (CurrentChannel.Value == null) - return; - - if (!api.IsLoggedIn) - { - CurrentChannel.Value.AddNewMessages(new ErrorMessage("Please sign in to participate in chat!")); - return; - } - - var message = new LocalEchoMessage - { - Sender = api.LocalUser.Value, - Timestamp = DateTimeOffset.Now, - TargetType = CurrentChannel.Value.Target, - TargetId = CurrentChannel.Value.Id, - IsAction = isAction, - Content = text - }; - - CurrentChannel.Value.AddLocalEcho(message); - - var req = new PostMessageRequest(message); - req.Failure += e => CurrentChannel.Value?.ReplaceMessage(message, null); - req.Success += m => CurrentChannel.Value?.ReplaceMessage(message, m); - api.Queue(req); - } - - public void PostCommand(string text) - { - if (CurrentChannel.Value == null) - return; - - var parameters = text.Split(new[] { ' ' }, 2); - string command = parameters[0]; - string content = parameters.Length == 2 ? parameters[1] : string.Empty; - - switch (command) - { - case "me": - if (string.IsNullOrWhiteSpace(content)) - { - CurrentChannel.Value.AddNewMessages(new ErrorMessage("Usage: /me [action]")); - break; - } - - PostMessage(content, true); - break; - - case "help": - CurrentChannel.Value.AddNewMessages(new InfoMessage("Supported commands: /help, /me [action]")); - break; - - default: - CurrentChannel.Value.AddNewMessages(new ErrorMessage($@"""/{command}"" is not supported! For a list of supported commands see /help")); - break; - } - } - - private void fetchNewMessages() - { - if (fetchMsgReq == null) - fetchMessages( - () => new GetMessagesRequest(JoinedChannels.Where(c => c.Target == TargetType.Channel), lastChannelMsgId), - messages => - { - if (messages == null) - return; - handleChannelMessages(messages); - lastChannelMsgId = messages.LastOrDefault()?.Id ?? lastChannelMsgId; - fetchMsgReq = null; - } - ); - - - if (fetchPrivateMsgReq == null) - fetchMessages( - () => new GetPrivateMessagesRequest(lastChannelMsgId), - messages => - { - if (messages == null) - return; - handleUserMessages(messages); - lastUserMsgId = messages.LastOrDefault()?.Id ?? lastUserMsgId; - fetchPrivateMsgReq = null; - } - ); - } - - private void fetchMessages(Func messagesRequest, Action> handler) - { - if (messagesRequest == null) - throw new ArgumentNullException(nameof(messagesRequest)); - if (handler == null) - throw new ArgumentNullException(nameof(handler)); - - var messagesReq = messagesRequest.Invoke(); - - messagesReq.Success += handler.Invoke; - messagesReq.Failure += exception => Logger.Error(exception, "Fetching messages failed."); - - api.Queue(messagesReq); - } - - private void handleUserMessages(IEnumerable messages) - { - var joinedUserChannels = JoinedChannels.Where(c => c.Target == TargetType.User).ToList(); - - var outgoingMessages = messages.Where(m => m.Sender.Id == api.LocalUser.Value.Id); - var outgoingMessagesGroups = outgoingMessages.GroupBy(m => m.TargetId); - var incomingMessagesGroups = messages.Except(outgoingMessages).GroupBy(m => m.UserId); - - foreach (var messageGroup in incomingMessagesGroups) - { - var targetUser = messageGroup.First().Sender; - var channel = joinedUserChannels.FirstOrDefault(c => c.Id == targetUser.Id); - - if (channel == null) - { - channel = new Channel(targetUser); - JoinedChannels.Add(channel); - joinedUserChannels.Add(channel); - } - - channel.AddNewMessages(messageGroup.ToArray()); - var outgoingTargetMessages = outgoingMessagesGroups.FirstOrDefault(g => g.Key == targetUser.Id); - if (outgoingTargetMessages != null) - channel.AddNewMessages(outgoingTargetMessages.ToArray()); - } - - var withoutReplyGroups = outgoingMessagesGroups.Where(g => joinedUserChannels.All(m => m.Id != g.Key)); - - foreach (var withoutReplyGroup in withoutReplyGroups) - { - var userReq = new GetUserRequest(withoutReplyGroup.First().TargetId); - - userReq.Failure += exception => Logger.Error(exception, "Failed to get user informations."); - userReq.Success += user => - { - var channel = new Channel(user); - - channel.AddNewMessages(withoutReplyGroup.ToArray()); - JoinedChannels.Add(channel); - }; - - api.Queue(userReq); - } - } - - private void handleChannelMessages(IEnumerable messages) - { - var channels = JoinedChannels.ToList(); - - foreach (var group in messages.GroupBy(m => m.TargetId)) - channels.Find(c => c.Id == group.Key)?.AddNewMessages(group.ToArray()); - } - - private void initializeDefaultChannels() - { - var req = new ListChannelsRequest(); - - req.Success += channels => - { - channels.Where(channel => AvailableChannels.All(c => c.Id != channel.Id)) - .ForEach(channel => AvailableChannels.Add(channel)); - - channels.Where(channel => defaultChannels.Contains(channel.Name)) - .Where(channel => JoinedChannels.All(c => c.Id != channel.Id)) - .ForEach(channel => - { - JoinedChannels.Add(channel); - - var fetchInitialMsgReq = new GetMessagesRequest(new[] { channel }, null); - fetchInitialMsgReq.Success += handleChannelMessages; - fetchInitialMsgReq.Failure += exception => Logger.Error(exception, "Failed to fetch inital messages."); - api.Queue(fetchInitialMsgReq); - }); - - fetchNewMessages(); - }; - req.Failure += error => Logger.Error(error, "Fetching channel list failed"); - - api.Queue(req); - } - - public void APIStateChanged(APIAccess api, APIState state) - { - switch (state) - { - case APIState.Online: - if (JoinedChannels.Count == 0) - initializeDefaultChannels(); - fetchMessagesScheduleder = scheduler.AddDelayed(fetchNewMessages, 1000, true); - break; - default: - fetchMsgReq?.Cancel(); - fetchMsgReq = null; - fetchMessagesScheduleder?.Cancel(); - break; - } - } - - [BackgroundDependencyLoader] - private void load(IAPIProvider api) - { - this.api = this.api; - api.Register(this); - } - } -} +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Configuration; +using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Framework.Graphics; +using osu.Framework.Logging; +using osu.Framework.Threading; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; +using osu.Game.Users; + +namespace osu.Game.Online.Chat +{ + /// + /// Manages everything channel related + /// + public class ChannelManager : Component, IOnlineComponent + { + /// + /// The channels the player joins on startup + /// + private readonly string[] defaultChannels = + { + @"#lazer", + @"#osu", + @"#lobby" + }; + + /// + /// The currently opened channel + /// + public Bindable CurrentChannel { get; } = new Bindable(); + + /// + /// The Channels the player has joined + /// + public ObservableCollection JoinedChannels { get; } = new ObservableCollection(); + + /// + /// The channels available for the player to join + /// + public ObservableCollection AvailableChannels { get; } = new ObservableCollection(); + + private APIAccess api; + private readonly Scheduler scheduler; + private ScheduledDelegate fetchMessagesScheduleder; + private GetMessagesRequest fetchMsgReq; + private GetPrivateMessagesRequest fetchPrivateMsgReq; + private long? lastChannelMsgId; + private long? lastUserMsgId; + + public void OpenChannel(string name) + { + if (name == null) + throw new ArgumentNullException(nameof(name)); + + CurrentChannel.Value = AvailableChannels.FirstOrDefault(c => c.Name == name) + ?? throw new ArgumentException($"Channel {name} was not found."); + } + + public void OpenUserChannel(User user) + { + if (user == null) + throw new ArgumentNullException(nameof(user)); + + CurrentChannel.Value = JoinedChannels.FirstOrDefault(c => c.Target == TargetType.User && c.Id == user.Id) + ?? new Channel(user); + } + + public ChannelManager() + { + CurrentChannel.ValueChanged += currentChannelChanged; + } + + private void currentChannelChanged(Channel channel) + { + if (!JoinedChannels.Contains(channel)) + JoinedChannels.Add(channel); + } + + /// + /// Posts a message to the currently opened channel. + /// + /// The message text that is going to be posted + /// Is true if the message is an action, e.g.: user is currently eating + public void PostMessage(string text, bool isAction = false) + { + if (CurrentChannel.Value == null) + return; + + if (!api.IsLoggedIn) + { + CurrentChannel.Value.AddNewMessages(new ErrorMessage("Please sign in to participate in chat!")); + return; + } + + var message = new LocalEchoMessage + { + Sender = api.LocalUser.Value, + Timestamp = DateTimeOffset.Now, + TargetType = CurrentChannel.Value.Target, + TargetId = CurrentChannel.Value.Id, + IsAction = isAction, + Content = text + }; + + CurrentChannel.Value.AddLocalEcho(message); + + var req = new PostMessageRequest(message); + req.Failure += e => CurrentChannel.Value?.ReplaceMessage(message, null); + req.Success += m => CurrentChannel.Value?.ReplaceMessage(message, m); + api.Queue(req); + } + + public void PostCommand(string text) + { + if (CurrentChannel.Value == null) + return; + + var parameters = text.Split(new[] { ' ' }, 2); + string command = parameters[0]; + string content = parameters.Length == 2 ? parameters[1] : string.Empty; + + switch (command) + { + case "me": + if (string.IsNullOrWhiteSpace(content)) + { + CurrentChannel.Value.AddNewMessages(new ErrorMessage("Usage: /me [action]")); + break; + } + + PostMessage(content, true); + break; + + case "help": + CurrentChannel.Value.AddNewMessages(new InfoMessage("Supported commands: /help, /me [action]")); + break; + + default: + CurrentChannel.Value.AddNewMessages(new ErrorMessage($@"""/{command}"" is not supported! For a list of supported commands see /help")); + break; + } + } + + private void fetchNewMessages() + { + if (fetchMsgReq == null) + fetchMessages( + () => new GetMessagesRequest(JoinedChannels.Where(c => c.Target == TargetType.Channel), lastChannelMsgId), + messages => + { + if (messages == null) + return; + handleChannelMessages(messages); + lastChannelMsgId = messages.LastOrDefault()?.Id ?? lastChannelMsgId; + fetchMsgReq = null; + } + ); + + + if (fetchPrivateMsgReq == null) + fetchMessages( + () => new GetPrivateMessagesRequest(lastChannelMsgId), + messages => + { + if (messages == null) + return; + handleUserMessages(messages); + lastUserMsgId = messages.LastOrDefault()?.Id ?? lastUserMsgId; + fetchPrivateMsgReq = null; + } + ); + } + + private void fetchMessages(Func messagesRequest, Action> handler) + { + if (messagesRequest == null) + throw new ArgumentNullException(nameof(messagesRequest)); + if (handler == null) + throw new ArgumentNullException(nameof(handler)); + + var messagesReq = messagesRequest.Invoke(); + + messagesReq.Success += handler.Invoke; + messagesReq.Failure += exception => Logger.Error(exception, "Fetching messages failed."); + + api.Queue(messagesReq); + } + + private void handleUserMessages(IEnumerable messages) + { + var joinedUserChannels = JoinedChannels.Where(c => c.Target == TargetType.User).ToList(); + + var outgoingMessages = messages.Where(m => m.Sender.Id == api.LocalUser.Value.Id); + var outgoingMessagesGroups = outgoingMessages.GroupBy(m => m.TargetId); + var incomingMessagesGroups = messages.Except(outgoingMessages).GroupBy(m => m.UserId); + + foreach (var messageGroup in incomingMessagesGroups) + { + var targetUser = messageGroup.First().Sender; + var channel = joinedUserChannels.FirstOrDefault(c => c.Id == targetUser.Id); + + if (channel == null) + { + channel = new Channel(targetUser); + JoinedChannels.Add(channel); + joinedUserChannels.Add(channel); + } + + channel.AddNewMessages(messageGroup.ToArray()); + var outgoingTargetMessages = outgoingMessagesGroups.FirstOrDefault(g => g.Key == targetUser.Id); + if (outgoingTargetMessages != null) + channel.AddNewMessages(outgoingTargetMessages.ToArray()); + } + + var withoutReplyGroups = outgoingMessagesGroups.Where(g => joinedUserChannels.All(m => m.Id != g.Key)); + + foreach (var withoutReplyGroup in withoutReplyGroups) + { + var userReq = new GetUserRequest(withoutReplyGroup.First().TargetId); + + userReq.Failure += exception => Logger.Error(exception, "Failed to get user informations."); + userReq.Success += user => + { + var channel = new Channel(user); + + channel.AddNewMessages(withoutReplyGroup.ToArray()); + JoinedChannels.Add(channel); + }; + + api.Queue(userReq); + } + } + + private void handleChannelMessages(IEnumerable messages) + { + var channels = JoinedChannels.ToList(); + + foreach (var group in messages.GroupBy(m => m.TargetId)) + channels.Find(c => c.Id == group.Key)?.AddNewMessages(group.ToArray()); + } + + private void initializeDefaultChannels() + { + var req = new ListChannelsRequest(); + + req.Success += channels => + { + channels.Where(channel => AvailableChannels.All(c => c.Id != channel.Id)) + .ForEach(channel => AvailableChannels.Add(channel)); + + channels.Where(channel => defaultChannels.Contains(channel.Name)) + .Where(channel => JoinedChannels.All(c => c.Id != channel.Id)) + .ForEach(channel => + { + JoinedChannels.Add(channel); + + var fetchInitialMsgReq = new GetMessagesRequest(new[] { channel }, null); + fetchInitialMsgReq.Success += handleChannelMessages; + fetchInitialMsgReq.Failure += exception => Logger.Error(exception, "Failed to fetch inital messages."); + api.Queue(fetchInitialMsgReq); + }); + + fetchNewMessages(); + }; + req.Failure += error => Logger.Error(error, "Fetching channel list failed"); + + api.Queue(req); + } + + public void APIStateChanged(APIAccess api, APIState state) + { + switch (state) + { + case APIState.Online: + if (JoinedChannels.Count == 0) + initializeDefaultChannels(); + fetchMessagesScheduleder = scheduler.AddDelayed(fetchNewMessages, 1000, true); + break; + default: + fetchMsgReq?.Cancel(); + fetchMsgReq = null; + fetchMessagesScheduleder?.Cancel(); + break; + } + } + + [BackgroundDependencyLoader] + private void load(IAPIProvider api) + { + this.api = this.api; + api.Register(this); + } + } +} diff --git a/osu.Game/Overlays/Chat/ChannelTabControl.cs b/osu.Game/Overlays/Chat/ChannelTabControl.cs index 9c07294a50..66ee4285d3 100644 --- a/osu.Game/Overlays/Chat/ChannelTabControl.cs +++ b/osu.Game/Overlays/Chat/ChannelTabControl.cs @@ -1,331 +1,331 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using osu.Framework.Allocation; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Graphics.UserInterface; -using osu.Framework.Input; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; -using osu.Game.Online.Chat; -using OpenTK; -using OpenTK.Graphics; -using osu.Framework.Configuration; -using System; -using osu.Game.Graphics.Containers; - -namespace osu.Game.Overlays.Chat -{ - public class ChannelTabControl : OsuTabControl - { - private const float shear_width = 10; - - public Action OnRequestLeave; - - public readonly Bindable ChannelSelectorActive = new Bindable(); - - private readonly ChannelTabItem.ChannelSelectorTabItem selectorTab; - - public ChannelTabControl() - { - TabContainer.Margin = new MarginPadding { Left = 50 }; - TabContainer.Spacing = new Vector2(-shear_width, 0); - TabContainer.Masking = false; - - AddInternal(new SpriteIcon - { - Icon = FontAwesome.fa_comments, - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Size = new Vector2(20), - Margin = new MarginPadding(10), - }); - - AddTabItem(selectorTab = new ChannelTabItem.ChannelSelectorTabItem(new Channel { Name = "+" })); - - ChannelSelectorActive.BindTo(selectorTab.Active); - } - - protected override void AddTabItem(TabItem item, bool addToDropdown = true) - { - if (item != selectorTab && TabContainer.GetLayoutPosition(selectorTab) < float.MaxValue) - // performTabSort might've made selectorTab's position wonky, fix it - TabContainer.SetLayoutPosition(selectorTab, float.MaxValue); - - base.AddTabItem(item, addToDropdown); - } - - protected override TabItem CreateTabItem(Channel value) => new ChannelTabItem(value) { OnRequestClose = tabCloseRequested }; - - protected override void SelectTab(TabItem tab) - { - if (tab is ChannelTabItem.ChannelSelectorTabItem) - { - tab.Active.Toggle(); - return; - } - - selectorTab.Active.Value = false; - - base.SelectTab(tab); - } - - private void tabCloseRequested(TabItem tab) - { - int totalTabs = TabContainer.Count - 1; // account for selectorTab - int currentIndex = MathHelper.Clamp(TabContainer.IndexOf(tab), 1, totalTabs); - - if (tab == SelectedTab && totalTabs > 1) - // Select the tab after tab-to-be-removed's index, or the tab before if current == last - SelectTab(TabContainer[currentIndex == totalTabs ? currentIndex - 1 : currentIndex + 1]); - else if (totalTabs == 1 && !selectorTab.Active) - // Open channel selection overlay if all channel tabs will be closed after removing this tab - SelectTab(selectorTab); - - OnRequestLeave?.Invoke(tab.Value); - } - - private class ChannelTabItem : TabItem - { - private Color4 backgroundInactive; - private Color4 backgroundHover; - private Color4 backgroundActive; - - public override bool IsRemovable => !Pinned; - - private readonly SpriteText text; - private readonly SpriteText textBold; - private readonly ClickableContainer closeButton; - private readonly Box box; - private readonly Box highlightBox; - private readonly SpriteIcon icon; - - public Action OnRequestClose; - - private void updateState() - { - if (Active) - fadeActive(); - else - fadeInactive(); - } - - private const float transition_length = 400; - - private void fadeActive() - { - this.ResizeTo(new Vector2(Width, 1.1f), transition_length, Easing.OutQuint); - - box.FadeColour(backgroundActive, transition_length, Easing.OutQuint); - highlightBox.FadeIn(transition_length, Easing.OutQuint); - - text.FadeOut(transition_length, Easing.OutQuint); - textBold.FadeIn(transition_length, Easing.OutQuint); - } - - private void fadeInactive() - { - this.ResizeTo(new Vector2(Width, 1), transition_length, Easing.OutQuint); - - box.FadeColour(backgroundInactive, transition_length, Easing.OutQuint); - highlightBox.FadeOut(transition_length, Easing.OutQuint); - - text.FadeIn(transition_length, Easing.OutQuint); - textBold.FadeOut(transition_length, Easing.OutQuint); - } - - protected override bool OnHover(InputState state) - { - if (IsRemovable) - closeButton.FadeIn(200, Easing.OutQuint); - - if (!Active) - box.FadeColour(backgroundHover, transition_length, Easing.OutQuint); - return true; - } - - protected override void OnHoverLost(InputState state) - { - closeButton.FadeOut(200, Easing.OutQuint); - updateState(); - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - backgroundActive = colours.ChatBlue; - backgroundInactive = colours.Gray4; - backgroundHover = colours.Gray7; - - highlightBox.Colour = colours.Yellow; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - updateState(); - } - - public ChannelTabItem(Channel value) : base(value) - { - Width = 150; - - RelativeSizeAxes = Axes.Y; - - Anchor = Anchor.BottomLeft; - Origin = Anchor.BottomLeft; - - Shear = new Vector2(shear_width / ChatOverlay.TAB_AREA_HEIGHT, 0); - - Masking = true; - EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Shadow, - Radius = 10, - Colour = Color4.Black.Opacity(0.2f), - }; - - Children = new Drawable[] - { - box = new Box - { - EdgeSmoothness = new Vector2(1, 0), - RelativeSizeAxes = Axes.Both, - }, - highlightBox = new Box - { - Width = 5, - Alpha = 0, - Anchor = Anchor.BottomRight, - Origin = Anchor.BottomRight, - EdgeSmoothness = new Vector2(1, 0), - RelativeSizeAxes = Axes.Y, - }, - new Container - { - Shear = new Vector2(-shear_width / ChatOverlay.TAB_AREA_HEIGHT, 0), - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - icon = new SpriteIcon - { - Icon = FontAwesome.fa_hashtag, - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Colour = Color4.Black, - X = -10, - Alpha = 0.2f, - Size = new Vector2(ChatOverlay.TAB_AREA_HEIGHT), - }, - text = new OsuSpriteText - { - Margin = new MarginPadding(5), - Origin = Anchor.CentreLeft, - Anchor = Anchor.CentreLeft, - Text = value.ToString(), - TextSize = 18, - }, - textBold = new OsuSpriteText - { - Alpha = 0, - Margin = new MarginPadding(5), - Origin = Anchor.CentreLeft, - Anchor = Anchor.CentreLeft, - Text = value.ToString(), - Font = @"Exo2.0-Bold", - TextSize = 18, - }, - closeButton = new CloseButton - { - Alpha = 0, - Margin = new MarginPadding { Right = 20 }, - Origin = Anchor.CentreRight, - Anchor = Anchor.CentreRight, - Action = delegate - { - if (IsRemovable) OnRequestClose?.Invoke(this); - }, - }, - }, - }, - }; - } - - public class CloseButton : OsuClickableContainer - { - private readonly SpriteIcon icon; - - public CloseButton() - { - Size = new Vector2(20); - - Child = icon = new SpriteIcon - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Scale = new Vector2(0.75f), - Icon = FontAwesome.fa_close, - RelativeSizeAxes = Axes.Both, - }; - } - - protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) - { - icon.ScaleTo(0.5f, 1000, Easing.OutQuint); - return base.OnMouseDown(state, args); - } - - protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) - { - icon.ScaleTo(0.75f, 1000, Easing.OutElastic); - return base.OnMouseUp(state, args); - } - - protected override bool OnHover(InputState state) - { - icon.FadeColour(Color4.Red, 200, Easing.OutQuint); - return base.OnHover(state); - } - - protected override void OnHoverLost(InputState state) - { - icon.FadeColour(Color4.White, 200, Easing.OutQuint); - base.OnHoverLost(state); - } - } - - public class ChannelSelectorTabItem : ChannelTabItem - { - public override bool IsRemovable => false; - - public ChannelSelectorTabItem(Channel value) : base(value) - { - Depth = float.MaxValue; - Width = 45; - - icon.Alpha = 0; - - text.TextSize = 45; - textBold.TextSize = 45; - } - - [BackgroundDependencyLoader] - private new void load(OsuColour colour) - { - backgroundInactive = colour.Gray2; - backgroundActive = colour.Gray3; - } - } - - protected override void OnActivated() => updateState(); - - protected override void OnDeactivated() => updateState(); - } - } -} +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Online.Chat; +using OpenTK; +using OpenTK.Graphics; +using osu.Framework.Configuration; +using System; +using osu.Game.Graphics.Containers; + +namespace osu.Game.Overlays.Chat +{ + public class ChannelTabControl : OsuTabControl + { + private const float shear_width = 10; + + public Action OnRequestLeave; + + public readonly Bindable ChannelSelectorActive = new Bindable(); + + private readonly ChannelTabItem.ChannelSelectorTabItem selectorTab; + + public ChannelTabControl() + { + TabContainer.Margin = new MarginPadding { Left = 50 }; + TabContainer.Spacing = new Vector2(-shear_width, 0); + TabContainer.Masking = false; + + AddInternal(new SpriteIcon + { + Icon = FontAwesome.fa_comments, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Size = new Vector2(20), + Margin = new MarginPadding(10), + }); + + AddTabItem(selectorTab = new ChannelTabItem.ChannelSelectorTabItem(new Channel { Name = "+" })); + + ChannelSelectorActive.BindTo(selectorTab.Active); + } + + protected override void AddTabItem(TabItem item, bool addToDropdown = true) + { + if (item != selectorTab && TabContainer.GetLayoutPosition(selectorTab) < float.MaxValue) + // performTabSort might've made selectorTab's position wonky, fix it + TabContainer.SetLayoutPosition(selectorTab, float.MaxValue); + + base.AddTabItem(item, addToDropdown); + } + + protected override TabItem CreateTabItem(Channel value) => new ChannelTabItem(value) { OnRequestClose = tabCloseRequested }; + + protected override void SelectTab(TabItem tab) + { + if (tab is ChannelTabItem.ChannelSelectorTabItem) + { + tab.Active.Toggle(); + return; + } + + selectorTab.Active.Value = false; + + base.SelectTab(tab); + } + + private void tabCloseRequested(TabItem tab) + { + int totalTabs = TabContainer.Count - 1; // account for selectorTab + int currentIndex = MathHelper.Clamp(TabContainer.IndexOf(tab), 1, totalTabs); + + if (tab == SelectedTab && totalTabs > 1) + // Select the tab after tab-to-be-removed's index, or the tab before if current == last + SelectTab(TabContainer[currentIndex == totalTabs ? currentIndex - 1 : currentIndex + 1]); + else if (totalTabs == 1 && !selectorTab.Active) + // Open channel selection overlay if all channel tabs will be closed after removing this tab + SelectTab(selectorTab); + + OnRequestLeave?.Invoke(tab.Value); + } + + private class ChannelTabItem : TabItem + { + private Color4 backgroundInactive; + private Color4 backgroundHover; + private Color4 backgroundActive; + + public override bool IsRemovable => !Pinned; + + private readonly SpriteText text; + private readonly SpriteText textBold; + private readonly ClickableContainer closeButton; + private readonly Box box; + private readonly Box highlightBox; + private readonly SpriteIcon icon; + + public Action OnRequestClose; + + private void updateState() + { + if (Active) + fadeActive(); + else + fadeInactive(); + } + + private const float transition_length = 400; + + private void fadeActive() + { + this.ResizeTo(new Vector2(Width, 1.1f), transition_length, Easing.OutQuint); + + box.FadeColour(backgroundActive, transition_length, Easing.OutQuint); + highlightBox.FadeIn(transition_length, Easing.OutQuint); + + text.FadeOut(transition_length, Easing.OutQuint); + textBold.FadeIn(transition_length, Easing.OutQuint); + } + + private void fadeInactive() + { + this.ResizeTo(new Vector2(Width, 1), transition_length, Easing.OutQuint); + + box.FadeColour(backgroundInactive, transition_length, Easing.OutQuint); + highlightBox.FadeOut(transition_length, Easing.OutQuint); + + text.FadeIn(transition_length, Easing.OutQuint); + textBold.FadeOut(transition_length, Easing.OutQuint); + } + + protected override bool OnHover(InputState state) + { + if (IsRemovable) + closeButton.FadeIn(200, Easing.OutQuint); + + if (!Active) + box.FadeColour(backgroundHover, transition_length, Easing.OutQuint); + return true; + } + + protected override void OnHoverLost(InputState state) + { + closeButton.FadeOut(200, Easing.OutQuint); + updateState(); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + backgroundActive = colours.ChatBlue; + backgroundInactive = colours.Gray4; + backgroundHover = colours.Gray7; + + highlightBox.Colour = colours.Yellow; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + updateState(); + } + + public ChannelTabItem(Channel value) : base(value) + { + Width = 150; + + RelativeSizeAxes = Axes.Y; + + Anchor = Anchor.BottomLeft; + Origin = Anchor.BottomLeft; + + Shear = new Vector2(shear_width / ChatOverlay.TAB_AREA_HEIGHT, 0); + + Masking = true; + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Radius = 10, + Colour = Color4.Black.Opacity(0.2f), + }; + + Children = new Drawable[] + { + box = new Box + { + EdgeSmoothness = new Vector2(1, 0), + RelativeSizeAxes = Axes.Both, + }, + highlightBox = new Box + { + Width = 5, + Alpha = 0, + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + EdgeSmoothness = new Vector2(1, 0), + RelativeSizeAxes = Axes.Y, + }, + new Container + { + Shear = new Vector2(-shear_width / ChatOverlay.TAB_AREA_HEIGHT, 0), + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + icon = new SpriteIcon + { + Icon = FontAwesome.fa_hashtag, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Colour = Color4.Black, + X = -10, + Alpha = 0.2f, + Size = new Vector2(ChatOverlay.TAB_AREA_HEIGHT), + }, + text = new OsuSpriteText + { + Margin = new MarginPadding(5), + Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreLeft, + Text = value.ToString(), + TextSize = 18, + }, + textBold = new OsuSpriteText + { + Alpha = 0, + Margin = new MarginPadding(5), + Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreLeft, + Text = value.ToString(), + Font = @"Exo2.0-Bold", + TextSize = 18, + }, + closeButton = new CloseButton + { + Alpha = 0, + Margin = new MarginPadding { Right = 20 }, + Origin = Anchor.CentreRight, + Anchor = Anchor.CentreRight, + Action = delegate + { + if (IsRemovable) OnRequestClose?.Invoke(this); + }, + }, + }, + }, + }; + } + + public class CloseButton : OsuClickableContainer + { + private readonly SpriteIcon icon; + + public CloseButton() + { + Size = new Vector2(20); + + Child = icon = new SpriteIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Scale = new Vector2(0.75f), + Icon = FontAwesome.fa_close, + RelativeSizeAxes = Axes.Both, + }; + } + + protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) + { + icon.ScaleTo(0.5f, 1000, Easing.OutQuint); + return base.OnMouseDown(state, args); + } + + protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) + { + icon.ScaleTo(0.75f, 1000, Easing.OutElastic); + return base.OnMouseUp(state, args); + } + + protected override bool OnHover(InputState state) + { + icon.FadeColour(Color4.Red, 200, Easing.OutQuint); + return base.OnHover(state); + } + + protected override void OnHoverLost(InputState state) + { + icon.FadeColour(Color4.White, 200, Easing.OutQuint); + base.OnHoverLost(state); + } + } + + public class ChannelSelectorTabItem : ChannelTabItem + { + public override bool IsRemovable => false; + + public ChannelSelectorTabItem(Channel value) : base(value) + { + Depth = float.MaxValue; + Width = 45; + + icon.Alpha = 0; + + text.TextSize = 45; + textBold.TextSize = 45; + } + + [BackgroundDependencyLoader] + private new void load(OsuColour colour) + { + backgroundInactive = colour.Gray2; + backgroundActive = colour.Gray3; + } + } + + protected override void OnActivated() => updateState(); + + protected override void OnDeactivated() => updateState(); + } + } +} diff --git a/osu.Game/Overlays/Chat/ChatTabItemCloseButton.cs b/osu.Game/Overlays/Chat/ChatTabItemCloseButton.cs index e87396356a..0ec2e52963 100644 --- a/osu.Game/Overlays/Chat/ChatTabItemCloseButton.cs +++ b/osu.Game/Overlays/Chat/ChatTabItemCloseButton.cs @@ -1,55 +1,55 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using osu.Framework.Graphics; -using osu.Framework.Input; -using osu.Game.Graphics; -using osu.Game.Graphics.Containers; -using OpenTK; -using OpenTK.Graphics; - -namespace osu.Game.Overlays.Chat -{ - public class ChatTabItemCloseButton : OsuClickableContainer - { - private readonly SpriteIcon icon; - - public ChatTabItemCloseButton() - { - Size = new Vector2(20); - - Child = icon = new SpriteIcon - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Scale = new Vector2(0.75f), - Icon = FontAwesome.fa_close, - RelativeSizeAxes = Axes.Both, - }; - } - - protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) - { - icon.ScaleTo(0.5f, 1000, Easing.OutQuint); - return base.OnMouseDown(state, args); - } - - protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) - { - icon.ScaleTo(0.75f, 1000, Easing.OutElastic); - return base.OnMouseUp(state, args); - } - - protected override bool OnHover(InputState state) - { - icon.FadeColour(Color4.Red, 200, Easing.OutQuint); - return base.OnHover(state); - } - - protected override void OnHoverLost(InputState state) - { - icon.FadeColour(Color4.White, 200, Easing.OutQuint); - base.OnHoverLost(state); - } - } -} +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics; +using osu.Framework.Input; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using OpenTK; +using OpenTK.Graphics; + +namespace osu.Game.Overlays.Chat +{ + public class ChatTabItemCloseButton : OsuClickableContainer + { + private readonly SpriteIcon icon; + + public ChatTabItemCloseButton() + { + Size = new Vector2(20); + + Child = icon = new SpriteIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Scale = new Vector2(0.75f), + Icon = FontAwesome.fa_close, + RelativeSizeAxes = Axes.Both, + }; + } + + protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) + { + icon.ScaleTo(0.5f, 1000, Easing.OutQuint); + return base.OnMouseDown(state, args); + } + + protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) + { + icon.ScaleTo(0.75f, 1000, Easing.OutElastic); + return base.OnMouseUp(state, args); + } + + protected override bool OnHover(InputState state) + { + icon.FadeColour(Color4.Red, 200, Easing.OutQuint); + return base.OnHover(state); + } + + protected override void OnHoverLost(InputState state) + { + icon.FadeColour(Color4.White, 200, Easing.OutQuint); + base.OnHoverLost(state); + } + } +} diff --git a/osu.Game/Overlays/Chat/UserTabControl.cs b/osu.Game/Overlays/Chat/UserTabControl.cs index 5e23b4c2eb..7da7cab900 100644 --- a/osu.Game/Overlays/Chat/UserTabControl.cs +++ b/osu.Game/Overlays/Chat/UserTabControl.cs @@ -1,46 +1,46 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System; -using osu.Framework.Graphics; -using osu.Framework.Graphics.UserInterface; -using osu.Game.Graphics.UserInterface; -using osu.Game.Online.Chat; -using OpenTK; - -namespace osu.Game.Overlays.Chat -{ - public class UserTabControl : OsuTabControl - { - protected override TabItem CreateTabItem(Channel value) - { - if (value.Target != TargetType.User) - throw new ArgumentException("Argument value needs to have the targettype user."); - return new UserTabItem(value) { OnRequestClose = tabCloseRequested }; - } - - public Action OnRequestLeave; - - public UserTabControl() - { - TabContainer.Spacing = new Vector2(-10, 0); - TabContainer.Masking = false; - Margin = new MarginPadding - { - Right = 10 - }; - } - - private void tabCloseRequested(TabItem priv) - { - int totalTabs = TabContainer.Count -1; // account for selectorTab - int currentIndex = MathHelper.Clamp(TabContainer.IndexOf(priv), 1, totalTabs); - - if (priv == SelectedTab && totalTabs > 1) - // Select the tab after tab-to-be-removed's index, or the tab before if current == last - SelectTab(TabContainer[currentIndex == totalTabs ? currentIndex - 1 : currentIndex + 1]); - - OnRequestLeave?.Invoke(priv.Value); - } - } -} +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using osu.Framework.Graphics; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Graphics.UserInterface; +using osu.Game.Online.Chat; +using OpenTK; + +namespace osu.Game.Overlays.Chat +{ + public class UserTabControl : OsuTabControl + { + protected override TabItem CreateTabItem(Channel value) + { + if (value.Target != TargetType.User) + throw new ArgumentException("Argument value needs to have the targettype user."); + return new UserTabItem(value) { OnRequestClose = tabCloseRequested }; + } + + public Action OnRequestLeave; + + public UserTabControl() + { + TabContainer.Spacing = new Vector2(-10, 0); + TabContainer.Masking = false; + Margin = new MarginPadding + { + Right = 10 + }; + } + + private void tabCloseRequested(TabItem priv) + { + int totalTabs = TabContainer.Count -1; // account for selectorTab + int currentIndex = MathHelper.Clamp(TabContainer.IndexOf(priv), 1, totalTabs); + + if (priv == SelectedTab && totalTabs > 1) + // Select the tab after tab-to-be-removed's index, or the tab before if current == last + SelectTab(TabContainer[currentIndex == totalTabs ? currentIndex - 1 : currentIndex + 1]); + + OnRequestLeave?.Invoke(priv.Value); + } + } +} diff --git a/osu.Game/Overlays/Chat/UserTabItem.cs b/osu.Game/Overlays/Chat/UserTabItem.cs index 3dfec0b7ea..86dc6c23e6 100644 --- a/osu.Game/Overlays/Chat/UserTabItem.cs +++ b/osu.Game/Overlays/Chat/UserTabItem.cs @@ -1,215 +1,215 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System; -using System.Linq; -using osu.Framework.Allocation; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.UserInterface; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Game.Online.Chat; -using osu.Game.Screens.Menu; -using osu.Game.Users; -using OpenTK; -using OpenTK.Graphics; - -namespace osu.Game.Overlays.Chat -{ - public class UserTabItem : TabItem - { - private static readonly Vector2 shear = new Vector2(1f / 5f, 0); - public override bool IsRemovable => true; - - private readonly Box highlightBox; - private readonly Container backgroundContainer; - private readonly Box backgroundBox; - private readonly OsuSpriteText username; - private readonly Avatar avatarContainer; - private readonly ChatTabItemCloseButton closeButton; - - public UserTabItem(Channel value) - : base(value) - { - if (value.Target != TargetType.User) - throw new ArgumentException("Argument value needs to have the targettype user!"); - - AutoSizeAxes = Axes.X; - Height = 50; - Origin = Anchor.BottomRight; - Anchor = Anchor.BottomRight; - EdgeEffect = activateEdgeEffect; - Masking = true; - Shear = shear; - Children = new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - backgroundBox = new Box - { - RelativeSizeAxes = Axes.Both, - Origin = Anchor.BottomLeft, - Anchor = Anchor.BottomLeft, - EdgeSmoothness = new Vector2(1, 0), - }, - } - }, - highlightBox = new Box - { - Width = 5, - BypassAutoSizeAxes = Axes.X, - Alpha = 0, - Anchor = Anchor.BottomRight, - Origin = Anchor.BottomRight, - EdgeSmoothness = new Vector2(1, 0), - RelativeSizeAxes = Axes.Y, - Colour = new OsuColour().Yellow - }, - new Container - { - Masking = true, - AutoSizeAxes = Axes.X, - RelativeSizeAxes = Axes.Y, - Child = new FlowContainerWithOrigin - { - AutoSizeAxes = Axes.X, - RelativeSizeAxes = Axes.Y, - X = -5, - Direction = FillDirection.Horizontal, - Origin = Anchor.TopLeft, - Anchor = Anchor.TopLeft, - Shear = -shear, - Children = new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.Y, - AutoSizeAxes = Axes.X, - Margin = new MarginPadding - { - Horizontal = 5 - }, - Origin = Anchor.BottomLeft, - Anchor = Anchor.BottomLeft, - Children = new Drawable[] - { - new SpriteIcon - { - Icon = FontAwesome.fa_eercast, - Origin = Anchor.Centre, - Scale = new Vector2(1.2f), - X = -5, - Y = 5, - Anchor = Anchor.Centre, - Colour = new OsuColour().BlueDarker, - RelativeSizeAxes = Axes.Both, - }, - new CircularContainer - { - RelativeSizeAxes = Axes.Y, - Scale = new Vector2(0.95f), - AutoSizeAxes = Axes.X, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Masking = true, - Child = new DelayedLoadWrapper(new Avatar(value.JoinedUsers.First()) - { - Size = new Vector2(ChatOverlay.TAB_AREA_HEIGHT), - OnLoadComplete = d => d.FadeInFromZero(300, Easing.OutQuint), - }) - { - Size = new Vector2(ChatOverlay.TAB_AREA_HEIGHT), - } - }, - } - }, - username = new OsuSpriteText - { - Origin = Anchor.CentreLeft, - Anchor = Anchor.CentreLeft, - Text = value.Name, - Margin = new MarginPadding(1), - TextSize = 18, - Alpha = 0, - }, - closeButton = new ChatTabItemCloseButton - { - Height = 1, - Origin = Anchor.BottomLeft, - Anchor = Anchor.BottomLeft, - Alpha = 0, - Margin = new MarginPadding - { - Right = 5 - }, - RelativeSizeAxes = Axes.Y, - Action = delegate - { - if (IsRemovable) OnRequestClose?.Invoke(this); - }, - }, - } - } - } - }; - } - - public Action OnRequestClose; - - private readonly EdgeEffectParameters activateEdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Shadow, - Radius = 15, - Colour = Color4.Black.Opacity(0.4f), - }; - - protected override void OnActivated() - { - const int activate_length = 1000; - - backgroundBox.ResizeHeightTo(1.1f, activate_length, Easing.OutQuint); - highlightBox.ResizeHeightTo(1.1f, activate_length, Easing.OutQuint); - highlightBox.FadeIn(activate_length, Easing.OutQuint); - username.FadeIn(activate_length, Easing.OutQuint); - username.ScaleTo(new Vector2(1, 1), activate_length, Easing.OutQuint); - closeButton.ScaleTo(new Vector2(1, 1), activate_length, Easing.OutQuint); - closeButton.FadeIn(activate_length, Easing.OutQuint); - TweenEdgeEffectTo(activateEdgeEffect, activate_length); - } - - private readonly EdgeEffectParameters deactivateEdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Shadow, - Radius = 10, - Colour = Color4.Black.Opacity(0.2f), - }; - - protected override void OnDeactivated() - { - const int deactivate_length = 500; - - backgroundBox.ResizeHeightTo(1, deactivate_length, Easing.OutQuint); - highlightBox.ResizeHeightTo(1, deactivate_length, Easing.OutQuint); - highlightBox.FadeOut(deactivate_length, Easing.OutQuint); - username.FadeOut(deactivate_length, Easing.OutQuint); - username.ScaleTo(new Vector2(0, 1), deactivate_length, Easing.OutQuint); - closeButton.FadeOut(deactivate_length, Easing.OutQuint); - closeButton.ScaleTo(new Vector2(0, 1), deactivate_length, Easing.OutQuint); - TweenEdgeEffectTo(deactivateEdgeEffect, deactivate_length); - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - var user = Value.JoinedUsers.First(); - - backgroundBox.Colour = user.Colour != null ? OsuColour.FromHex(user.Colour) : colours.BlueDark; - } - } -} +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Online.Chat; +using osu.Game.Screens.Menu; +using osu.Game.Users; +using OpenTK; +using OpenTK.Graphics; + +namespace osu.Game.Overlays.Chat +{ + public class UserTabItem : TabItem + { + private static readonly Vector2 shear = new Vector2(1f / 5f, 0); + public override bool IsRemovable => true; + + private readonly Box highlightBox; + private readonly Container backgroundContainer; + private readonly Box backgroundBox; + private readonly OsuSpriteText username; + private readonly Avatar avatarContainer; + private readonly ChatTabItemCloseButton closeButton; + + public UserTabItem(Channel value) + : base(value) + { + if (value.Target != TargetType.User) + throw new ArgumentException("Argument value needs to have the targettype user!"); + + AutoSizeAxes = Axes.X; + Height = 50; + Origin = Anchor.BottomRight; + Anchor = Anchor.BottomRight; + EdgeEffect = activateEdgeEffect; + Masking = true; + Shear = shear; + Children = new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + backgroundBox = new Box + { + RelativeSizeAxes = Axes.Both, + Origin = Anchor.BottomLeft, + Anchor = Anchor.BottomLeft, + EdgeSmoothness = new Vector2(1, 0), + }, + } + }, + highlightBox = new Box + { + Width = 5, + BypassAutoSizeAxes = Axes.X, + Alpha = 0, + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + EdgeSmoothness = new Vector2(1, 0), + RelativeSizeAxes = Axes.Y, + Colour = new OsuColour().Yellow + }, + new Container + { + Masking = true, + AutoSizeAxes = Axes.X, + RelativeSizeAxes = Axes.Y, + Child = new FlowContainerWithOrigin + { + AutoSizeAxes = Axes.X, + RelativeSizeAxes = Axes.Y, + X = -5, + Direction = FillDirection.Horizontal, + Origin = Anchor.TopLeft, + Anchor = Anchor.TopLeft, + Shear = -shear, + Children = new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + Margin = new MarginPadding + { + Horizontal = 5 + }, + Origin = Anchor.BottomLeft, + Anchor = Anchor.BottomLeft, + Children = new Drawable[] + { + new SpriteIcon + { + Icon = FontAwesome.fa_eercast, + Origin = Anchor.Centre, + Scale = new Vector2(1.2f), + X = -5, + Y = 5, + Anchor = Anchor.Centre, + Colour = new OsuColour().BlueDarker, + RelativeSizeAxes = Axes.Both, + }, + new CircularContainer + { + RelativeSizeAxes = Axes.Y, + Scale = new Vector2(0.95f), + AutoSizeAxes = Axes.X, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Masking = true, + Child = new DelayedLoadWrapper(new Avatar(value.JoinedUsers.First()) + { + Size = new Vector2(ChatOverlay.TAB_AREA_HEIGHT), + OnLoadComplete = d => d.FadeInFromZero(300, Easing.OutQuint), + }) + { + Size = new Vector2(ChatOverlay.TAB_AREA_HEIGHT), + } + }, + } + }, + username = new OsuSpriteText + { + Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreLeft, + Text = value.Name, + Margin = new MarginPadding(1), + TextSize = 18, + Alpha = 0, + }, + closeButton = new ChatTabItemCloseButton + { + Height = 1, + Origin = Anchor.BottomLeft, + Anchor = Anchor.BottomLeft, + Alpha = 0, + Margin = new MarginPadding + { + Right = 5 + }, + RelativeSizeAxes = Axes.Y, + Action = delegate + { + if (IsRemovable) OnRequestClose?.Invoke(this); + }, + }, + } + } + } + }; + } + + public Action OnRequestClose; + + private readonly EdgeEffectParameters activateEdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Radius = 15, + Colour = Color4.Black.Opacity(0.4f), + }; + + protected override void OnActivated() + { + const int activate_length = 1000; + + backgroundBox.ResizeHeightTo(1.1f, activate_length, Easing.OutQuint); + highlightBox.ResizeHeightTo(1.1f, activate_length, Easing.OutQuint); + highlightBox.FadeIn(activate_length, Easing.OutQuint); + username.FadeIn(activate_length, Easing.OutQuint); + username.ScaleTo(new Vector2(1, 1), activate_length, Easing.OutQuint); + closeButton.ScaleTo(new Vector2(1, 1), activate_length, Easing.OutQuint); + closeButton.FadeIn(activate_length, Easing.OutQuint); + TweenEdgeEffectTo(activateEdgeEffect, activate_length); + } + + private readonly EdgeEffectParameters deactivateEdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Radius = 10, + Colour = Color4.Black.Opacity(0.2f), + }; + + protected override void OnDeactivated() + { + const int deactivate_length = 500; + + backgroundBox.ResizeHeightTo(1, deactivate_length, Easing.OutQuint); + highlightBox.ResizeHeightTo(1, deactivate_length, Easing.OutQuint); + highlightBox.FadeOut(deactivate_length, Easing.OutQuint); + username.FadeOut(deactivate_length, Easing.OutQuint); + username.ScaleTo(new Vector2(0, 1), deactivate_length, Easing.OutQuint); + closeButton.FadeOut(deactivate_length, Easing.OutQuint); + closeButton.ScaleTo(new Vector2(0, 1), deactivate_length, Easing.OutQuint); + TweenEdgeEffectTo(deactivateEdgeEffect, deactivate_length); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + var user = Value.JoinedUsers.First(); + + backgroundBox.Colour = user.Colour != null ? OsuColour.FromHex(user.Colour) : colours.BlueDark; + } + } +} From 29e8c70ed77766f5718c3b272c53ddb425a943cc Mon Sep 17 00:00:00 2001 From: miterosan Date: Wed, 18 Apr 2018 20:46:42 +0200 Subject: [PATCH 026/155] Only use one tabControl (channeltabcontrol). Fix that the Channel messages did not refresh. --- .../Visual/TestCaseChatTabControl.cs | 3 +- osu.Game/Online/Chat/ChannelManager.cs | 7 +-- osu.Game/OsuGameBase.cs | 4 +- osu.Game/Overlays/Chat/ChannelTabControl.cs | 13 ++++- osu.Game/Overlays/Chat/ChatTabControl.cs | 57 +++---------------- osu.Game/Overlays/Chat/DrawableChat.cs | 2 +- osu.Game/Overlays/Chat/UserTabControl.cs | 46 --------------- osu.Game/Overlays/Chat/UserTabItem.cs | 4 +- osu.Game/Overlays/ChatOverlay.cs | 1 + 9 files changed, 30 insertions(+), 107 deletions(-) delete mode 100644 osu.Game/Overlays/Chat/UserTabControl.cs diff --git a/osu.Game.Tests/Visual/TestCaseChatTabControl.cs b/osu.Game.Tests/Visual/TestCaseChatTabControl.cs index ac5d59a74f..4c408806a4 100644 --- a/osu.Game.Tests/Visual/TestCaseChatTabControl.cs +++ b/osu.Game.Tests/Visual/TestCaseChatTabControl.cs @@ -21,8 +21,7 @@ namespace osu.Game.Tests.Visual public override IReadOnlyList RequiredTypes => new[] { typeof(ChatTabControl), - typeof(ChannelTabControl), - typeof(UserTabControl) + typeof(ChannelTabControl) }; private readonly ChatTabControl chatTabControl; diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 069b88565d..0b658428fe 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -47,8 +47,7 @@ namespace osu.Game.Online.Chat /// public ObservableCollection AvailableChannels { get; } = new ObservableCollection(); - private APIAccess api; - private readonly Scheduler scheduler; + private IAPIProvider api; private ScheduledDelegate fetchMessagesScheduleder; private GetMessagesRequest fetchMsgReq; private GetPrivateMessagesRequest fetchPrivateMsgReq; @@ -282,7 +281,7 @@ namespace osu.Game.Online.Chat case APIState.Online: if (JoinedChannels.Count == 0) initializeDefaultChannels(); - fetchMessagesScheduleder = scheduler.AddDelayed(fetchNewMessages, 1000, true); + fetchMessagesScheduleder = Scheduler.AddDelayed(fetchNewMessages, 1000, true); break; default: fetchMsgReq?.Cancel(); @@ -295,7 +294,7 @@ namespace osu.Game.Online.Chat [BackgroundDependencyLoader] private void load(IAPIProvider api) { - this.api = this.api; + this.api = api; api.Register(this); } } diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 3c34c0c108..c3e3881a28 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -118,7 +118,9 @@ namespace osu.Game dependencies.Cache(api); dependencies.CacheAs(api); - dependencies.Cache(new ChannelManager()); + var channelManager = new ChannelManager(); + dependencies.Inject(channelManager); + dependencies.Cache(channelManager); dependencies.Cache(RulesetStore = new RulesetStore(contextFactory)); dependencies.Cache(FileStore = new FileStore(contextFactory, Host.Storage)); diff --git a/osu.Game/Overlays/Chat/ChannelTabControl.cs b/osu.Game/Overlays/Chat/ChannelTabControl.cs index 66ee4285d3..b6c3d4900b 100644 --- a/osu.Game/Overlays/Chat/ChannelTabControl.cs +++ b/osu.Game/Overlays/Chat/ChannelTabControl.cs @@ -60,7 +60,18 @@ namespace osu.Game.Overlays.Chat base.AddTabItem(item, addToDropdown); } - protected override TabItem CreateTabItem(Channel value) => new ChannelTabItem(value) { OnRequestClose = tabCloseRequested }; + protected override TabItem CreateTabItem(Channel value) + { + switch (value.Target) + { + case TargetType.Channel: + return new ChannelTabItem(value) { OnRequestClose = tabCloseRequested }; + case TargetType.User: + return new UserTabItem(value) { OnRequestClose = tabCloseRequested }; + default: + throw new InvalidOperationException("Only TargetType User and Channel are supported."); + } + } protected override void SelectTab(TabItem tab) { diff --git a/osu.Game/Overlays/Chat/ChatTabControl.cs b/osu.Game/Overlays/Chat/ChatTabControl.cs index a95b96b8fb..42ea643087 100644 --- a/osu.Game/Overlays/Chat/ChatTabControl.cs +++ b/osu.Game/Overlays/Chat/ChatTabControl.cs @@ -14,7 +14,6 @@ namespace osu.Game.Overlays.Chat public class ChatTabControl : Container, IHasCurrentValue { public readonly ChannelTabControl ChannelTabControl; - public readonly UserTabControl UserTabControl; public Bindable Current { get; } = new Bindable(); public Action OnRequestLeave; @@ -27,20 +26,11 @@ namespace osu.Game.Overlays.Chat { ChannelTabControl = new ChannelTabControl { - Width = 0.5f, Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, RelativeSizeAxes = Axes.Both, OnRequestLeave = channel => OnRequestLeave?.Invoke(channel) }, - UserTabControl = new UserTabControl - { - Width = 0.5f, - Anchor = Anchor.BottomRight, - Origin = Anchor.BottomRight, - RelativeSizeAxes = Axes.Both, - OnRequestLeave = channel => OnRequestLeave?.Invoke(channel) - }, }; Current.ValueChanged += currentTabChanged; @@ -49,58 +39,25 @@ namespace osu.Game.Overlays.Chat if (channel != null) Current.Value = channel; }; - UserTabControl.Current.ValueChanged += channel => - { - if (channel != null) - Current.Value = channel; - }; } private void currentTabChanged(Channel channel) { - switch (channel.Target) - { - case TargetType.User: - UserTabControl.Current.Value = channel; - ChannelTabControl.Current.Value = null; - break; - case TargetType.Channel: - ChannelTabControl.Current.Value = channel; - UserTabControl.Current.Value = null; - break; - } + ChannelTabControl.Current.Value = channel; } public void AddItem(Channel channel) { - switch (channel.Target) - { - case TargetType.User: - UserTabControl.AddItem(channel); - break; - case TargetType.Channel: - ChannelTabControl.AddItem(channel); - break; - } + ChannelTabControl.AddItem(channel); + if (Current.Value == null) + Current.Value = channel; } public void RemoveItem(Channel channel) { - Channel nextSelectedChannel = null; - - switch (channel.Target) - { - case TargetType.User: - UserTabControl.RemoveItem(channel); - if (Current.Value == channel) - Current.Value = UserTabControl.Items.FirstOrDefault() ?? ChannelTabControl.Items.FirstOrDefault(); - break; - case TargetType.Channel: - ChannelTabControl.RemoveItem(channel); - if (Current.Value == channel) - Current.Value = ChannelTabControl.Items.FirstOrDefault() ?? UserTabControl.Items.FirstOrDefault(); - break; - } + ChannelTabControl.RemoveItem(channel); + if (Current.Value == channel) + Current.Value = ChannelTabControl.Items.FirstOrDefault(); } } } diff --git a/osu.Game/Overlays/Chat/DrawableChat.cs b/osu.Game/Overlays/Chat/DrawableChat.cs index 83cabfafa1..30ba105b5c 100644 --- a/osu.Game/Overlays/Chat/DrawableChat.cs +++ b/osu.Game/Overlays/Chat/DrawableChat.cs @@ -58,7 +58,7 @@ namespace osu.Game.Overlays.Chat [BackgroundDependencyLoader] private void load() { - Scheduler.Add(() => newMessagesArrived(Chat.Messages)); + newMessagesArrived(Chat.Messages); } protected override void LoadComplete() diff --git a/osu.Game/Overlays/Chat/UserTabControl.cs b/osu.Game/Overlays/Chat/UserTabControl.cs deleted file mode 100644 index 7da7cab900..0000000000 --- a/osu.Game/Overlays/Chat/UserTabControl.cs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System; -using osu.Framework.Graphics; -using osu.Framework.Graphics.UserInterface; -using osu.Game.Graphics.UserInterface; -using osu.Game.Online.Chat; -using OpenTK; - -namespace osu.Game.Overlays.Chat -{ - public class UserTabControl : OsuTabControl - { - protected override TabItem CreateTabItem(Channel value) - { - if (value.Target != TargetType.User) - throw new ArgumentException("Argument value needs to have the targettype user."); - return new UserTabItem(value) { OnRequestClose = tabCloseRequested }; - } - - public Action OnRequestLeave; - - public UserTabControl() - { - TabContainer.Spacing = new Vector2(-10, 0); - TabContainer.Masking = false; - Margin = new MarginPadding - { - Right = 10 - }; - } - - private void tabCloseRequested(TabItem priv) - { - int totalTabs = TabContainer.Count -1; // account for selectorTab - int currentIndex = MathHelper.Clamp(TabContainer.IndexOf(priv), 1, totalTabs); - - if (priv == SelectedTab && totalTabs > 1) - // Select the tab after tab-to-be-removed's index, or the tab before if current == last - SelectTab(TabContainer[currentIndex == totalTabs ? currentIndex - 1 : currentIndex + 1]); - - OnRequestLeave?.Invoke(priv.Value); - } - } -} diff --git a/osu.Game/Overlays/Chat/UserTabItem.cs b/osu.Game/Overlays/Chat/UserTabItem.cs index 86dc6c23e6..5f81e9fe9e 100644 --- a/osu.Game/Overlays/Chat/UserTabItem.cs +++ b/osu.Game/Overlays/Chat/UserTabItem.cs @@ -39,8 +39,8 @@ namespace osu.Game.Overlays.Chat AutoSizeAxes = Axes.X; Height = 50; - Origin = Anchor.BottomRight; - Anchor = Anchor.BottomRight; + Origin = Anchor.BottomLeft; + Anchor = Anchor.BottomLeft; EdgeEffect = activateEdgeEffect; Masking = true; Shear = shear; diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index ec8851799a..4d13e05c9e 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -345,6 +345,7 @@ namespace osu.Game.Overlays channelManager.CurrentChannel.ValueChanged += currentChatChanged; channelManager.JoinedChannels.CollectionChanged += joinedChannelsChanged; channelManager.AvailableChannels.CollectionChanged += availableChannelsChanged; + Add(channelManager); } private void postMessage(TextBox textbox, bool newText) From 1bbeb6d70e6210ea011bf12635622a0690e33b7e Mon Sep 17 00:00:00 2001 From: miterosan Date: Sun, 6 May 2018 19:54:41 +0200 Subject: [PATCH 027/155] Make the sinceId readonly --- osu.Game/Online/API/APIMessagesRequest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/API/APIMessagesRequest.cs b/osu.Game/Online/API/APIMessagesRequest.cs index c957564771..991096c0af 100644 --- a/osu.Game/Online/API/APIMessagesRequest.cs +++ b/osu.Game/Online/API/APIMessagesRequest.cs @@ -9,7 +9,7 @@ namespace osu.Game.Online.API { public abstract class APIMessagesRequest : APIRequest> { - private long? sinceId; + private readonly long? sinceId; protected APIMessagesRequest(long? sinceId) { From 6e0099d2b137dfe0fae02900d7d7eb0fede2763c Mon Sep 17 00:00:00 2001 From: miterosan Date: Thu, 31 May 2018 22:56:12 +0200 Subject: [PATCH 028/155] Fix webexception due to invalid user ids --- .../Visual/TestCaseChatTabControl.cs | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseChatTabControl.cs b/osu.Game.Tests/Visual/TestCaseChatTabControl.cs index 4c408806a4..e530c1b72a 100644 --- a/osu.Game.Tests/Visual/TestCaseChatTabControl.cs +++ b/osu.Game.Tests/Visual/TestCaseChatTabControl.cs @@ -3,12 +3,16 @@ using System; using System.Collections.Generic; +using System.Linq; +using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.MathUtils; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; using osu.Game.Online.Chat; using osu.Game.Overlays.Chat; using osu.Game.Users; @@ -71,18 +75,19 @@ namespace osu.Game.Tests.Visual chatTabControl.OnRequestLeave += chat => chatTabControl.RemoveItem(chat); chatTabControl.Current.ValueChanged += chat => currentText.Text = "Currently selected chat: " + chat.ToString(); - AddStep("Add random user", () => addUser(RNG.Next(100000), RNG.Next().ToString())); - AddRepeatStep("3 random users", () => addUser(RNG.Next(100000), RNG.Next().ToString()), 3); + AddStep("Add random user", addRandomUser); + AddRepeatStep("Add 3 random users", addRandomUser, 3); AddStep("Add random channel", () => addChannel(RNG.Next().ToString())); } - private void addUser(long id, string name) + private List users; + + private void addRandomUser() { - chatTabControl.AddItem(new Channel(new User - { - Id = id, - Username = name - })); + if (users == null || users.Count == 0) + return; + + chatTabControl.AddItem(new Channel(users[RNG.Next(0, users.Count - 1)])); } private void addChannel(string name) @@ -92,5 +97,14 @@ namespace osu.Game.Tests.Visual Name = name }); } + + [BackgroundDependencyLoader] + private void load(IAPIProvider api) + { + GetUsersRequest req = new GetUsersRequest(); + req.Success += list => users = list.Select(e => e.User).ToList(); + + api.Queue(req); + } } } From 1f04dd9adabe868b2ab0a6f04b3dac072554f990 Mon Sep 17 00:00:00 2001 From: miterosan Date: Sun, 17 Jun 2018 15:08:13 +0200 Subject: [PATCH 029/155] Cache the dependencies using the static method of the class Dependencies. --- osu.Game.Tests/Visual/TestCaseChatLink.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseChatLink.cs b/osu.Game.Tests/Visual/TestCaseChatLink.cs index 071a79dc8c..51def9be7d 100644 --- a/osu.Game.Tests/Visual/TestCaseChatLink.cs +++ b/osu.Game.Tests/Visual/TestCaseChatLink.cs @@ -54,9 +54,9 @@ namespace osu.Game.Tests.Visual var chatManager = new ChannelManager(); chatManager.AvailableChannels.Add(new Channel { Name = "#english"}); chatManager.AvailableChannels.Add(new Channel { Name = "#japanese" }); - dependencies.Cache(chatManager); + Dependencies.Cache(chatManager); - dependencies.Cache(new ChatOverlay()); + Dependencies.Cache(new ChatOverlay()); testLinksGeneral(); testEcho(); From 709d134f49c35e31606ef242532c6bb4b52c34f6 Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 9 Jul 2018 18:23:40 +0200 Subject: [PATCH 030/155] Rename DrawableChat to DrawableChannel --- .../Overlays/Chat/{DrawableChat.cs => DrawableChannel.cs} | 0 osu.Game/Overlays/ChatOverlay.cs | 8 ++++---- 2 files changed, 4 insertions(+), 4 deletions(-) rename osu.Game/Overlays/Chat/{DrawableChat.cs => DrawableChannel.cs} (100%) diff --git a/osu.Game/Overlays/Chat/DrawableChat.cs b/osu.Game/Overlays/Chat/DrawableChannel.cs similarity index 100% rename from osu.Game/Overlays/Chat/DrawableChat.cs rename to osu.Game/Overlays/Chat/DrawableChannel.cs diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 438277bfe6..3df57f86b7 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -29,8 +29,8 @@ namespace osu.Game.Overlays private ChannelManager channelManager; - private readonly Container currentChatContainer; - private readonly List loadedChannels = new List(); + private readonly Container currentChatContainer; + private readonly List loadedChannels = new List(); private readonly LoadingAnimation loading; @@ -101,7 +101,7 @@ namespace osu.Game.Overlays { RelativeSizeAxes = Axes.Both, }, - currentChatContainer = new Container + currentChatContainer = new Container { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding @@ -240,7 +240,7 @@ namespace osu.Game.Overlays currentChatContainer.FadeOut(500, Easing.OutQuint); loading.Show(); - loaded = new DrawableChat(chat); + loaded = new DrawableChannel(chat); loadedChannels.Add(loaded); LoadComponentAsync(loaded, l => { From 5e95995429718caaae78d9b54bf1edb7a3ddfaf3 Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 9 Jul 2018 18:30:41 +0200 Subject: [PATCH 031/155] Rename chat to channel --- osu.Game/Overlays/Chat/DrawableChannel.cs | 24 +++++++++++------------ osu.Game/Overlays/ChatOverlay.cs | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/osu.Game/Overlays/Chat/DrawableChannel.cs b/osu.Game/Overlays/Chat/DrawableChannel.cs index 30ba105b5c..bcc8879902 100644 --- a/osu.Game/Overlays/Chat/DrawableChannel.cs +++ b/osu.Game/Overlays/Chat/DrawableChannel.cs @@ -15,15 +15,15 @@ using osu.Game.Online.Chat; namespace osu.Game.Overlays.Chat { - public class DrawableChat : Container + public class DrawableChannel : Container { - public readonly Channel Chat; + public readonly Channel Channel; private readonly ChatLineContainer flow; private readonly ScrollContainer scroll; - public DrawableChat(Channel chat) + public DrawableChannel(Channel channel) { - Chat = chat; + Channel = channel; RelativeSizeAxes = Axes.Both; @@ -50,15 +50,15 @@ namespace osu.Game.Overlays.Chat } }; - Chat.NewMessagesArrived += newMessagesArrived; - Chat.MessageRemoved += messageRemoved; - Chat.PendingMessageResolved += pendingMessageResolved; + Channel.NewMessagesArrived += newMessagesArrived; + Channel.MessageRemoved += messageRemoved; + Channel.PendingMessageResolved += pendingMessageResolved; } [BackgroundDependencyLoader] private void load() { - newMessagesArrived(Chat.Messages); + newMessagesArrived(Channel.Messages); } protected override void LoadComplete() @@ -71,14 +71,14 @@ namespace osu.Game.Overlays.Chat { base.Dispose(isDisposing); - Chat.NewMessagesArrived -= newMessagesArrived; - Chat.MessageRemoved -= messageRemoved; - Chat.PendingMessageResolved -= pendingMessageResolved; + Channel.NewMessagesArrived -= newMessagesArrived; + Channel.MessageRemoved -= messageRemoved; + Channel.PendingMessageResolved -= pendingMessageResolved; } private void newMessagesArrived(IEnumerable newMessages) { - // Add up to last ChatBase.MAX_HISTORY messages + // Add up to last Channel.MAX_HISTORY messages var displayMessages = newMessages.Skip(Math.Max(0, newMessages.Count() - Channel.MAX_HISTORY)); flow.AddRange(displayMessages.Select(m => new ChatLine(m))); diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 3df57f86b7..403508627e 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -212,7 +212,7 @@ namespace osu.Game.Overlays foreach (Channel removedChannel in args.OldItems) { chatTabControl.RemoveItem(removedChannel); - loadedChannels.Remove(loadedChannels.Find(c => c.Chat == removedChannel )); + loadedChannels.Remove(loadedChannels.Find(c => c.Channel == removedChannel )); removedChannel.Joined.Value = false; } break; @@ -234,7 +234,7 @@ namespace osu.Game.Overlays if (chatTabControl.Current.Value != chat) Scheduler.Add(() => chatTabControl.Current.Value = chat); - var loaded = loadedChannels.Find(d => d.Chat == chat); + var loaded = loadedChannels.Find(d => d.Channel == chat); if (loaded == null) { currentChatContainer.FadeOut(500, Easing.OutQuint); From 263e68de91ebabe1aec5be4d04d7b913d91cc854 Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 9 Jul 2018 18:45:11 +0200 Subject: [PATCH 032/155] Use a custom channel not found exception. --- osu.Game/Graphics/Containers/LinkFlowContainer.cs | 2 +- osu.Game/Online/Chat/ChannelManager.cs | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/Containers/LinkFlowContainer.cs b/osu.Game/Graphics/Containers/LinkFlowContainer.cs index 51b9acff44..0e3c1592a3 100644 --- a/osu.Game/Graphics/Containers/LinkFlowContainer.cs +++ b/osu.Game/Graphics/Containers/LinkFlowContainer.cs @@ -84,7 +84,7 @@ namespace osu.Game.Graphics.Containers { channelManager.OpenChannel(linkArgument); } - catch (ArgumentException) + catch (ChannelNotFoundException) { //channel was not found } diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 0b658428fe..60e7217756 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -60,7 +60,7 @@ namespace osu.Game.Online.Chat throw new ArgumentNullException(nameof(name)); CurrentChannel.Value = AvailableChannels.FirstOrDefault(c => c.Name == name) - ?? throw new ArgumentException($"Channel {name} was not found."); + ?? throw new ChannelNotFoundException(name); } public void OpenUserChannel(User user) @@ -298,4 +298,14 @@ namespace osu.Game.Online.Chat api.Register(this); } } + + + public class ChannelNotFoundException : Exception + { + public ChannelNotFoundException(string channelName) + : base($"A channel with the name {channelName} could not be found.") + { + + } + } } From 4b638db4752206f33d60646e689b0f97cfa6ed9d Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 9 Jul 2018 18:52:28 +0200 Subject: [PATCH 033/155] Reorder the properties and fields on Channel. Make MAX_HISTORY because cause can not be public. --- osu.Game/Online/Chat/Channel.cs | 37 +++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/osu.Game/Online/Chat/Channel.cs b/osu.Game/Online/Chat/Channel.cs index e9cd7e51e0..1196738bd7 100644 --- a/osu.Game/Online/Chat/Channel.cs +++ b/osu.Game/Online/Chat/Channel.cs @@ -14,7 +14,22 @@ namespace osu.Game.Online.Chat { public class Channel { - public const int MAX_HISTORY = 300; + public readonly int MAX_HISTORY = 300; + + /// + /// Contains every joined user except yourself + /// + public readonly ObservableCollection JoinedUsers = new ObservableCollection(); + public readonly SortedList Messages = new SortedList(Comparer.Default); + + public event Action> NewMessagesArrived; + public event Action PendingMessageResolved; + public event Action MessageRemoved; + + public readonly Bindable Joined = new Bindable(); + public TargetType Target { get; } + public bool ReadOnly { get; set; } + public override string ToString() => Name; [JsonProperty(@"name")] public string Name; @@ -28,6 +43,8 @@ namespace osu.Game.Online.Chat [JsonProperty(@"channel_id")] public long Id; + private readonly List pendingMessages = new List(); + [JsonConstructor] public Channel() { @@ -37,7 +54,7 @@ namespace osu.Game.Online.Chat /// Contructs a private channel /// TODO this class needs to be serialized from something like channels/private, instead of creating from a contructor /// - /// The user + /// The user public Channel(User user) { Target = TargetType.User; @@ -46,20 +63,8 @@ namespace osu.Game.Online.Chat JoinedUsers.Add(user); } - /// - /// Contains every joined user except yourself - /// - public ObservableCollection JoinedUsers = new ObservableCollection(); - public readonly SortedList Messages = new SortedList(Comparer.Default); - private readonly List pendingMessages = new List(); + - public event Action> NewMessagesArrived; - public event Action PendingMessageResolved; - public event Action MessageRemoved; - - public Bindable Joined = new Bindable(); - public TargetType Target { get; set; } - public bool ReadOnly { get; set; } public void AddLocalEcho(LocalEchoMessage message) { @@ -118,6 +123,6 @@ namespace osu.Game.Online.Chat Messages.RemoveRange(0, messageCount - MAX_HISTORY); } - public override string ToString() => Name; + } } From 66378d5847327e24e2684b177e84375fd3776647 Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 9 Jul 2018 18:58:10 +0200 Subject: [PATCH 034/155] Remove the highlight from "Start Chat" --- osu.Game/Overlays/Chat/ChatLine.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Chat/ChatLine.cs b/osu.Game/Overlays/Chat/ChatLine.cs index 50d09b6ef6..f8fb9e01f3 100644 --- a/osu.Game/Overlays/Chat/ChatLine.cs +++ b/osu.Game/Overlays/Chat/ChatLine.cs @@ -254,7 +254,7 @@ namespace osu.Game.Overlays.Chat public MenuItem[] ContextMenuItems => new MenuItem[] { new OsuMenuItem("View Profile", MenuItemType.Highlighted, Action), - new OsuMenuItem("Start Chat", MenuItemType.Highlighted, startChatAction), + new OsuMenuItem("Start Chat", MenuItemType.Standard, startChatAction), }; } } From 16d3815a5943ec14b3eb66efd1c8f6b8f705f8d3 Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 9 Jul 2018 18:58:33 +0200 Subject: [PATCH 035/155] Clean Channel up and reword two comments --- osu.Game/Online/Chat/Channel.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/osu.Game/Online/Chat/Channel.cs b/osu.Game/Online/Chat/Channel.cs index 1196738bd7..b7893ed9ff 100644 --- a/osu.Game/Online/Chat/Channel.cs +++ b/osu.Game/Online/Chat/Channel.cs @@ -17,7 +17,7 @@ namespace osu.Game.Online.Chat public readonly int MAX_HISTORY = 300; /// - /// Contains every joined user except yourself + /// Contains every joined user except the current logged in user. /// public readonly ObservableCollection JoinedUsers = new ObservableCollection(); public readonly SortedList Messages = new SortedList(Comparer.Default); @@ -52,7 +52,7 @@ namespace osu.Game.Online.Chat /// /// Contructs a private channel - /// TODO this class needs to be serialized from something like channels/private, instead of creating from a contructor + /// TODO this class needs to be serialized from something like channels/private, instead of creating from the contructor /// /// The user public Channel(User user) @@ -62,10 +62,7 @@ namespace osu.Game.Online.Chat Id = user.Id; JoinedUsers.Add(user); } - - - - + public void AddLocalEcho(LocalEchoMessage message) { pendingMessages.Add(message); From 1589b65494f9df6fc9aedc0c1016e6d013767eb2 Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 9 Jul 2018 19:42:57 +0200 Subject: [PATCH 036/155] Move tab related stuff to /tabs, move selection related stuff to /selection, remove channeltabcontrol --- osu.Game/Overlays/Chat/ChannelTabControl.cs | 342 ------------------ osu.Game/Overlays/Chat/ChatTabControl.cs | 1 + .../Chat/{ => Selection}/ChannelListItem.cs | 2 +- .../Chat/{ => Selection}/ChannelSection.cs | 2 +- .../ChannelSelectionOverlay.cs | 2 +- .../Chat/Tabs/ChannelSelectorTabItem.cs | 32 ++ .../Overlays/Chat/Tabs/ChannelTabControl.cs | 96 +++++ osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs | 194 ++++++++++ .../TabCloseButton.cs} | 6 +- .../Overlays/Chat/{ => Tabs}/UserTabItem.cs | 6 +- osu.Game/Overlays/ChatOverlay.cs | 1 + 11 files changed, 333 insertions(+), 351 deletions(-) delete mode 100644 osu.Game/Overlays/Chat/ChannelTabControl.cs rename osu.Game/Overlays/Chat/{ => Selection}/ChannelListItem.cs (99%) rename osu.Game/Overlays/Chat/{ => Selection}/ChannelSection.cs (97%) rename osu.Game/Overlays/Chat/{ => Selection}/ChannelSelectionOverlay.cs (99%) create mode 100644 osu.Game/Overlays/Chat/Tabs/ChannelSelectorTabItem.cs create mode 100644 osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs create mode 100644 osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs rename osu.Game/Overlays/Chat/{ChatTabItemCloseButton.cs => Tabs/TabCloseButton.cs} (91%) rename osu.Game/Overlays/Chat/{ => Tabs}/UserTabItem.cs (98%) diff --git a/osu.Game/Overlays/Chat/ChannelTabControl.cs b/osu.Game/Overlays/Chat/ChannelTabControl.cs deleted file mode 100644 index b6c3d4900b..0000000000 --- a/osu.Game/Overlays/Chat/ChannelTabControl.cs +++ /dev/null @@ -1,342 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using osu.Framework.Allocation; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Graphics.UserInterface; -using osu.Framework.Input; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; -using osu.Game.Online.Chat; -using OpenTK; -using OpenTK.Graphics; -using osu.Framework.Configuration; -using System; -using osu.Game.Graphics.Containers; - -namespace osu.Game.Overlays.Chat -{ - public class ChannelTabControl : OsuTabControl - { - private const float shear_width = 10; - - public Action OnRequestLeave; - - public readonly Bindable ChannelSelectorActive = new Bindable(); - - private readonly ChannelTabItem.ChannelSelectorTabItem selectorTab; - - public ChannelTabControl() - { - TabContainer.Margin = new MarginPadding { Left = 50 }; - TabContainer.Spacing = new Vector2(-shear_width, 0); - TabContainer.Masking = false; - - AddInternal(new SpriteIcon - { - Icon = FontAwesome.fa_comments, - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Size = new Vector2(20), - Margin = new MarginPadding(10), - }); - - AddTabItem(selectorTab = new ChannelTabItem.ChannelSelectorTabItem(new Channel { Name = "+" })); - - ChannelSelectorActive.BindTo(selectorTab.Active); - } - - protected override void AddTabItem(TabItem item, bool addToDropdown = true) - { - if (item != selectorTab && TabContainer.GetLayoutPosition(selectorTab) < float.MaxValue) - // performTabSort might've made selectorTab's position wonky, fix it - TabContainer.SetLayoutPosition(selectorTab, float.MaxValue); - - base.AddTabItem(item, addToDropdown); - } - - protected override TabItem CreateTabItem(Channel value) - { - switch (value.Target) - { - case TargetType.Channel: - return new ChannelTabItem(value) { OnRequestClose = tabCloseRequested }; - case TargetType.User: - return new UserTabItem(value) { OnRequestClose = tabCloseRequested }; - default: - throw new InvalidOperationException("Only TargetType User and Channel are supported."); - } - } - - protected override void SelectTab(TabItem tab) - { - if (tab is ChannelTabItem.ChannelSelectorTabItem) - { - tab.Active.Toggle(); - return; - } - - selectorTab.Active.Value = false; - - base.SelectTab(tab); - } - - private void tabCloseRequested(TabItem tab) - { - int totalTabs = TabContainer.Count - 1; // account for selectorTab - int currentIndex = MathHelper.Clamp(TabContainer.IndexOf(tab), 1, totalTabs); - - if (tab == SelectedTab && totalTabs > 1) - // Select the tab after tab-to-be-removed's index, or the tab before if current == last - SelectTab(TabContainer[currentIndex == totalTabs ? currentIndex - 1 : currentIndex + 1]); - else if (totalTabs == 1 && !selectorTab.Active) - // Open channel selection overlay if all channel tabs will be closed after removing this tab - SelectTab(selectorTab); - - OnRequestLeave?.Invoke(tab.Value); - } - - private class ChannelTabItem : TabItem - { - private Color4 backgroundInactive; - private Color4 backgroundHover; - private Color4 backgroundActive; - - public override bool IsRemovable => !Pinned; - - private readonly SpriteText text; - private readonly SpriteText textBold; - private readonly ClickableContainer closeButton; - private readonly Box box; - private readonly Box highlightBox; - private readonly SpriteIcon icon; - - public Action OnRequestClose; - - private void updateState() - { - if (Active) - fadeActive(); - else - fadeInactive(); - } - - private const float transition_length = 400; - - private void fadeActive() - { - this.ResizeTo(new Vector2(Width, 1.1f), transition_length, Easing.OutQuint); - - box.FadeColour(backgroundActive, transition_length, Easing.OutQuint); - highlightBox.FadeIn(transition_length, Easing.OutQuint); - - text.FadeOut(transition_length, Easing.OutQuint); - textBold.FadeIn(transition_length, Easing.OutQuint); - } - - private void fadeInactive() - { - this.ResizeTo(new Vector2(Width, 1), transition_length, Easing.OutQuint); - - box.FadeColour(backgroundInactive, transition_length, Easing.OutQuint); - highlightBox.FadeOut(transition_length, Easing.OutQuint); - - text.FadeIn(transition_length, Easing.OutQuint); - textBold.FadeOut(transition_length, Easing.OutQuint); - } - - protected override bool OnHover(InputState state) - { - if (IsRemovable) - closeButton.FadeIn(200, Easing.OutQuint); - - if (!Active) - box.FadeColour(backgroundHover, transition_length, Easing.OutQuint); - return true; - } - - protected override void OnHoverLost(InputState state) - { - closeButton.FadeOut(200, Easing.OutQuint); - updateState(); - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - backgroundActive = colours.ChatBlue; - backgroundInactive = colours.Gray4; - backgroundHover = colours.Gray7; - - highlightBox.Colour = colours.Yellow; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - updateState(); - } - - public ChannelTabItem(Channel value) : base(value) - { - Width = 150; - - RelativeSizeAxes = Axes.Y; - - Anchor = Anchor.BottomLeft; - Origin = Anchor.BottomLeft; - - Shear = new Vector2(shear_width / ChatOverlay.TAB_AREA_HEIGHT, 0); - - Masking = true; - EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Shadow, - Radius = 10, - Colour = Color4.Black.Opacity(0.2f), - }; - - Children = new Drawable[] - { - box = new Box - { - EdgeSmoothness = new Vector2(1, 0), - RelativeSizeAxes = Axes.Both, - }, - highlightBox = new Box - { - Width = 5, - Alpha = 0, - Anchor = Anchor.BottomRight, - Origin = Anchor.BottomRight, - EdgeSmoothness = new Vector2(1, 0), - RelativeSizeAxes = Axes.Y, - }, - new Container - { - Shear = new Vector2(-shear_width / ChatOverlay.TAB_AREA_HEIGHT, 0), - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - icon = new SpriteIcon - { - Icon = FontAwesome.fa_hashtag, - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Colour = Color4.Black, - X = -10, - Alpha = 0.2f, - Size = new Vector2(ChatOverlay.TAB_AREA_HEIGHT), - }, - text = new OsuSpriteText - { - Margin = new MarginPadding(5), - Origin = Anchor.CentreLeft, - Anchor = Anchor.CentreLeft, - Text = value.ToString(), - TextSize = 18, - }, - textBold = new OsuSpriteText - { - Alpha = 0, - Margin = new MarginPadding(5), - Origin = Anchor.CentreLeft, - Anchor = Anchor.CentreLeft, - Text = value.ToString(), - Font = @"Exo2.0-Bold", - TextSize = 18, - }, - closeButton = new CloseButton - { - Alpha = 0, - Margin = new MarginPadding { Right = 20 }, - Origin = Anchor.CentreRight, - Anchor = Anchor.CentreRight, - Action = delegate - { - if (IsRemovable) OnRequestClose?.Invoke(this); - }, - }, - }, - }, - }; - } - - public class CloseButton : OsuClickableContainer - { - private readonly SpriteIcon icon; - - public CloseButton() - { - Size = new Vector2(20); - - Child = icon = new SpriteIcon - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Scale = new Vector2(0.75f), - Icon = FontAwesome.fa_close, - RelativeSizeAxes = Axes.Both, - }; - } - - protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) - { - icon.ScaleTo(0.5f, 1000, Easing.OutQuint); - return base.OnMouseDown(state, args); - } - - protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) - { - icon.ScaleTo(0.75f, 1000, Easing.OutElastic); - return base.OnMouseUp(state, args); - } - - protected override bool OnHover(InputState state) - { - icon.FadeColour(Color4.Red, 200, Easing.OutQuint); - return base.OnHover(state); - } - - protected override void OnHoverLost(InputState state) - { - icon.FadeColour(Color4.White, 200, Easing.OutQuint); - base.OnHoverLost(state); - } - } - - public class ChannelSelectorTabItem : ChannelTabItem - { - public override bool IsRemovable => false; - - public ChannelSelectorTabItem(Channel value) : base(value) - { - Depth = float.MaxValue; - Width = 45; - - icon.Alpha = 0; - - text.TextSize = 45; - textBold.TextSize = 45; - } - - [BackgroundDependencyLoader] - private new void load(OsuColour colour) - { - backgroundInactive = colour.Gray2; - backgroundActive = colour.Gray3; - } - } - - protected override void OnActivated() => updateState(); - - protected override void OnDeactivated() => updateState(); - } - } -} diff --git a/osu.Game/Overlays/Chat/ChatTabControl.cs b/osu.Game/Overlays/Chat/ChatTabControl.cs index 42ea643087..c668f78ff4 100644 --- a/osu.Game/Overlays/Chat/ChatTabControl.cs +++ b/osu.Game/Overlays/Chat/ChatTabControl.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; using osu.Game.Online.Chat; +using osu.Game.Overlays.Chat.Tabs; namespace osu.Game.Overlays.Chat { diff --git a/osu.Game/Overlays/Chat/ChannelListItem.cs b/osu.Game/Overlays/Chat/Selection/ChannelListItem.cs similarity index 99% rename from osu.Game/Overlays/Chat/ChannelListItem.cs rename to osu.Game/Overlays/Chat/Selection/ChannelListItem.cs index 910c87e0a8..175d7fd0d2 100644 --- a/osu.Game/Overlays/Chat/ChannelListItem.cs +++ b/osu.Game/Overlays/Chat/Selection/ChannelListItem.cs @@ -15,7 +15,7 @@ using osu.Game.Graphics.Sprites; using osu.Game.Online.Chat; using osu.Game.Graphics.Containers; -namespace osu.Game.Overlays.Chat +namespace osu.Game.Overlays.Chat.Selection { public class ChannelListItem : OsuClickableContainer, IFilterable { diff --git a/osu.Game/Overlays/Chat/ChannelSection.cs b/osu.Game/Overlays/Chat/Selection/ChannelSection.cs similarity index 97% rename from osu.Game/Overlays/Chat/ChannelSection.cs rename to osu.Game/Overlays/Chat/Selection/ChannelSection.cs index 89d9d2231c..c9097fe4db 100644 --- a/osu.Game/Overlays/Chat/ChannelSection.cs +++ b/osu.Game/Overlays/Chat/Selection/ChannelSection.cs @@ -9,7 +9,7 @@ using osu.Framework.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Online.Chat; -namespace osu.Game.Overlays.Chat +namespace osu.Game.Overlays.Chat.Selection { public class ChannelSection : Container, IHasFilterableChildren { diff --git a/osu.Game/Overlays/Chat/ChannelSelectionOverlay.cs b/osu.Game/Overlays/Chat/Selection/ChannelSelectionOverlay.cs similarity index 99% rename from osu.Game/Overlays/Chat/ChannelSelectionOverlay.cs rename to osu.Game/Overlays/Chat/Selection/ChannelSelectionOverlay.cs index 57f2cd405d..8a18f6e0fa 100644 --- a/osu.Game/Overlays/Chat/ChannelSelectionOverlay.cs +++ b/osu.Game/Overlays/Chat/Selection/ChannelSelectionOverlay.cs @@ -18,7 +18,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Online.Chat; using osu.Game.Graphics.Containers; -namespace osu.Game.Overlays.Chat +namespace osu.Game.Overlays.Chat.Selection { public class ChannelSelectionOverlay : OsuFocusedOverlayContainer { diff --git a/osu.Game/Overlays/Chat/Tabs/ChannelSelectorTabItem.cs b/osu.Game/Overlays/Chat/Tabs/ChannelSelectorTabItem.cs new file mode 100644 index 0000000000..0b1721741a --- /dev/null +++ b/osu.Game/Overlays/Chat/Tabs/ChannelSelectorTabItem.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 osu.Framework.Allocation; +using osu.Game.Graphics; +using osu.Game.Online.Chat; + +namespace osu.Game.Overlays.Chat.Tabs +{ + public class ChannelSelectorTabItem : ChannelTabItem + { + public override bool IsRemovable => false; + + public ChannelSelectorTabItem(Channel value) : base(value) + { + Depth = float.MaxValue; + Width = 45; + + Icon.Alpha = 0; + + Text.TextSize = 45; + TextBold.TextSize = 45; + } + + [BackgroundDependencyLoader] + private new void load(OsuColour colour) + { + BackgroundInactive = colour.Gray2; + BackgroundActive = colour.Gray3; + } + } +} diff --git a/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs b/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs new file mode 100644 index 0000000000..1df26fb118 --- /dev/null +++ b/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs @@ -0,0 +1,96 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; +using osu.Game.Online.Chat; +using OpenTK; +using osu.Framework.Configuration; +using System; +using osu.Game.Overlays.Chat.Tabs; + +namespace osu.Game.Overlays.Chat.Tabs +{ + public class ChannelTabControl : OsuTabControl + { + public static readonly float shear_width = 10; + + public Action OnRequestLeave; + + public readonly Bindable ChannelSelectorActive = new Bindable(); + + private readonly ChannelSelectorTabItem selectorTab; + + public ChannelTabControl() + { + TabContainer.Margin = new MarginPadding { Left = 50 }; + TabContainer.Spacing = new Vector2(-shear_width, 0); + TabContainer.Masking = false; + + AddInternal(new SpriteIcon + { + Icon = FontAwesome.fa_comments, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Size = new Vector2(20), + Margin = new MarginPadding(10), + }); + + AddTabItem(selectorTab = new ChannelSelectorTabItem(new Channel { Name = "+" })); + + ChannelSelectorActive.BindTo(selectorTab.Active); + } + + protected override void AddTabItem(TabItem item, bool addToDropdown = true) + { + if (item != selectorTab && TabContainer.GetLayoutPosition(selectorTab) < float.MaxValue) + // performTabSort might've made selectorTab's position wonky, fix it + TabContainer.SetLayoutPosition(selectorTab, float.MaxValue); + + base.AddTabItem(item, addToDropdown); + } + + protected override TabItem CreateTabItem(Channel value) + { + switch (value.Target) + { + case TargetType.Channel: + return new ChannelTabItem(value) { OnRequestClose = tabCloseRequested }; + case TargetType.User: + return new UserTabItem(value) { OnRequestClose = tabCloseRequested }; + default: + throw new InvalidOperationException("Only TargetType User and Channel are supported."); + } + } + + protected override void SelectTab(TabItem tab) + { + if (tab is ChannelSelectorTabItem) + { + tab.Active.Toggle(); + return; + } + + selectorTab.Active.Value = false; + + base.SelectTab(tab); + } + + private void tabCloseRequested(TabItem tab) + { + int totalTabs = TabContainer.Count - 1; // account for selectorTab + int currentIndex = MathHelper.Clamp(TabContainer.IndexOf(tab), 1, totalTabs); + + if (tab == SelectedTab && totalTabs > 1) + // Select the tab after tab-to-be-removed's index, or the tab before if current == last + SelectTab(TabContainer[currentIndex == totalTabs ? currentIndex - 1 : currentIndex + 1]); + else if (totalTabs == 1 && !selectorTab.Active) + // Open channel selection overlay if all channel tabs will be closed after removing this tab + SelectTab(selectorTab); + + OnRequestLeave?.Invoke(tab.Value); + } + } +} diff --git a/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs b/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs new file mode 100644 index 0000000000..592f2eead8 --- /dev/null +++ b/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs @@ -0,0 +1,194 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Online.Chat; +using OpenTK; +using OpenTK.Graphics; + +namespace osu.Game.Overlays.Chat.Tabs +{ + public class ChannelTabItem : TabItem + { + + protected Color4 BackgroundInactive; + private Color4 backgroundHover; + protected Color4 BackgroundActive; + + public override bool IsRemovable => !Pinned; + + protected readonly SpriteText Text; + protected readonly SpriteText TextBold; + private readonly ClickableContainer closeButton; + private readonly Box box; + private readonly Box highlightBox; + protected readonly SpriteIcon Icon; + + public Action OnRequestClose; + + private void updateState() + { + if (Active) + fadeActive(); + else + fadeInactive(); + } + + private const float transition_length = 400; + + private void fadeActive() + { + this.ResizeTo(new Vector2(Width, 1.1f), transition_length, Easing.OutQuint); + + box.FadeColour(BackgroundActive, transition_length, Easing.OutQuint); + highlightBox.FadeIn(transition_length, Easing.OutQuint); + + Text.FadeOut(transition_length, Easing.OutQuint); + TextBold.FadeIn(transition_length, Easing.OutQuint); + } + + private void fadeInactive() + { + this.ResizeTo(new Vector2(Width, 1), transition_length, Easing.OutQuint); + + box.FadeColour(BackgroundInactive, transition_length, Easing.OutQuint); + highlightBox.FadeOut(transition_length, Easing.OutQuint); + + Text.FadeIn(transition_length, Easing.OutQuint); + TextBold.FadeOut(transition_length, Easing.OutQuint); + } + + protected override bool OnHover(InputState state) + { + if (IsRemovable) + closeButton.FadeIn(200, Easing.OutQuint); + + if (!Active) + box.FadeColour(backgroundHover, transition_length, Easing.OutQuint); + return true; + } + + protected override void OnHoverLost(InputState state) + { + closeButton.FadeOut(200, Easing.OutQuint); + updateState(); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + BackgroundActive = colours.ChatBlue; + BackgroundInactive = colours.Gray4; + backgroundHover = colours.Gray7; + + highlightBox.Colour = colours.Yellow; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + updateState(); + } + + protected override void OnActivated() => updateState(); + + protected override void OnDeactivated() => updateState(); + + public ChannelTabItem(Channel value) + : base(value) + { + Width = 150; + + RelativeSizeAxes = Axes.Y; + + Anchor = Anchor.BottomLeft; + Origin = Anchor.BottomLeft; + + Shear = new Vector2(ChannelTabControl.shear_width / ChatOverlay.TAB_AREA_HEIGHT, 0); + + Masking = true; + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Radius = 10, + Colour = Color4.Black.Opacity(0.2f), + }; + + Children = new Drawable[] + { + box = new Box + { + EdgeSmoothness = new Vector2(1, 0), + RelativeSizeAxes = Axes.Both, + }, + highlightBox = new Box + { + Width = 5, + Alpha = 0, + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + EdgeSmoothness = new Vector2(1, 0), + RelativeSizeAxes = Axes.Y, + }, + new Container + { + Shear = new Vector2(-ChannelTabControl.shear_width / ChatOverlay.TAB_AREA_HEIGHT, 0), + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + Icon = new SpriteIcon + { + Icon = FontAwesome.fa_hashtag, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Colour = Color4.Black, + X = -10, + Alpha = 0.2f, + Size = new Vector2(ChatOverlay.TAB_AREA_HEIGHT), + }, + Text = new OsuSpriteText + { + Margin = new MarginPadding(5), + Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreLeft, + Text = value.ToString(), + TextSize = 18, + }, + TextBold = new OsuSpriteText + { + Alpha = 0, + Margin = new MarginPadding(5), + Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreLeft, + Text = value.ToString(), + Font = @"Exo2.0-Bold", + TextSize = 18, + }, + closeButton = new TabCloseButton + { + Alpha = 0, + Margin = new MarginPadding { Right = 20 }, + Origin = Anchor.CentreRight, + Anchor = Anchor.CentreRight, + Action = delegate + { + if (IsRemovable) OnRequestClose?.Invoke(this); + }, + }, + }, + }, + }; + } + } +} diff --git a/osu.Game/Overlays/Chat/ChatTabItemCloseButton.cs b/osu.Game/Overlays/Chat/Tabs/TabCloseButton.cs similarity index 91% rename from osu.Game/Overlays/Chat/ChatTabItemCloseButton.cs rename to osu.Game/Overlays/Chat/Tabs/TabCloseButton.cs index 0ec2e52963..f6af2f2a4a 100644 --- a/osu.Game/Overlays/Chat/ChatTabItemCloseButton.cs +++ b/osu.Game/Overlays/Chat/Tabs/TabCloseButton.cs @@ -8,13 +8,13 @@ using osu.Game.Graphics.Containers; using OpenTK; using OpenTK.Graphics; -namespace osu.Game.Overlays.Chat +namespace osu.Game.Overlays.Chat.Tabs { - public class ChatTabItemCloseButton : OsuClickableContainer + public class TabCloseButton : OsuClickableContainer { private readonly SpriteIcon icon; - public ChatTabItemCloseButton() + public TabCloseButton() { Size = new Vector2(20); diff --git a/osu.Game/Overlays/Chat/UserTabItem.cs b/osu.Game/Overlays/Chat/Tabs/UserTabItem.cs similarity index 98% rename from osu.Game/Overlays/Chat/UserTabItem.cs rename to osu.Game/Overlays/Chat/Tabs/UserTabItem.cs index 5f81e9fe9e..075e4ae965 100644 --- a/osu.Game/Overlays/Chat/UserTabItem.cs +++ b/osu.Game/Overlays/Chat/Tabs/UserTabItem.cs @@ -17,7 +17,7 @@ using osu.Game.Users; using OpenTK; using OpenTK.Graphics; -namespace osu.Game.Overlays.Chat +namespace osu.Game.Overlays.Chat.Tabs { public class UserTabItem : TabItem { @@ -29,7 +29,7 @@ namespace osu.Game.Overlays.Chat private readonly Box backgroundBox; private readonly OsuSpriteText username; private readonly Avatar avatarContainer; - private readonly ChatTabItemCloseButton closeButton; + private readonly TabCloseButton closeButton; public UserTabItem(Channel value) : base(value) @@ -138,7 +138,7 @@ namespace osu.Game.Overlays.Chat TextSize = 18, Alpha = 0, }, - closeButton = new ChatTabItemCloseButton + closeButton = new TabCloseButton { Height = 1, Origin = Anchor.BottomLeft, diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 403508627e..01de1dd9d7 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -19,6 +19,7 @@ using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osu.Game.Online.Chat; using osu.Game.Overlays.Chat; +using osu.Game.Overlays.Chat.Selection; namespace osu.Game.Overlays { From 0c62726fd72a4585351d27d671327d755eef5882 Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 9 Jul 2018 19:48:05 +0200 Subject: [PATCH 037/155] Rename UserTabItem to UserChannelTabItem --- osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs | 2 +- .../Chat/Tabs/{UserTabItem.cs => UserChannelTabItem.cs} | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) rename osu.Game/Overlays/Chat/Tabs/{UserTabItem.cs => UserChannelTabItem.cs} (98%) diff --git a/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs b/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs index 1df26fb118..de5ef4d1d1 100644 --- a/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs +++ b/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs @@ -59,7 +59,7 @@ namespace osu.Game.Overlays.Chat.Tabs case TargetType.Channel: return new ChannelTabItem(value) { OnRequestClose = tabCloseRequested }; case TargetType.User: - return new UserTabItem(value) { OnRequestClose = tabCloseRequested }; + return new UserChannelTabItem(value) { OnRequestClose = tabCloseRequested }; default: throw new InvalidOperationException("Only TargetType User and Channel are supported."); } diff --git a/osu.Game/Overlays/Chat/Tabs/UserTabItem.cs b/osu.Game/Overlays/Chat/Tabs/UserChannelTabItem.cs similarity index 98% rename from osu.Game/Overlays/Chat/Tabs/UserTabItem.cs rename to osu.Game/Overlays/Chat/Tabs/UserChannelTabItem.cs index 075e4ae965..c4b84e7c21 100644 --- a/osu.Game/Overlays/Chat/Tabs/UserTabItem.cs +++ b/osu.Game/Overlays/Chat/Tabs/UserChannelTabItem.cs @@ -19,7 +19,7 @@ using OpenTK.Graphics; namespace osu.Game.Overlays.Chat.Tabs { - public class UserTabItem : TabItem + public class UserChannelTabItem : TabItem { private static readonly Vector2 shear = new Vector2(1f / 5f, 0); public override bool IsRemovable => true; @@ -31,7 +31,7 @@ namespace osu.Game.Overlays.Chat.Tabs private readonly Avatar avatarContainer; private readonly TabCloseButton closeButton; - public UserTabItem(Channel value) + public UserChannelTabItem(Channel value) : base(value) { if (value.Target != TargetType.User) @@ -160,7 +160,7 @@ namespace osu.Game.Overlays.Chat.Tabs }; } - public Action OnRequestClose; + public Action OnRequestClose; private readonly EdgeEffectParameters activateEdgeEffect = new EdgeEffectParameters { From f22f62ef40a4444bd65ea92a270a167c0c13529e Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 9 Jul 2018 20:13:34 +0200 Subject: [PATCH 038/155] Rename the currentChatChanged to currentChannelContainer, move drawing specific part into from chatoverlay to ChannelSelectionOverlay --- .../Chat/Selection/ChannelSelectionOverlay.cs | 38 +++++++++-------- osu.Game/Overlays/ChatOverlay.cs | 42 ++++++++----------- 2 files changed, 39 insertions(+), 41 deletions(-) diff --git a/osu.Game/Overlays/Chat/Selection/ChannelSelectionOverlay.cs b/osu.Game/Overlays/Chat/Selection/ChannelSelectionOverlay.cs index 8a18f6e0fa..b51d7f9904 100644 --- a/osu.Game/Overlays/Chat/Selection/ChannelSelectionOverlay.cs +++ b/osu.Game/Overlays/Chat/Selection/ChannelSelectionOverlay.cs @@ -35,23 +35,6 @@ namespace osu.Game.Overlays.Chat.Selection public Action OnRequestJoin; public Action OnRequestLeave; - public IEnumerable Sections - { - set - { - sectionsFlow.ChildrenEnumerable = value; - - foreach (ChannelSection s in sectionsFlow.Children) - { - foreach (ChannelListItem c in s.ChannelFlow.Children) - { - c.OnRequestJoin = channel => { OnRequestJoin?.Invoke(channel); }; - c.OnRequestLeave = channel => { OnRequestLeave?.Invoke(channel); }; - } - } - } - } - public ChannelSelectionOverlay() { RelativeSizeAxes = Axes.X; @@ -140,6 +123,27 @@ namespace osu.Game.Overlays.Chat.Selection search.Current.ValueChanged += newValue => sectionsFlow.SearchTerm = newValue; } + public void UpdateAvailableChannels(IEnumerable channels) + { + sectionsFlow.ChildrenEnumerable = new[] + { + new ChannelSection + { + Header = "All Channels", + Channels = channels, + }, + }; + + foreach (ChannelSection s in sectionsFlow.Children) + { + foreach (ChannelListItem c in s.ChannelFlow.Children) + { + c.OnRequestJoin = channel => { OnRequestJoin?.Invoke(channel); }; + c.OnRequestLeave = channel => { OnRequestLeave?.Invoke(channel); }; + } + } + } + [BackgroundDependencyLoader] private void load(OsuColour colours) { diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 01de1dd9d7..d1982e109d 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -30,7 +30,7 @@ namespace osu.Game.Overlays private ChannelManager channelManager; - private readonly Container currentChatContainer; + private readonly Container currentChannelContainer; private readonly List loadedChannels = new List(); private readonly LoadingAnimation loading; @@ -102,7 +102,7 @@ namespace osu.Game.Overlays { RelativeSizeAxes = Axes.Both, }, - currentChatContainer = new Container + currentChannelContainer = new Container { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding @@ -188,14 +188,8 @@ namespace osu.Game.Overlays private void availableChannelsChanged(object sender, NotifyCollectionChangedEventArgs args) { - channelSelection.Sections = new[] - { - new ChannelSection - { - Header = "All Channels", - Channels = channelManager.AvailableChannels, - }, - }; + channelSelection.UpdateAvailableChannels(channelManager.); + } private void joinedChannelsChanged(object sender, NotifyCollectionChangedEventArgs args) @@ -220,42 +214,42 @@ namespace osu.Game.Overlays } } - private void currentChatChanged(Channel chat) + private void currentChatChanged(Channel channel) { - if (chat == null) + if (channel == null) { textbox.Current.Disabled = true; - currentChatContainer.Clear(false); + currentChannelContainer.Clear(false); chatTabControl.Current.Value = null; return; } - textbox.Current.Disabled = chat.ReadOnly; + textbox.Current.Disabled = channel.ReadOnly; - if (chatTabControl.Current.Value != chat) - Scheduler.Add(() => chatTabControl.Current.Value = chat); + if (chatTabControl.Current.Value != channel) + Scheduler.Add(() => chatTabControl.Current.Value = channel); - var loaded = loadedChannels.Find(d => d.Channel == chat); + var loaded = loadedChannels.Find(d => d.Channel == channel); if (loaded == null) { - currentChatContainer.FadeOut(500, Easing.OutQuint); + currentChannelContainer.FadeOut(500, Easing.OutQuint); loading.Show(); - loaded = new DrawableChannel(chat); + loaded = new DrawableChannel(channel); loadedChannels.Add(loaded); LoadComponentAsync(loaded, l => { loading.Hide(); - currentChatContainer.Clear(false); - currentChatContainer.Add(loaded); - currentChatContainer.FadeIn(500, Easing.OutQuint); + currentChannelContainer.Clear(false); + currentChannelContainer.Add(loaded); + currentChannelContainer.FadeIn(500, Easing.OutQuint); }); } else { - currentChatContainer.Clear(false); - currentChatContainer.Add(loaded); + currentChannelContainer.Clear(false); + currentChannelContainer.Add(loaded); } } From f681ef41ac2e8735713547343758719b2b16e9a8 Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 9 Jul 2018 20:39:16 +0200 Subject: [PATCH 039/155] Rename MAX_HISTORY to MaxHistory, added some logging on failures, use a lamda in ChatOverlay instead of a method pointer. --- osu.Game/Online/Chat/Channel.cs | 16 +++++----------- osu.Game/Online/Chat/ChannelManager.cs | 7 +++++-- osu.Game/Overlays/Chat/DrawableChannel.cs | 4 ++-- osu.Game/Overlays/ChatOverlay.cs | 8 +------- 4 files changed, 13 insertions(+), 22 deletions(-) diff --git a/osu.Game/Online/Chat/Channel.cs b/osu.Game/Online/Chat/Channel.cs index b7893ed9ff..c515557c3e 100644 --- a/osu.Game/Online/Chat/Channel.cs +++ b/osu.Game/Online/Chat/Channel.cs @@ -14,13 +14,14 @@ namespace osu.Game.Online.Chat { public class Channel { - public readonly int MAX_HISTORY = 300; + public readonly int MaxHistory = 300; /// /// Contains every joined user except the current logged in user. /// public readonly ObservableCollection JoinedUsers = new ObservableCollection(); public readonly SortedList Messages = new SortedList(Comparer.Default); + private readonly List pendingMessages = new List(); public event Action> NewMessagesArrived; public event Action PendingMessageResolved; @@ -43,8 +44,6 @@ namespace osu.Game.Online.Chat [JsonProperty(@"channel_id")] public long Id; - private readonly List pendingMessages = new List(); - [JsonConstructor] public Channel() { @@ -101,12 +100,7 @@ namespace osu.Game.Online.Chat } if (Messages.Contains(final)) - { - // message already inserted, so let's throw away this update. - // we may want to handle this better in the future, but for the time being api requests are single-threaded so order is assumed. - MessageRemoved?.Invoke(echo); - return; - } + throw new InvalidOperationException("Attempted to add the same message again"); Messages.Add(final); PendingMessageResolved?.Invoke(echo, final); @@ -116,8 +110,8 @@ namespace osu.Game.Online.Chat { // never purge local echos int messageCount = Messages.Count - pendingMessages.Count; - if (messageCount > MAX_HISTORY) - Messages.RemoveRange(0, messageCount - MAX_HISTORY); + if (messageCount > MaxHistory) + Messages.RemoveRange(0, messageCount - MaxHistory); } diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 60e7217756..027f18ce3f 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -112,7 +112,11 @@ namespace osu.Game.Online.Chat CurrentChannel.Value.AddLocalEcho(message); var req = new PostMessageRequest(message); - req.Failure += e => CurrentChannel.Value?.ReplaceMessage(message, null); + req.Failure += exception => + { + Logger.Error(exception, "Posting message failed."); + CurrentChannel.Value?.ReplaceMessage(message, null); + }; req.Success += m => CurrentChannel.Value?.ReplaceMessage(message, m); api.Queue(req); } @@ -305,7 +309,6 @@ namespace osu.Game.Online.Chat public ChannelNotFoundException(string channelName) : base($"A channel with the name {channelName} could not be found.") { - } } } diff --git a/osu.Game/Overlays/Chat/DrawableChannel.cs b/osu.Game/Overlays/Chat/DrawableChannel.cs index bcc8879902..8cc77f82f3 100644 --- a/osu.Game/Overlays/Chat/DrawableChannel.cs +++ b/osu.Game/Overlays/Chat/DrawableChannel.cs @@ -79,7 +79,7 @@ namespace osu.Game.Overlays.Chat private void newMessagesArrived(IEnumerable newMessages) { // Add up to last Channel.MAX_HISTORY messages - var displayMessages = newMessages.Skip(Math.Max(0, newMessages.Count() - Channel.MAX_HISTORY)); + var displayMessages = newMessages.Skip(Math.Max(0, newMessages.Count() - Channel.MaxHistory)); flow.AddRange(displayMessages.Select(m => new ChatLine(m))); @@ -89,7 +89,7 @@ namespace osu.Game.Overlays.Chat scrollToEnd(); var staleMessages = flow.Children.Where(c => c.LifetimeEnd == double.MaxValue).ToArray(); - int count = staleMessages.Length - Channel.MAX_HISTORY; + int count = staleMessages.Length - Channel.MaxHistory; for (int i = 0; i < count; i++) { diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index d1982e109d..de241dd9c0 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -186,12 +186,6 @@ namespace osu.Game.Overlays channelSelection.OnRequestLeave = channel => channelManager.JoinedChannels.Remove(channel); } - private void availableChannelsChanged(object sender, NotifyCollectionChangedEventArgs args) - { - channelSelection.UpdateAvailableChannels(channelManager.); - - } - private void joinedChannelsChanged(object sender, NotifyCollectionChangedEventArgs args) { switch (args.Action) @@ -337,7 +331,7 @@ namespace osu.Game.Overlays this.channelManager = channelManager; channelManager.CurrentChannel.ValueChanged += currentChatChanged; channelManager.JoinedChannels.CollectionChanged += joinedChannelsChanged; - channelManager.AvailableChannels.CollectionChanged += availableChannelsChanged; + channelManager.AvailableChannels.CollectionChanged += (sender, args) => channelSelection.UpdateAvailableChannels(channelManager.AvailableChannels); Add(channelManager); } From ec914a5095ddaaebbe7c24ad3ad7d49abc1c2252 Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 9 Jul 2018 21:00:39 +0200 Subject: [PATCH 040/155] Fix crash when the local echo is send to the wrong channel. --- osu.Game/Online/Chat/Channel.cs | 2 +- osu.Game/Online/Chat/ChannelManager.cs | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/osu.Game/Online/Chat/Channel.cs b/osu.Game/Online/Chat/Channel.cs index c515557c3e..666a41f9d3 100644 --- a/osu.Game/Online/Chat/Channel.cs +++ b/osu.Game/Online/Chat/Channel.cs @@ -29,7 +29,7 @@ namespace osu.Game.Online.Chat public readonly Bindable Joined = new Bindable(); public TargetType Target { get; } - public bool ReadOnly { get; set; } + public bool ReadOnly => false; //todo not yet used. public override string ToString() => Name; [JsonProperty(@"name")] diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 027f18ce3f..233ed00261 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -93,9 +93,11 @@ namespace osu.Game.Online.Chat if (CurrentChannel.Value == null) return; + var currentChannel = CurrentChannel.Value; + if (!api.IsLoggedIn) { - CurrentChannel.Value.AddNewMessages(new ErrorMessage("Please sign in to participate in chat!")); + currentChannel.AddNewMessages(new ErrorMessage("Please sign in to participate in chat!")); return; } @@ -109,15 +111,15 @@ namespace osu.Game.Online.Chat Content = text }; - CurrentChannel.Value.AddLocalEcho(message); + currentChannel.AddLocalEcho(message); var req = new PostMessageRequest(message); req.Failure += exception => { Logger.Error(exception, "Posting message failed."); - CurrentChannel.Value?.ReplaceMessage(message, null); + currentChannel.ReplaceMessage(message, null); }; - req.Success += m => CurrentChannel.Value?.ReplaceMessage(message, m); + req.Success += m => currentChannel.ReplaceMessage(message, m); api.Queue(req); } From 290b6e5f1de32c206d9adbe57e2ee41716b9c2f4 Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 9 Jul 2018 22:09:27 +0200 Subject: [PATCH 041/155] Fix the crash in the visual testcase --- osu.Game.Tests/Visual/TestCaseChatDisplay.cs | 1 + osu.Game.Tests/Visual/TestCaseChatTabControl.cs | 1 + osu.Game/Online/Chat/ChannelManager.cs | 10 +++++----- osu.Game/OsuGameBase.cs | 1 + osu.Game/Overlays/ChatOverlay.cs | 1 - 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseChatDisplay.cs b/osu.Game.Tests/Visual/TestCaseChatDisplay.cs index c03b12bdc1..9057ec0d79 100644 --- a/osu.Game.Tests/Visual/TestCaseChatDisplay.cs +++ b/osu.Game.Tests/Visual/TestCaseChatDisplay.cs @@ -3,6 +3,7 @@ using System.ComponentModel; using osu.Framework.Graphics.Containers; +using osu.Game.Online.Chat; using osu.Game.Overlays; namespace osu.Game.Tests.Visual diff --git a/osu.Game.Tests/Visual/TestCaseChatTabControl.cs b/osu.Game.Tests/Visual/TestCaseChatTabControl.cs index e530c1b72a..a1b8eaf051 100644 --- a/osu.Game.Tests/Visual/TestCaseChatTabControl.cs +++ b/osu.Game.Tests/Visual/TestCaseChatTabControl.cs @@ -15,6 +15,7 @@ using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.Chat; using osu.Game.Overlays.Chat; +using osu.Game.Overlays.Chat.Tabs; using osu.Game.Users; using OpenTK.Graphics; diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 233ed00261..ed8677097b 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -50,7 +50,7 @@ namespace osu.Game.Online.Chat private IAPIProvider api; private ScheduledDelegate fetchMessagesScheduleder; private GetMessagesRequest fetchMsgReq; - private GetPrivateMessagesRequest fetchPrivateMsgReq; + private GetPrivateMessagesRequest fetchUserMsgReq; private long? lastChannelMsgId; private long? lastUserMsgId; @@ -170,16 +170,16 @@ namespace osu.Game.Online.Chat ); - if (fetchPrivateMsgReq == null) + if (fetchUserMsgReq == null) fetchMessages( - () => new GetPrivateMessagesRequest(lastChannelMsgId), + () => new GetPrivateMessagesRequest(lastUserMsgId), messages => { if (messages == null) return; handleUserMessages(messages); - lastUserMsgId = messages.LastOrDefault()?.Id ?? lastUserMsgId; - fetchPrivateMsgReq = null; + lastUserMsgId = messages.Max(m => m.Id) ?? lastUserMsgId; + fetchUserMsgReq = null; } ); } diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index cae5352739..b32585e129 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -124,6 +124,7 @@ namespace osu.Game var channelManager = new ChannelManager(); dependencies.Inject(channelManager); dependencies.Cache(channelManager); + AddInternal(channelManager); dependencies.Cache(RulesetStore = new RulesetStore(contextFactory)); dependencies.Cache(FileStore = new FileStore(contextFactory, Host.Storage)); diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index de241dd9c0..8132c3c7ed 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -332,7 +332,6 @@ namespace osu.Game.Overlays channelManager.CurrentChannel.ValueChanged += currentChatChanged; channelManager.JoinedChannels.CollectionChanged += joinedChannelsChanged; channelManager.AvailableChannels.CollectionChanged += (sender, args) => channelSelection.UpdateAvailableChannels(channelManager.AvailableChannels); - Add(channelManager); } private void postMessage(TextBox textbox, bool newText) From 3140b2e15c67089e4b62f0538f032af3d46c9348 Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 9 Jul 2018 22:14:21 +0200 Subject: [PATCH 042/155] Fix duplicate messages appearing --- osu.Game/Online/Chat/ChannelManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index ed8677097b..f4ff523689 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -158,7 +158,7 @@ namespace osu.Game.Online.Chat { if (fetchMsgReq == null) fetchMessages( - () => new GetMessagesRequest(JoinedChannels.Where(c => c.Target == TargetType.Channel), lastChannelMsgId), + () => fetchMsgReq = new GetMessagesRequest(JoinedChannels.Where(c => c.Target == TargetType.Channel), lastChannelMsgId), messages => { if (messages == null) @@ -172,7 +172,7 @@ namespace osu.Game.Online.Chat if (fetchUserMsgReq == null) fetchMessages( - () => new GetPrivateMessagesRequest(lastUserMsgId), + () => fetchUserMsgReq = new GetPrivateMessagesRequest(lastUserMsgId), messages => { if (messages == null) From 72ea3128faaa58429e0fd0840bf11fad3187e94e Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 9 Jul 2018 22:14:47 +0200 Subject: [PATCH 043/155] Use the AT (@) symbol for the background --- osu.Game/Overlays/Chat/Tabs/UserChannelTabItem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Chat/Tabs/UserChannelTabItem.cs b/osu.Game/Overlays/Chat/Tabs/UserChannelTabItem.cs index c4b84e7c21..e729e72d36 100644 --- a/osu.Game/Overlays/Chat/Tabs/UserChannelTabItem.cs +++ b/osu.Game/Overlays/Chat/Tabs/UserChannelTabItem.cs @@ -101,7 +101,7 @@ namespace osu.Game.Overlays.Chat.Tabs { new SpriteIcon { - Icon = FontAwesome.fa_eercast, + Icon = FontAwesome.fa_at, Origin = Anchor.Centre, Scale = new Vector2(1.2f), X = -5, From ea597916ca2837e83ed93804b9ef2f93d9a4357a Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 9 Jul 2018 22:41:53 +0200 Subject: [PATCH 044/155] Code cleanups --- osu.Game.Tests/Visual/TestCaseChatDisplay.cs | 1 - osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs | 1 - osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs | 4 ++-- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseChatDisplay.cs b/osu.Game.Tests/Visual/TestCaseChatDisplay.cs index 9057ec0d79..c03b12bdc1 100644 --- a/osu.Game.Tests/Visual/TestCaseChatDisplay.cs +++ b/osu.Game.Tests/Visual/TestCaseChatDisplay.cs @@ -3,7 +3,6 @@ using System.ComponentModel; using osu.Framework.Graphics.Containers; -using osu.Game.Online.Chat; using osu.Game.Overlays; namespace osu.Game.Tests.Visual diff --git a/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs b/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs index de5ef4d1d1..69df971df4 100644 --- a/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs +++ b/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs @@ -9,7 +9,6 @@ using osu.Game.Online.Chat; using OpenTK; using osu.Framework.Configuration; using System; -using osu.Game.Overlays.Chat.Tabs; namespace osu.Game.Overlays.Chat.Tabs { diff --git a/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs b/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs index 592f2eead8..389861ca9c 100644 --- a/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs +++ b/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs @@ -115,7 +115,7 @@ namespace osu.Game.Overlays.Chat.Tabs Anchor = Anchor.BottomLeft; Origin = Anchor.BottomLeft; - Shear = new Vector2(ChannelTabControl.shear_width / ChatOverlay.TAB_AREA_HEIGHT, 0); + Shear = new Vector2(ChannelTabControl.SHEAR_WIDTH / ChatOverlay.TAB_AREA_HEIGHT, 0); Masking = true; EdgeEffect = new EdgeEffectParameters @@ -143,7 +143,7 @@ namespace osu.Game.Overlays.Chat.Tabs }, new Container { - Shear = new Vector2(-ChannelTabControl.shear_width / ChatOverlay.TAB_AREA_HEIGHT, 0), + Shear = new Vector2(-ChannelTabControl.SHEAR_WIDTH / ChatOverlay.TAB_AREA_HEIGHT, 0), RelativeSizeAxes = Axes.Both, Children = new Drawable[] { From 8e93269885300b1aa8ac3c9d32409de61bbc2411 Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 9 Jul 2018 22:47:01 +0200 Subject: [PATCH 045/155] Remove whitespace --- osu.Game/Online/Chat/Channel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/Channel.cs b/osu.Game/Online/Chat/Channel.cs index 666a41f9d3..e749a7c946 100644 --- a/osu.Game/Online/Chat/Channel.cs +++ b/osu.Game/Online/Chat/Channel.cs @@ -61,7 +61,7 @@ namespace osu.Game.Online.Chat Id = user.Id; JoinedUsers.Add(user); } - + public void AddLocalEcho(LocalEchoMessage message) { pendingMessages.Add(message); From 73a87914f26a1749b1e9d8bbeb1c4b6688ec7ca1 Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 9 Jul 2018 22:52:14 +0200 Subject: [PATCH 046/155] Rename uppcase shear width to lowercase shearwidth --- osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs b/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs index 389861ca9c..592f2eead8 100644 --- a/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs +++ b/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs @@ -115,7 +115,7 @@ namespace osu.Game.Overlays.Chat.Tabs Anchor = Anchor.BottomLeft; Origin = Anchor.BottomLeft; - Shear = new Vector2(ChannelTabControl.SHEAR_WIDTH / ChatOverlay.TAB_AREA_HEIGHT, 0); + Shear = new Vector2(ChannelTabControl.shear_width / ChatOverlay.TAB_AREA_HEIGHT, 0); Masking = true; EdgeEffect = new EdgeEffectParameters @@ -143,7 +143,7 @@ namespace osu.Game.Overlays.Chat.Tabs }, new Container { - Shear = new Vector2(-ChannelTabControl.SHEAR_WIDTH / ChatOverlay.TAB_AREA_HEIGHT, 0), + Shear = new Vector2(-ChannelTabControl.shear_width / ChatOverlay.TAB_AREA_HEIGHT, 0), RelativeSizeAxes = Axes.Both, Children = new Drawable[] { From 9f9444d65af583ec8c9b27b5ce4a6b404525ace1 Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 9 Jul 2018 22:59:29 +0200 Subject: [PATCH 047/155] Uppercase shear... wtf --- osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs | 4 ++-- osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs b/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs index 69df971df4..e1f02e9c79 100644 --- a/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs +++ b/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs @@ -14,7 +14,7 @@ namespace osu.Game.Overlays.Chat.Tabs { public class ChannelTabControl : OsuTabControl { - public static readonly float shear_width = 10; + public static readonly float SHEAR_WIDTH = 10; public Action OnRequestLeave; @@ -25,7 +25,7 @@ namespace osu.Game.Overlays.Chat.Tabs public ChannelTabControl() { TabContainer.Margin = new MarginPadding { Left = 50 }; - TabContainer.Spacing = new Vector2(-shear_width, 0); + TabContainer.Spacing = new Vector2(-SHEAR_WIDTH, 0); TabContainer.Masking = false; AddInternal(new SpriteIcon diff --git a/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs b/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs index 592f2eead8..389861ca9c 100644 --- a/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs +++ b/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs @@ -115,7 +115,7 @@ namespace osu.Game.Overlays.Chat.Tabs Anchor = Anchor.BottomLeft; Origin = Anchor.BottomLeft; - Shear = new Vector2(ChannelTabControl.shear_width / ChatOverlay.TAB_AREA_HEIGHT, 0); + Shear = new Vector2(ChannelTabControl.SHEAR_WIDTH / ChatOverlay.TAB_AREA_HEIGHT, 0); Masking = true; EdgeEffect = new EdgeEffectParameters @@ -143,7 +143,7 @@ namespace osu.Game.Overlays.Chat.Tabs }, new Container { - Shear = new Vector2(-ChannelTabControl.shear_width / ChatOverlay.TAB_AREA_HEIGHT, 0), + Shear = new Vector2(-ChannelTabControl.SHEAR_WIDTH / ChatOverlay.TAB_AREA_HEIGHT, 0), RelativeSizeAxes = Axes.Both, Children = new Drawable[] { From d03367ef9eb22adb1465530849c4e398f4e05f97 Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 9 Jul 2018 23:12:41 +0200 Subject: [PATCH 048/155] Fix the start animations of username and the closeButton --- osu.Game/Overlays/Chat/Tabs/UserChannelTabItem.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Overlays/Chat/Tabs/UserChannelTabItem.cs b/osu.Game/Overlays/Chat/Tabs/UserChannelTabItem.cs index e729e72d36..6b11c7860f 100644 --- a/osu.Game/Overlays/Chat/Tabs/UserChannelTabItem.cs +++ b/osu.Game/Overlays/Chat/Tabs/UserChannelTabItem.cs @@ -158,6 +158,9 @@ namespace osu.Game.Overlays.Chat.Tabs } } }; + + username.ScaleTo(new Vector2(0, 1)); + closeButton.ScaleTo(new Vector2(0, 1)); } public Action OnRequestClose; From 344ec40a2767ebd3a015c542b051fbebb0f03501 Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 23 Jul 2018 15:48:48 +0200 Subject: [PATCH 049/155] Readd usings I removed with my merge --- osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs | 1 + osu.Game/Overlays/Chat/Tabs/TabCloseButton.cs | 2 ++ osu.Game/Overlays/ChatOverlay.cs | 1 + 3 files changed, 4 insertions(+) diff --git a/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs b/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs index 389861ca9c..fede67529b 100644 --- a/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs +++ b/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input; +using osu.Framework.Input.States; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Online.Chat; diff --git a/osu.Game/Overlays/Chat/Tabs/TabCloseButton.cs b/osu.Game/Overlays/Chat/Tabs/TabCloseButton.cs index f6af2f2a4a..ec53c9a353 100644 --- a/osu.Game/Overlays/Chat/Tabs/TabCloseButton.cs +++ b/osu.Game/Overlays/Chat/Tabs/TabCloseButton.cs @@ -3,6 +3,8 @@ using osu.Framework.Graphics; using osu.Framework.Input; +using osu.Framework.Input.EventArgs; +using osu.Framework.Input.States; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using OpenTK; diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 8132c3c7ed..36ee49a3d9 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -13,6 +13,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input; +using osu.Framework.Input.States; using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Containers; From 2726d91594fb4efca6f8c03099f88104f23e8579 Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 23 Jul 2018 16:05:39 +0200 Subject: [PATCH 050/155] Remove unessary usings --- osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs | 1 - osu.Game/Overlays/Chat/Tabs/TabCloseButton.cs | 1 - osu.Game/Overlays/ChatOverlay.cs | 1 - 3 files changed, 3 deletions(-) diff --git a/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs b/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs index fede67529b..28a1f91df4 100644 --- a/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs +++ b/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs @@ -9,7 +9,6 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; -using osu.Framework.Input; using osu.Framework.Input.States; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; diff --git a/osu.Game/Overlays/Chat/Tabs/TabCloseButton.cs b/osu.Game/Overlays/Chat/Tabs/TabCloseButton.cs index ec53c9a353..4476e61dfc 100644 --- a/osu.Game/Overlays/Chat/Tabs/TabCloseButton.cs +++ b/osu.Game/Overlays/Chat/Tabs/TabCloseButton.cs @@ -2,7 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Graphics; -using osu.Framework.Input; using osu.Framework.Input.EventArgs; using osu.Framework.Input.States; using osu.Game.Graphics; diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 36ee49a3d9..cee0a19868 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -12,7 +12,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; -using osu.Framework.Input; using osu.Framework.Input.States; using osu.Game.Configuration; using osu.Game.Graphics; From 0aacde836ac04281901c6dc8e6d3848c1f8e4f29 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 Jul 2018 20:46:44 +0200 Subject: [PATCH 051/155] Move private channel constructor to own class --- .../Visual/TestCaseChatTabControl.cs | 2 +- .../Online/API/Requests/GetMessagesRequest.cs | 2 +- osu.Game/Online/Chat/Channel.cs | 18 ++---------- osu.Game/Online/Chat/ChannelManager.cs | 6 ++-- osu.Game/Online/Chat/PrivateChannel.cs | 29 +++++++++++++++++++ 5 files changed, 36 insertions(+), 21 deletions(-) create mode 100644 osu.Game/Online/Chat/PrivateChannel.cs diff --git a/osu.Game.Tests/Visual/TestCaseChatTabControl.cs b/osu.Game.Tests/Visual/TestCaseChatTabControl.cs index a1b8eaf051..c7d88a4d0e 100644 --- a/osu.Game.Tests/Visual/TestCaseChatTabControl.cs +++ b/osu.Game.Tests/Visual/TestCaseChatTabControl.cs @@ -88,7 +88,7 @@ namespace osu.Game.Tests.Visual if (users == null || users.Count == 0) return; - chatTabControl.AddItem(new Channel(users[RNG.Next(0, users.Count - 1)])); + chatTabControl.AddItem(new PrivateChannel { User = users[RNG.Next(0, users.Count - 1)] }); } private void addChannel(string name) diff --git a/osu.Game/Online/API/Requests/GetMessagesRequest.cs b/osu.Game/Online/API/Requests/GetMessagesRequest.cs index 5ab621c662..f959f94b9c 100644 --- a/osu.Game/Online/API/Requests/GetMessagesRequest.cs +++ b/osu.Game/Online/API/Requests/GetMessagesRequest.cs @@ -18,7 +18,7 @@ namespace osu.Game.Online.API.Requests if (channels == null) throw new ArgumentNullException(nameof(channels)); if (channels.Any(c => c.Target != TargetType.Channel)) - throw new ArgumentException("All channels in the argument channels must have the targettype Channel"); + throw new ArgumentException($"All channels in the argument channels must have the {nameof(Channel.Target)} Channel"); this.channels = channels; } diff --git a/osu.Game/Online/Chat/Channel.cs b/osu.Game/Online/Chat/Channel.cs index e749a7c946..cf702f2608 100644 --- a/osu.Game/Online/Chat/Channel.cs +++ b/osu.Game/Online/Chat/Channel.cs @@ -20,6 +20,7 @@ namespace osu.Game.Online.Chat /// Contains every joined user except the current logged in user. /// public readonly ObservableCollection JoinedUsers = new ObservableCollection(); + public readonly SortedList Messages = new SortedList(Comparer.Default); private readonly List pendingMessages = new List(); @@ -28,7 +29,7 @@ namespace osu.Game.Online.Chat public event Action MessageRemoved; public readonly Bindable Joined = new Bindable(); - public TargetType Target { get; } + public TargetType Target { get; protected set; } public bool ReadOnly => false; //todo not yet used. public override string ToString() => Name; @@ -49,19 +50,6 @@ namespace osu.Game.Online.Chat { } - /// - /// Contructs a private channel - /// TODO this class needs to be serialized from something like channels/private, instead of creating from the contructor - /// - /// The user - public Channel(User user) - { - Target = TargetType.User; - Name = user.Username; - Id = user.Id; - JoinedUsers.Add(user); - } - public void AddLocalEcho(LocalEchoMessage message) { pendingMessages.Add(message); @@ -113,7 +101,5 @@ namespace osu.Game.Online.Chat if (messageCount > MaxHistory) Messages.RemoveRange(0, messageCount - MaxHistory); } - - } } diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index f4ff523689..c881fb4fe8 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -69,7 +69,7 @@ namespace osu.Game.Online.Chat throw new ArgumentNullException(nameof(user)); CurrentChannel.Value = JoinedChannels.FirstOrDefault(c => c.Target == TargetType.User && c.Id == user.Id) - ?? new Channel(user); + ?? new PrivateChannel { User = user }; } public ChannelManager() @@ -214,7 +214,7 @@ namespace osu.Game.Online.Chat if (channel == null) { - channel = new Channel(targetUser); + channel = new PrivateChannel { User = targetUser }; JoinedChannels.Add(channel); joinedUserChannels.Add(channel); } @@ -234,7 +234,7 @@ namespace osu.Game.Online.Chat userReq.Failure += exception => Logger.Error(exception, "Failed to get user informations."); userReq.Success += user => { - var channel = new Channel(user); + var channel = new PrivateChannel { User = user }; channel.AddNewMessages(withoutReplyGroup.ToArray()); JoinedChannels.Add(channel); diff --git a/osu.Game/Online/Chat/PrivateChannel.cs b/osu.Game/Online/Chat/PrivateChannel.cs new file mode 100644 index 0000000000..aac88ecb27 --- /dev/null +++ b/osu.Game/Online/Chat/PrivateChannel.cs @@ -0,0 +1,29 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Users; + +namespace osu.Game.Online.Chat +{ + public class PrivateChannel : Channel + { + public User User + { + set + { + Name = value.Username; + Id = value.Id; + JoinedUsers.Add(value); + } + } + + /// + /// Contructs a private channel + /// + /// The user + public PrivateChannel() + { + Target = TargetType.User; + } + } +} From 1ab75529a198fecba829a8584fdff792f3a656f4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 Jul 2018 21:15:52 +0200 Subject: [PATCH 052/155] Simplify user channel message population code --- osu.Game/Online/Chat/ChannelManager.cs | 39 +++++++++++++++++--------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index c881fb4fe8..fd8454337e 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -203,29 +203,42 @@ namespace osu.Game.Online.Chat { var joinedUserChannels = JoinedChannels.Where(c => c.Target == TargetType.User).ToList(); - var outgoingMessages = messages.Where(m => m.Sender.Id == api.LocalUser.Value.Id); - var outgoingMessagesGroups = outgoingMessages.GroupBy(m => m.TargetId); - var incomingMessagesGroups = messages.Except(outgoingMessages).GroupBy(m => m.UserId); - - foreach (var messageGroup in incomingMessagesGroups) + Channel getChannelForUser(User user) { - var targetUser = messageGroup.First().Sender; - var channel = joinedUserChannels.FirstOrDefault(c => c.Id == targetUser.Id); + var channel = joinedUserChannels.FirstOrDefault(c => c.Id == user.Id); if (channel == null) { - channel = new PrivateChannel { User = targetUser }; + channel = new PrivateChannel { User = user }; JoinedChannels.Add(channel); joinedUserChannels.Add(channel); } - channel.AddNewMessages(messageGroup.ToArray()); - var outgoingTargetMessages = outgoingMessagesGroups.FirstOrDefault(g => g.Key == targetUser.Id); + return channel; + } + + long localUserId = api.LocalUser.Value.Id; + + var outgoingGroups = messages.Where(m => m.Sender.Id == localUserId).GroupBy(m => m.TargetId); + var incomingGroups = messages.Where(m => m.Sender.Id != localUserId).GroupBy(m => m.UserId); + + foreach (var group in incomingGroups) + { + var targetUser = group.First().Sender; + + var channel = getChannelForUser(targetUser); + + channel.AddNewMessages(group.ToArray()); + + var outgoingTargetMessages = outgoingGroups.FirstOrDefault(g => g.Key == targetUser.Id); if (outgoingTargetMessages != null) channel.AddNewMessages(outgoingTargetMessages.ToArray()); } - var withoutReplyGroups = outgoingMessagesGroups.Where(g => joinedUserChannels.All(m => m.Id != g.Key)); + // Because of the way the API provides data right now, outgoing messages do not contain required + // user (or in the future, target channel) metadata. As such we need to do a second request + // to find out the specifics of the user. + var withoutReplyGroups = outgoingGroups.Where(g => joinedUserChannels.All(m => m.Id != g.Key)); foreach (var withoutReplyGroup in withoutReplyGroups) { @@ -234,10 +247,8 @@ namespace osu.Game.Online.Chat userReq.Failure += exception => Logger.Error(exception, "Failed to get user informations."); userReq.Success += user => { - var channel = new PrivateChannel { User = user }; - + var channel = getChannelForUser(user); channel.AddNewMessages(withoutReplyGroup.ToArray()); - JoinedChannels.Add(channel); }; api.Queue(userReq); From d9611dcffbf2de4dad02e90146e79033266562c3 Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 23 Jul 2018 22:06:40 +0200 Subject: [PATCH 053/155] Instead of Doing nothing at LinkFlowContainer if no link was found, we log it as an error. --- osu.Game/Graphics/Containers/LinkFlowContainer.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/Containers/LinkFlowContainer.cs b/osu.Game/Graphics/Containers/LinkFlowContainer.cs index 0576fc3918..d9be374ced 100644 --- a/osu.Game/Graphics/Containers/LinkFlowContainer.cs +++ b/osu.Game/Graphics/Containers/LinkFlowContainer.cs @@ -7,6 +7,7 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics.Sprites; using System.Collections.Generic; +using osu.Framework.Logging; using osu.Framework.Platform; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; @@ -87,9 +88,9 @@ namespace osu.Game.Graphics.Containers { channelManager.OpenChannel(linkArgument); } - catch (ChannelNotFoundException) + catch (ChannelNotFoundException e) { - //channel was not found + Logger.Error(e, "It should not be possible that the user is able to click a invalid channel link."); } break; case LinkAction.OpenEditorTimestamp: From 2ae890366ad0b06cb3229b33435a763680e26772 Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 23 Jul 2018 22:08:37 +0200 Subject: [PATCH 054/155] Nicefy the errormessage in the constructor of GetMessagesRequest --- osu.Game/Online/API/Requests/GetMessagesRequest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/API/Requests/GetMessagesRequest.cs b/osu.Game/Online/API/Requests/GetMessagesRequest.cs index f959f94b9c..d82046e1e5 100644 --- a/osu.Game/Online/API/Requests/GetMessagesRequest.cs +++ b/osu.Game/Online/API/Requests/GetMessagesRequest.cs @@ -18,7 +18,7 @@ namespace osu.Game.Online.API.Requests if (channels == null) throw new ArgumentNullException(nameof(channels)); if (channels.Any(c => c.Target != TargetType.Channel)) - throw new ArgumentException($"All channels in the argument channels must have the {nameof(Channel.Target)} Channel"); + throw new ArgumentException($"All channels in the argument channels must have a {nameof(Channel.Target)} of {nameof(TargetType.Channel)}"); this.channels = channels; } From 9a6d92bb22558ba1f242c8ca252498bca4c03e6e Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 23 Jul 2018 22:09:05 +0200 Subject: [PATCH 055/155] Rename fetchMsgReq to fetchMessageReq in ChannelManager.cs --- osu.Game/Online/Chat/ChannelManager.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index fd8454337e..57f55492ad 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -49,7 +49,7 @@ namespace osu.Game.Online.Chat private IAPIProvider api; private ScheduledDelegate fetchMessagesScheduleder; - private GetMessagesRequest fetchMsgReq; + private GetMessagesRequest fetchMessageReq; private GetPrivateMessagesRequest fetchUserMsgReq; private long? lastChannelMsgId; private long? lastUserMsgId; @@ -156,16 +156,16 @@ namespace osu.Game.Online.Chat private void fetchNewMessages() { - if (fetchMsgReq == null) + if (fetchMessageReq == null) fetchMessages( - () => fetchMsgReq = new GetMessagesRequest(JoinedChannels.Where(c => c.Target == TargetType.Channel), lastChannelMsgId), + () => fetchMessageReq = new GetMessagesRequest(JoinedChannels.Where(c => c.Target == TargetType.Channel), lastChannelMsgId), messages => { if (messages == null) return; handleChannelMessages(messages); lastChannelMsgId = messages.LastOrDefault()?.Id ?? lastChannelMsgId; - fetchMsgReq = null; + fetchMessageReq = null; } ); @@ -301,8 +301,8 @@ namespace osu.Game.Online.Chat fetchMessagesScheduleder = Scheduler.AddDelayed(fetchNewMessages, 1000, true); break; default: - fetchMsgReq?.Cancel(); - fetchMsgReq = null; + fetchMessageReq?.Cancel(); + fetchMessageReq = null; fetchMessagesScheduleder?.Cancel(); break; } From 16db81e9b56e796e00c1a8d41a14d0ac04eb73a3 Mon Sep 17 00:00:00 2001 From: miterosan Date: Tue, 24 Jul 2018 04:54:11 +0200 Subject: [PATCH 056/155] Extract the message hadling logic into IncomingMessagesHandler --- osu.Game/Online/Chat/ChannelManager.cs | 71 ++++++++++--------- .../Online/Chat/IncomingMessagesHandler.cs | 66 +++++++++++++++++ 2 files changed, 103 insertions(+), 34 deletions(-) create mode 100644 osu.Game/Online/Chat/IncomingMessagesHandler.cs diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 57f55492ad..9b76c31c80 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -47,13 +47,17 @@ namespace osu.Game.Online.Chat /// public ObservableCollection AvailableChannels { get; } = new ObservableCollection(); + private readonly IncomingMessagesHandler channelMessagesHandler; + private readonly IncomingMessagesHandler privateMessagesHandler; + private IAPIProvider api; private ScheduledDelegate fetchMessagesScheduleder; - private GetMessagesRequest fetchMessageReq; - private GetPrivateMessagesRequest fetchUserMsgReq; - private long? lastChannelMsgId; - private long? lastUserMsgId; + /// + /// Opens a channel or switches to the channel if already opened. + /// + /// If the name of the specifed channel was not found this exception will be thrown. + /// public void OpenChannel(string name) { if (name == null) @@ -63,7 +67,11 @@ namespace osu.Game.Online.Chat ?? throw new ChannelNotFoundException(name); } - public void OpenUserChannel(User user) + /// + /// Opens a new private channel. + /// + /// + public void OpenPrivateChannel(User user) { if (user == null) throw new ArgumentNullException(nameof(user)); @@ -75,6 +83,14 @@ namespace osu.Game.Online.Chat public ChannelManager() { CurrentChannel.ValueChanged += currentChannelChanged; + + channelMessagesHandler = new IncomingMessagesHandler(); + channelMessagesHandler.CreateMessagesRequest = () => new GetMessagesRequest(JoinedChannels.Where(c => c.Target == TargetType.Channel), channelMessagesHandler.LastMessageId); + channelMessagesHandler.OnNewMessages = handleChannelMessages; + + privateMessagesHandler = new IncomingMessagesHandler(); + privateMessagesHandler.CreateMessagesRequest = () => new GetPrivateMessagesRequest(privateMessagesHandler.LastMessageId); + privateMessagesHandler.OnNewMessages = handleUserMessages; } private void currentChannelChanged(Channel channel) @@ -156,32 +172,11 @@ namespace osu.Game.Online.Chat private void fetchNewMessages() { - if (fetchMessageReq == null) - fetchMessages( - () => fetchMessageReq = new GetMessagesRequest(JoinedChannels.Where(c => c.Target == TargetType.Channel), lastChannelMsgId), - messages => - { - if (messages == null) - return; - handleChannelMessages(messages); - lastChannelMsgId = messages.LastOrDefault()?.Id ?? lastChannelMsgId; - fetchMessageReq = null; - } - ); + if (channelMessagesHandler.CanRequestNewMessages) + channelMessagesHandler.RequestNewMessages(api); - - if (fetchUserMsgReq == null) - fetchMessages( - () => fetchUserMsgReq = new GetPrivateMessagesRequest(lastUserMsgId), - messages => - { - if (messages == null) - return; - handleUserMessages(messages); - lastUserMsgId = messages.Max(m => m.Id) ?? lastUserMsgId; - fetchUserMsgReq = null; - } - ); + if (privateMessagesHandler.CanRequestNewMessages) + privateMessagesHandler.RequestNewMessages(api); } private void fetchMessages(Func messagesRequest, Action> handler) @@ -272,7 +267,7 @@ namespace osu.Game.Online.Chat channels.Where(channel => AvailableChannels.All(c => c.Id != channel.Id)) .ForEach(channel => AvailableChannels.Add(channel)); - channels.Where(channel => defaultChannels.Contains(channel.Name)) + channels.Where(channel => defaultChannels.Any(c => c.Equals(channel.Name, StringComparison.OrdinalIgnoreCase))) .Where(channel => JoinedChannels.All(c => c.Id != channel.Id)) .ForEach(channel => { @@ -286,7 +281,12 @@ namespace osu.Game.Online.Chat fetchNewMessages(); }; - req.Failure += error => Logger.Error(error, "Fetching channel list failed"); + req.Failure += error => + { + Logger.Error(error, "Fetching channel list failed"); + + initializeDefaultChannels(); + }; api.Queue(req); } @@ -298,12 +298,15 @@ namespace osu.Game.Online.Chat case APIState.Online: if (JoinedChannels.Count == 0) initializeDefaultChannels(); + fetchMessagesScheduleder = Scheduler.AddDelayed(fetchNewMessages, 1000, true); break; default: - fetchMessageReq?.Cancel(); - fetchMessageReq = null; + channelMessagesHandler.CancelOngoingRequests(); + privateMessagesHandler.CancelOngoingRequests(); + fetchMessagesScheduleder?.Cancel(); + fetchMessagesScheduleder = null; break; } } diff --git a/osu.Game/Online/Chat/IncomingMessagesHandler.cs b/osu.Game/Online/Chat/IncomingMessagesHandler.cs new file mode 100644 index 0000000000..dc2e1cdf6b --- /dev/null +++ b/osu.Game/Online/Chat/IncomingMessagesHandler.cs @@ -0,0 +1,66 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using System.Linq; +using osu.Framework.Logging; +using osu.Game.Online.API; + +namespace osu.Game.Online.Chat +{ + public class IncomingMessagesHandler + { + public long? LastMessageId { get; private set; } + + private APIMessagesRequest getMessagesRequest; + + public Func CreateMessagesRequest { set; private get; } + + public Action> OnNewMessages { set; private get; } + + public bool CanRequestNewMessages => getMessagesRequest == null; + + public void RequestNewMessages(IAPIProvider api) + { + if (!CanRequestNewMessages) + throw new InvalidOperationException("Requesting new messages is not possible yet, because the old request is still ongoing."); + + if (OnNewMessages == null) + throw new InvalidOperationException($"You need to set an handler for the new incoming messages ({nameof(OnNewMessages)}) first before using {nameof(RequestNewMessages)}."); + + getMessagesRequest = CreateMessagesRequest.Invoke(); + + getMessagesRequest.Success += handleNewMessages; + getMessagesRequest.Failure += exception => + { + Logger.Error(exception, "Fetching messages failed."); + + //allowing new messages to be requested even after the fail. + getMessagesRequest = null; + }; + + api.Queue(getMessagesRequest); + } + + private void handleNewMessages(List messages) + { + + //allowing new messages to be requested. + getMessagesRequest = null; + + //in case of no new messages we simply do nothing. + if (messages == null || messages.Count == 0) + return; + + OnNewMessages.Invoke(messages); + + LastMessageId = messages.Max(m => m.Id) ?? LastMessageId; + } + + public void CancelOngoingRequests() + { + getMessagesRequest?.Cancel(); + } + } +} From 55f0cbf63e11e438b2041c0e4795d835b769dcee Mon Sep 17 00:00:00 2001 From: miterosan Date: Tue, 24 Jul 2018 04:56:34 +0200 Subject: [PATCH 057/155] Finding peace with the UI thread. There is the issue that in some cases that the ui thread blocked. --- osu.Game/Overlays/Chat/ChatTabControl.cs | 6 +++-- osu.Game/Overlays/Chat/DrawableChannel.cs | 8 ++---- .../Chat/Selection/ChannelSelectionOverlay.cs | 27 ++++++++++--------- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/osu.Game/Overlays/Chat/ChatTabControl.cs b/osu.Game/Overlays/Chat/ChatTabControl.cs index c668f78ff4..5c09e81726 100644 --- a/osu.Game/Overlays/Chat/ChatTabControl.cs +++ b/osu.Game/Overlays/Chat/ChatTabControl.cs @@ -48,8 +48,10 @@ namespace osu.Game.Overlays.Chat } public void AddItem(Channel channel) - { - ChannelTabControl.AddItem(channel); + { + if (!ChannelTabControl.Items.Contains(channel)) + ChannelTabControl.AddItem(channel); + if (Current.Value == null) Current.Value = channel; } diff --git a/osu.Game/Overlays/Chat/DrawableChannel.cs b/osu.Game/Overlays/Chat/DrawableChannel.cs index 8cc77f82f3..cfefff9067 100644 --- a/osu.Game/Overlays/Chat/DrawableChannel.cs +++ b/osu.Game/Overlays/Chat/DrawableChannel.cs @@ -55,15 +55,11 @@ namespace osu.Game.Overlays.Chat Channel.PendingMessageResolved += pendingMessageResolved; } - [BackgroundDependencyLoader] - private void load() - { - newMessagesArrived(Channel.Messages); - } - protected override void LoadComplete() { base.LoadComplete(); + + newMessagesArrived(Channel.Messages); scrollToEnd(); } diff --git a/osu.Game/Overlays/Chat/Selection/ChannelSelectionOverlay.cs b/osu.Game/Overlays/Chat/Selection/ChannelSelectionOverlay.cs index df4a8f5d24..e2d064474f 100644 --- a/osu.Game/Overlays/Chat/Selection/ChannelSelectionOverlay.cs +++ b/osu.Game/Overlays/Chat/Selection/ChannelSelectionOverlay.cs @@ -125,23 +125,26 @@ namespace osu.Game.Overlays.Chat.Selection public void UpdateAvailableChannels(IEnumerable channels) { - sectionsFlow.ChildrenEnumerable = new[] + Scheduler.Add(() => { - new ChannelSection + sectionsFlow.ChildrenEnumerable = new[] { - Header = "All Channels", - Channels = channels, - }, - }; + new ChannelSection + { + Header = "All Channels", + Channels = channels, + }, + }; - foreach (ChannelSection s in sectionsFlow.Children) - { - foreach (ChannelListItem c in s.ChannelFlow.Children) + foreach (ChannelSection s in sectionsFlow.Children) { - c.OnRequestJoin = channel => { OnRequestJoin?.Invoke(channel); }; - c.OnRequestLeave = channel => { OnRequestLeave?.Invoke(channel); }; + foreach (ChannelListItem c in s.ChannelFlow.Children) + { + c.OnRequestJoin = channel => { OnRequestJoin?.Invoke(channel); }; + c.OnRequestLeave = channel => { OnRequestLeave?.Invoke(channel); }; + } } - } + }); } [BackgroundDependencyLoader] From 3df1842e1c3b439ac469f2ecd985d89097a4ba75 Mon Sep 17 00:00:00 2001 From: miterosan Date: Tue, 24 Jul 2018 04:58:40 +0200 Subject: [PATCH 058/155] Fix that in some timing specific cases the fetched channels are not getting an visual representation. Sadly there is not a nice way of fixing this. --- osu.Game/Overlays/ChatOverlay.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index cee0a19868..4a286346d1 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -332,6 +332,10 @@ namespace osu.Game.Overlays channelManager.CurrentChannel.ValueChanged += currentChatChanged; channelManager.JoinedChannels.CollectionChanged += joinedChannelsChanged; channelManager.AvailableChannels.CollectionChanged += (sender, args) => channelSelection.UpdateAvailableChannels(channelManager.AvailableChannels); + + //for the case that channelmanager was faster at fetching the channels than our attachment to CollectionChanged. + channelSelection.UpdateAvailableChannels(channelManager.AvailableChannels); + joinedChannelsChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, channelManager.JoinedChannels)); } private void postMessage(TextBox textbox, bool newText) From e769c15d284e424a1dcdb55c366f0654567e5408 Mon Sep 17 00:00:00 2001 From: miterosan Date: Tue, 24 Jul 2018 05:14:33 +0200 Subject: [PATCH 059/155] Provide XML doc in Channel.cs and ChannelManager.cs and ChatTabControl.cs --- osu.Game/Online/Chat/Channel.cs | 36 ++++++++++++++++++++++++ osu.Game/Online/Chat/ChannelManager.cs | 10 +++++-- osu.Game/Overlays/Chat/ChatTabControl.cs | 10 +++++++ 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/Chat/Channel.cs b/osu.Game/Online/Chat/Channel.cs index cf702f2608..5f11739227 100644 --- a/osu.Game/Online/Chat/Channel.cs +++ b/osu.Game/Online/Chat/Channel.cs @@ -21,16 +21,44 @@ namespace osu.Game.Online.Chat /// public readonly ObservableCollection JoinedUsers = new ObservableCollection(); + /// + /// Contains all the messages send in the channel. + /// public readonly SortedList Messages = new SortedList(Comparer.Default); + + /// + /// Contains all the messages that are still pending for submission to the server. + /// private readonly List pendingMessages = new List(); + + /// + /// An event that fires when new messages arrived. + /// public event Action> NewMessagesArrived; + + /// + /// An event that fires when a pending message gets resolved. + /// public event Action PendingMessageResolved; + + /// + /// An event that fires when a pending message gets removed. + /// public event Action MessageRemoved; + /// + /// Signalles if the current user joined this channel or not. Defaults to false. + /// public readonly Bindable Joined = new Bindable(); + + /// + /// Signalles whether the channels target is a private channel or public channel. + /// public TargetType Target { get; protected set; } + public bool ReadOnly => false; //todo not yet used. + public override string ToString() => Name; [JsonProperty(@"name")] @@ -50,6 +78,10 @@ namespace osu.Game.Online.Chat { } + /// + /// Adds the argument message as a local echo. When this local echo is resolved will get called. + /// + /// public void AddLocalEcho(LocalEchoMessage message) { pendingMessages.Add(message); @@ -58,6 +90,10 @@ namespace osu.Game.Online.Chat NewMessagesArrived?.Invoke(new[] { message }); } + /// + /// Adds new messages to the channel and purges old messages. Triggers the event. + /// + /// public void AddNewMessages(params Message[] messages) { messages = messages.Except(Messages).ToArray(); diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 9b76c31c80..cf63ef4efe 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -70,7 +70,7 @@ namespace osu.Game.Online.Chat /// /// Opens a new private channel. /// - /// + /// The user the private channel is opened with. public void OpenPrivateChannel(User user) { if (user == null) @@ -139,6 +139,10 @@ namespace osu.Game.Online.Chat api.Queue(req); } + /// + /// Posts a command locally. Commands like /help will result in a help message written in the current channel. + /// + /// the text containing the command identifier and command parameters. public void PostCommand(string text) { if (CurrentChannel.Value == null) @@ -319,7 +323,9 @@ namespace osu.Game.Online.Chat } } - + /// + /// An exception thrown when a channel could not been found. + /// public class ChannelNotFoundException : Exception { public ChannelNotFoundException(string channelName) diff --git a/osu.Game/Overlays/Chat/ChatTabControl.cs b/osu.Game/Overlays/Chat/ChatTabControl.cs index 5c09e81726..8006635ce3 100644 --- a/osu.Game/Overlays/Chat/ChatTabControl.cs +++ b/osu.Game/Overlays/Chat/ChatTabControl.cs @@ -47,6 +47,11 @@ namespace osu.Game.Overlays.Chat ChannelTabControl.Current.Value = channel; } + /// + /// Adds a channel to the ChatTabControl. + /// The first channel added will automaticly selected. + /// + /// The channel that is going to be added. public void AddItem(Channel channel) { if (!ChannelTabControl.Items.Contains(channel)) @@ -56,6 +61,11 @@ namespace osu.Game.Overlays.Chat Current.Value = channel; } + /// + /// Removes a channel from the ChatTabControl. + /// If the selected channel is the one that is beeing removed, the next available channel will be selected. + /// + /// The channel that is going to be removed. public void RemoveItem(Channel channel) { ChannelTabControl.RemoveItem(channel); From 9bc225e14b7a6a079cf4bdb1bff3413e24ad09e5 Mon Sep 17 00:00:00 2001 From: miterosan Date: Tue, 24 Jul 2018 05:14:47 +0200 Subject: [PATCH 060/155] rename user to private --- osu.Game/Overlays/Chat/ChatLine.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Chat/ChatLine.cs b/osu.Game/Overlays/Chat/ChatLine.cs index f8fb9e01f3..770f528e17 100644 --- a/osu.Game/Overlays/Chat/ChatLine.cs +++ b/osu.Game/Overlays/Chat/ChatLine.cs @@ -248,7 +248,7 @@ namespace osu.Game.Overlays.Chat private void load(UserProfileOverlay profile, ChannelManager chatManager) { Action = () => profile?.ShowUser(sender); - startChatAction = () => chatManager?.OpenUserChannel(sender); + startChatAction = () => chatManager?.OpenPrivateChannel(sender); } public MenuItem[] ContextMenuItems => new MenuItem[] From 42df0c974fea494266574a975e3f4daf98677710 Mon Sep 17 00:00:00 2001 From: miterosan Date: Tue, 24 Jul 2018 05:17:57 +0200 Subject: [PATCH 061/155] Rename UserChannel to private channel. --- osu.Game/Online/Chat/ChannelManager.cs | 8 ++++---- osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs | 2 +- .../{UserChannelTabItem.cs => PrivateChannelTabItem.cs} | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) rename osu.Game/Overlays/Chat/Tabs/{UserChannelTabItem.cs => PrivateChannelTabItem.cs} (98%) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index cf63ef4efe..7a914cc627 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -200,17 +200,17 @@ namespace osu.Game.Online.Chat private void handleUserMessages(IEnumerable messages) { - var joinedUserChannels = JoinedChannels.Where(c => c.Target == TargetType.User).ToList(); + var joinedPrivateChannels = JoinedChannels.Where(c => c.Target == TargetType.User).ToList(); Channel getChannelForUser(User user) { - var channel = joinedUserChannels.FirstOrDefault(c => c.Id == user.Id); + var channel = joinedPrivateChannels.FirstOrDefault(c => c.Id == user.Id); if (channel == null) { channel = new PrivateChannel { User = user }; JoinedChannels.Add(channel); - joinedUserChannels.Add(channel); + joinedPrivateChannels.Add(channel); } return channel; @@ -237,7 +237,7 @@ namespace osu.Game.Online.Chat // Because of the way the API provides data right now, outgoing messages do not contain required // user (or in the future, target channel) metadata. As such we need to do a second request // to find out the specifics of the user. - var withoutReplyGroups = outgoingGroups.Where(g => joinedUserChannels.All(m => m.Id != g.Key)); + var withoutReplyGroups = outgoingGroups.Where(g => joinedPrivateChannels.All(m => m.Id != g.Key)); foreach (var withoutReplyGroup in withoutReplyGroups) { diff --git a/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs b/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs index e1f02e9c79..1eb5f1ac6e 100644 --- a/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs +++ b/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs @@ -58,7 +58,7 @@ namespace osu.Game.Overlays.Chat.Tabs case TargetType.Channel: return new ChannelTabItem(value) { OnRequestClose = tabCloseRequested }; case TargetType.User: - return new UserChannelTabItem(value) { OnRequestClose = tabCloseRequested }; + return new PrivateChannelTabItem(value) { OnRequestClose = tabCloseRequested }; default: throw new InvalidOperationException("Only TargetType User and Channel are supported."); } diff --git a/osu.Game/Overlays/Chat/Tabs/UserChannelTabItem.cs b/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs similarity index 98% rename from osu.Game/Overlays/Chat/Tabs/UserChannelTabItem.cs rename to osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs index 6b11c7860f..3b837d0a79 100644 --- a/osu.Game/Overlays/Chat/Tabs/UserChannelTabItem.cs +++ b/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs @@ -19,7 +19,7 @@ using OpenTK.Graphics; namespace osu.Game.Overlays.Chat.Tabs { - public class UserChannelTabItem : TabItem + public class PrivateChannelTabItem : TabItem { private static readonly Vector2 shear = new Vector2(1f / 5f, 0); public override bool IsRemovable => true; @@ -31,7 +31,7 @@ namespace osu.Game.Overlays.Chat.Tabs private readonly Avatar avatarContainer; private readonly TabCloseButton closeButton; - public UserChannelTabItem(Channel value) + public PrivateChannelTabItem(Channel value) : base(value) { if (value.Target != TargetType.User) @@ -163,7 +163,7 @@ namespace osu.Game.Overlays.Chat.Tabs closeButton.ScaleTo(new Vector2(0, 1)); } - public Action OnRequestClose; + public Action OnRequestClose; private readonly EdgeEffectParameters activateEdgeEffect = new EdgeEffectParameters { From 53f556de9afb0227e5fa24e2c627da89ae1cc310 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Jul 2018 15:10:55 +0200 Subject: [PATCH 062/155] Trim whitespace --- osu.Game/Graphics/Containers/LinkFlowContainer.cs | 3 ++- osu.Game/Overlays/Chat/ChatTabControl.cs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/Containers/LinkFlowContainer.cs b/osu.Game/Graphics/Containers/LinkFlowContainer.cs index d9be374ced..8d3c7d1caf 100644 --- a/osu.Game/Graphics/Containers/LinkFlowContainer.cs +++ b/osu.Game/Graphics/Containers/LinkFlowContainer.cs @@ -90,8 +90,9 @@ namespace osu.Game.Graphics.Containers } catch (ChannelNotFoundException e) { - Logger.Error(e, "It should not be possible that the user is able to click a invalid channel link."); + Logger.Error(e, "It should not be possible that the user is able to click a invalid channel link."); } + break; case LinkAction.OpenEditorTimestamp: case LinkAction.JoinMultiplayerMatch: diff --git a/osu.Game/Overlays/Chat/ChatTabControl.cs b/osu.Game/Overlays/Chat/ChatTabControl.cs index 8006635ce3..1df89b668f 100644 --- a/osu.Game/Overlays/Chat/ChatTabControl.cs +++ b/osu.Game/Overlays/Chat/ChatTabControl.cs @@ -53,7 +53,7 @@ namespace osu.Game.Overlays.Chat /// /// The channel that is going to be added. public void AddItem(Channel channel) - { + { if (!ChannelTabControl.Items.Contains(channel)) ChannelTabControl.AddItem(channel); From da730269a95960d6591b6b7f3b412f2cda55341a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Jul 2018 15:19:50 +0200 Subject: [PATCH 063/155] Formatting and ctor usage for required parameters --- osu.Game/Online/Chat/ChannelManager.cs | 10 +++---- .../Online/Chat/IncomingMessagesHandler.cs | 30 +++++++++++-------- osu.Game/Overlays/Chat/DrawableChannel.cs | 1 - 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 7a914cc627..2c73535668 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -84,13 +84,11 @@ namespace osu.Game.Online.Chat { CurrentChannel.ValueChanged += currentChannelChanged; - channelMessagesHandler = new IncomingMessagesHandler(); - channelMessagesHandler.CreateMessagesRequest = () => new GetMessagesRequest(JoinedChannels.Where(c => c.Target == TargetType.Channel), channelMessagesHandler.LastMessageId); - channelMessagesHandler.OnNewMessages = handleChannelMessages; + channelMessagesHandler = new IncomingMessagesHandler( + () => new GetMessagesRequest(JoinedChannels.Where(c => c.Target == TargetType.Channel), channelMessagesHandler.LastMessageId), handleChannelMessages); - privateMessagesHandler = new IncomingMessagesHandler(); - privateMessagesHandler.CreateMessagesRequest = () => new GetPrivateMessagesRequest(privateMessagesHandler.LastMessageId); - privateMessagesHandler.OnNewMessages = handleUserMessages; + privateMessagesHandler = new IncomingMessagesHandler( + () => new GetPrivateMessagesRequest(privateMessagesHandler.LastMessageId),handleUserMessages); } private void currentChannelChanged(Channel channel) diff --git a/osu.Game/Online/Chat/IncomingMessagesHandler.cs b/osu.Game/Online/Chat/IncomingMessagesHandler.cs index dc2e1cdf6b..eb70285f0b 100644 --- a/osu.Game/Online/Chat/IncomingMessagesHandler.cs +++ b/osu.Game/Online/Chat/IncomingMessagesHandler.cs @@ -4,39 +4,44 @@ using System; using System.Collections.Generic; using System.Linq; +using JetBrains.Annotations; using osu.Framework.Logging; using osu.Game.Online.API; namespace osu.Game.Online.Chat { + /// + /// Handles tracking and updating of a specific message type, allowing polling and requesting of only new messages on an ongoing basis. + /// public class IncomingMessagesHandler { public long? LastMessageId { get; private set; } private APIMessagesRequest getMessagesRequest; - public Func CreateMessagesRequest { set; private get; } - - public Action> OnNewMessages { set; private get; } + private readonly Func createRequest; + private readonly Action> onNewMessages; public bool CanRequestNewMessages => getMessagesRequest == null; + public IncomingMessagesHandler([NotNull] Func createRequest, [NotNull] Action> onNewMessages) + { + this.createRequest = createRequest ?? throw new ArgumentNullException(nameof(createRequest)); + this.onNewMessages = onNewMessages ?? throw new ArgumentNullException(nameof(onNewMessages)); + } + public void RequestNewMessages(IAPIProvider api) { if (!CanRequestNewMessages) throw new InvalidOperationException("Requesting new messages is not possible yet, because the old request is still ongoing."); - if (OnNewMessages == null) - throw new InvalidOperationException($"You need to set an handler for the new incoming messages ({nameof(OnNewMessages)}) first before using {nameof(RequestNewMessages)}."); - - getMessagesRequest = CreateMessagesRequest.Invoke(); - + getMessagesRequest = createRequest.Invoke(); getMessagesRequest.Success += handleNewMessages; getMessagesRequest.Failure += exception => { Logger.Error(exception, "Fetching messages failed."); - //allowing new messages to be requested even after the fail. + // allowing new messages to be requested even after the fail. getMessagesRequest = null; }; @@ -45,15 +50,14 @@ namespace osu.Game.Online.Chat private void handleNewMessages(List messages) { - - //allowing new messages to be requested. + // allowing new messages to be requested. getMessagesRequest = null; - //in case of no new messages we simply do nothing. + // in case of no new messages we simply do nothing. if (messages == null || messages.Count == 0) return; - OnNewMessages.Invoke(messages); + onNewMessages.Invoke(messages); LastMessageId = messages.Max(m => m.Id) ?? LastMessageId; } diff --git a/osu.Game/Overlays/Chat/DrawableChannel.cs b/osu.Game/Overlays/Chat/DrawableChannel.cs index cfefff9067..894fd84b93 100644 --- a/osu.Game/Overlays/Chat/DrawableChannel.cs +++ b/osu.Game/Overlays/Chat/DrawableChannel.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; using OpenTK.Graphics; -using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics.Containers; From 2d861f5897c3db2e26fbd447d6fc46cf541a0ea0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Jul 2018 15:26:02 +0200 Subject: [PATCH 064/155] Remove unnecessary inject --- osu.Game/OsuGameBase.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 93cbebbf26..6ba724524c 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -126,7 +126,6 @@ namespace osu.Game dependencies.CacheAs(api); var channelManager = new ChannelManager(); - dependencies.Inject(channelManager); dependencies.Cache(channelManager); AddInternal(channelManager); From 090d197b21e3e41319d2157a6e9555dfed8f484f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Jul 2018 17:35:08 +0200 Subject: [PATCH 065/155] Remove unnecessary using --- 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 2c73535668..ca28161909 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -7,7 +7,6 @@ using System.Collections.ObjectModel; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Configuration; -using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Logging; using osu.Framework.Threading; From 6937cf27a7084339c964835da0a46920cdfdfdd3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Jul 2018 17:51:20 +0200 Subject: [PATCH 066/155] Tidy up channel join logic --- osu.Game/Online/Chat/ChannelManager.cs | 32 ++++++++++++++++---------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index ca28161909..da6cc58e02 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -265,20 +265,28 @@ namespace osu.Game.Online.Chat req.Success += channels => { - channels.Where(channel => AvailableChannels.All(c => c.Id != channel.Id)) - .ForEach(channel => AvailableChannels.Add(channel)); + foreach (var channel in channels) + { + if (JoinedChannels.Any(c => c.Id == channel.Id)) + continue; - channels.Where(channel => defaultChannels.Any(c => c.Equals(channel.Name, StringComparison.OrdinalIgnoreCase))) - .Where(channel => JoinedChannels.All(c => c.Id != channel.Id)) - .ForEach(channel => - { - JoinedChannels.Add(channel); + // add as available if not already + if (AvailableChannels.All(c => c.Id != channel.Id)) + AvailableChannels.Add(channel); - var fetchInitialMsgReq = new GetMessagesRequest(new[] { channel }, null); - fetchInitialMsgReq.Success += handleChannelMessages; - fetchInitialMsgReq.Failure += exception => Logger.Error(exception, "Failed to fetch inital messages."); - api.Queue(fetchInitialMsgReq); - }); + // join any channels classified as "defaults" + if (defaultChannels.Any(c => c.Equals(channel.Name, StringComparison.OrdinalIgnoreCase))) + { + JoinedChannels.Add(channel); + + // TODO: remove this when the API supports returning initial fetch messages for more than one channel. + // right now it caps out at 50 messages and therefore only returns one channel's worth of content. + var fetchInitialMsgReq = new GetMessagesRequest(new[] { channel }, null); + fetchInitialMsgReq.Success += handleChannelMessages; + fetchInitialMsgReq.Failure += exception => Logger.Error(exception, "Failed to fetch inital messages."); + api.Queue(fetchInitialMsgReq); + } + } fetchNewMessages(); }; From 7b653fab1743c45270359477586a0e512dc9c1ef Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Jul 2018 18:01:28 +0200 Subject: [PATCH 067/155] Pass in lastMessageId instead of self referencing --- osu.Game/Online/Chat/ChannelManager.cs | 4 ++-- osu.Game/Online/Chat/IncomingMessagesHandler.cs | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index da6cc58e02..f34321f597 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -84,10 +84,10 @@ namespace osu.Game.Online.Chat CurrentChannel.ValueChanged += currentChannelChanged; channelMessagesHandler = new IncomingMessagesHandler( - () => new GetMessagesRequest(JoinedChannels.Where(c => c.Target == TargetType.Channel), channelMessagesHandler.LastMessageId), handleChannelMessages); + lastId => new GetMessagesRequest(JoinedChannels.Where(c => c.Target == TargetType.Channel), lastId), handleChannelMessages); privateMessagesHandler = new IncomingMessagesHandler( - () => new GetPrivateMessagesRequest(privateMessagesHandler.LastMessageId),handleUserMessages); + lastId => new GetPrivateMessagesRequest(lastId),handleUserMessages); } private void currentChannelChanged(Channel channel) diff --git a/osu.Game/Online/Chat/IncomingMessagesHandler.cs b/osu.Game/Online/Chat/IncomingMessagesHandler.cs index eb70285f0b..46f2b805b3 100644 --- a/osu.Game/Online/Chat/IncomingMessagesHandler.cs +++ b/osu.Game/Online/Chat/IncomingMessagesHandler.cs @@ -15,16 +15,18 @@ namespace osu.Game.Online.Chat /// public class IncomingMessagesHandler { + public delegate APIMessagesRequest CreateRequestDelegate(long? lastMessageId); + public long? LastMessageId { get; private set; } private APIMessagesRequest getMessagesRequest; - private readonly Func createRequest; + private readonly CreateRequestDelegate createRequest; private readonly Action> onNewMessages; public bool CanRequestNewMessages => getMessagesRequest == null; - public IncomingMessagesHandler([NotNull] Func createRequest, [NotNull] Action> onNewMessages) + public IncomingMessagesHandler([NotNull] CreateRequestDelegate createRequest, [NotNull] Action> onNewMessages) { this.createRequest = createRequest ?? throw new ArgumentNullException(nameof(createRequest)); this.onNewMessages = onNewMessages ?? throw new ArgumentNullException(nameof(onNewMessages)); @@ -35,7 +37,7 @@ namespace osu.Game.Online.Chat if (!CanRequestNewMessages) throw new InvalidOperationException("Requesting new messages is not possible yet, because the old request is still ongoing."); - getMessagesRequest = createRequest.Invoke(); + getMessagesRequest = createRequest.Invoke(LastMessageId); getMessagesRequest.Success += handleNewMessages; getMessagesRequest.Failure += exception => { From 95cb21299a30a89113bb482fb26f49ba8490a453 Mon Sep 17 00:00:00 2001 From: miterosan Date: Sun, 29 Jul 2018 21:18:37 +0200 Subject: [PATCH 068/155] Remove chatTabControl and transfer the logic into ChannelTabControl. --- ...ontrol.cs => TestCaseChannelTabControl.cs} | 22 +++--- osu.Game/Overlays/Chat/ChatTabControl.cs | 76 ------------------- .../Overlays/Chat/Tabs/ChannelTabControl.cs | 28 +++++++ osu.Game/Overlays/ChatOverlay.cs | 31 ++++---- 4 files changed, 56 insertions(+), 101 deletions(-) rename osu.Game.Tests/Visual/{TestCaseChatTabControl.cs => TestCaseChannelTabControl.cs} (79%) delete mode 100644 osu.Game/Overlays/Chat/ChatTabControl.cs diff --git a/osu.Game.Tests/Visual/TestCaseChatTabControl.cs b/osu.Game.Tests/Visual/TestCaseChannelTabControl.cs similarity index 79% rename from osu.Game.Tests/Visual/TestCaseChatTabControl.cs rename to osu.Game.Tests/Visual/TestCaseChannelTabControl.cs index c7d88a4d0e..35f4037ed2 100644 --- a/osu.Game.Tests/Visual/TestCaseChatTabControl.cs +++ b/osu.Game.Tests/Visual/TestCaseChannelTabControl.cs @@ -14,24 +14,22 @@ using osu.Framework.MathUtils; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.Chat; -using osu.Game.Overlays.Chat; using osu.Game.Overlays.Chat.Tabs; using osu.Game.Users; using OpenTK.Graphics; namespace osu.Game.Tests.Visual { - public class TestCaseChatTabControl : OsuTestCase + public class TestCaseChannelTabControl : OsuTestCase { public override IReadOnlyList RequiredTypes => new[] { - typeof(ChatTabControl), - typeof(ChannelTabControl) + typeof(ChannelTabControl), }; - private readonly ChatTabControl chatTabControl; + private readonly ChannelTabControl channelTabControl; - public TestCaseChatTabControl() + public TestCaseChannelTabControl() { SpriteText currentText; Add(new Container @@ -41,7 +39,7 @@ namespace osu.Game.Tests.Visual Anchor = Anchor.Centre, Children = new Drawable[] { - chatTabControl = new ChatTabControl + channelTabControl = new ChannelTabControl { RelativeSizeAxes = Axes.X, Origin = Anchor.Centre, @@ -68,13 +66,13 @@ namespace osu.Game.Tests.Visual { currentText = new SpriteText { - Text = "Currently selected chat: " + Text = "Currently selected channel:" } } }); - chatTabControl.OnRequestLeave += chat => chatTabControl.RemoveItem(chat); - chatTabControl.Current.ValueChanged += chat => currentText.Text = "Currently selected chat: " + chat.ToString(); + channelTabControl.OnRequestLeave += channel => channelTabControl.RemoveChannel(channel); + channelTabControl.Current.ValueChanged += channel => currentText.Text = "Currently selected channel: " + channel.ToString(); AddStep("Add random user", addRandomUser); AddRepeatStep("Add 3 random users", addRandomUser, 3); @@ -88,12 +86,12 @@ namespace osu.Game.Tests.Visual if (users == null || users.Count == 0) return; - chatTabControl.AddItem(new PrivateChannel { User = users[RNG.Next(0, users.Count - 1)] }); + channelTabControl.AddChannel(new PrivateChannel { User = users[RNG.Next(0, users.Count - 1)] }); } private void addChannel(string name) { - chatTabControl.AddItem(new Channel + channelTabControl.AddChannel(new Channel { Name = name }); diff --git a/osu.Game/Overlays/Chat/ChatTabControl.cs b/osu.Game/Overlays/Chat/ChatTabControl.cs deleted file mode 100644 index 1df89b668f..0000000000 --- a/osu.Game/Overlays/Chat/ChatTabControl.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System; -using System.Linq; -using osu.Framework.Configuration; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.UserInterface; -using osu.Game.Online.Chat; -using osu.Game.Overlays.Chat.Tabs; - -namespace osu.Game.Overlays.Chat -{ - public class ChatTabControl : Container, IHasCurrentValue - { - public readonly ChannelTabControl ChannelTabControl; - - public Bindable Current { get; } = new Bindable(); - public Action OnRequestLeave; - - public ChatTabControl() - { - Masking = false; - - Children = new Drawable[] - { - ChannelTabControl = new ChannelTabControl - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - RelativeSizeAxes = Axes.Both, - OnRequestLeave = channel => OnRequestLeave?.Invoke(channel) - }, - }; - - Current.ValueChanged += currentTabChanged; - ChannelTabControl.Current.ValueChanged += channel => - { - if (channel != null) - Current.Value = channel; - }; - } - - private void currentTabChanged(Channel channel) - { - ChannelTabControl.Current.Value = channel; - } - - /// - /// Adds a channel to the ChatTabControl. - /// The first channel added will automaticly selected. - /// - /// The channel that is going to be added. - public void AddItem(Channel channel) - { - if (!ChannelTabControl.Items.Contains(channel)) - ChannelTabControl.AddItem(channel); - - if (Current.Value == null) - Current.Value = channel; - } - - /// - /// Removes a channel from the ChatTabControl. - /// If the selected channel is the one that is beeing removed, the next available channel will be selected. - /// - /// The channel that is going to be removed. - public void RemoveItem(Channel channel) - { - ChannelTabControl.RemoveItem(channel); - if (Current.Value == channel) - Current.Value = ChannelTabControl.Items.FirstOrDefault(); - } - } -} diff --git a/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs b/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs index 1eb5f1ac6e..6470963b4f 100644 --- a/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs +++ b/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs @@ -9,6 +9,7 @@ using osu.Game.Online.Chat; using OpenTK; using osu.Framework.Configuration; using System; +using System.Linq; namespace osu.Game.Overlays.Chat.Tabs { @@ -64,6 +65,33 @@ namespace osu.Game.Overlays.Chat.Tabs } } + /// + /// Adds a channel to the ChannelTabControl. + /// The first channel added will automaticly selected. + /// + /// The channel that is going to be added. + public void AddChannel(Channel channel) + { + if (!Items.Contains(channel)) + AddItem(channel); + + if (Current.Value == null) + Current.Value = channel; + } + + /// + /// Removes a channel from the ChannelTabControl. + /// If the selected channel is the one that is beeing removed, the next available channel will be selected. + /// + /// The channel that is going to be removed. + public void RemoveChannel(Channel channel) + { + RemoveItem(channel); + + if (Current.Value == channel) + Current.Value = Items.FirstOrDefault(); + } + protected override void SelectTab(TabItem tab) { if (tab is ChannelSelectorTabItem) diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 4a286346d1..99f392a183 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -20,6 +20,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Online.Chat; using osu.Game.Overlays.Chat; using osu.Game.Overlays.Chat.Selection; +using osu.Game.Overlays.Chat.Tabs; namespace osu.Game.Overlays { @@ -43,7 +44,7 @@ namespace osu.Game.Overlays public const float TAB_AREA_HEIGHT = 50; - private readonly ChatTabControl chatTabControl; + private readonly ChannelTabControl channelTabControl; private readonly Container chatContainer; private readonly Container tabsArea; @@ -152,22 +153,24 @@ namespace osu.Game.Overlays RelativeSizeAxes = Axes.Both, Colour = Color4.Black, }, - chatTabControl = new ChatTabControl + channelTabControl = new ChannelTabControl { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, RelativeSizeAxes = Axes.Both, OnRequestLeave = channel => channelManager.JoinedChannels.Remove(channel) - } + }, } }, }, }, }; - chatTabControl.Current.ValueChanged += chat => channelManager.CurrentChannel.Value = chat; - chatTabControl.ChannelTabControl.ChannelSelectorActive.ValueChanged += value => channelSelection.State = value ? Visibility.Visible : Visibility.Hidden; + channelTabControl.Current.ValueChanged += chat => channelManager.CurrentChannel.Value = chat; + channelTabControl.ChannelSelectorActive.ValueChanged += value => channelSelection.State = value ? Visibility.Visible : Visibility.Hidden; channelSelection.StateChanged += state => { - chatTabControl.ChannelTabControl.ChannelSelectorActive.Value = state == Visibility.Visible; + channelTabControl.ChannelSelectorActive.Value = state == Visibility.Visible; if (state == Visibility.Visible) { @@ -193,14 +196,16 @@ namespace osu.Game.Overlays case NotifyCollectionChangedAction.Add: foreach (Channel newChannel in args.NewItems) { - chatTabControl.AddItem(newChannel); + channelTabControl.AddChannel(newChannel); + newChannel.Joined.Value = true; } break; case NotifyCollectionChangedAction.Remove: foreach (Channel removedChannel in args.OldItems) { - chatTabControl.RemoveItem(removedChannel); + channelTabControl.RemoveChannel(removedChannel); + loadedChannels.Remove(loadedChannels.Find(c => c.Channel == removedChannel )); removedChannel.Joined.Value = false; } @@ -208,20 +213,20 @@ namespace osu.Game.Overlays } } - private void currentChatChanged(Channel channel) + private void currentChannelChanged(Channel channel) { if (channel == null) { textbox.Current.Disabled = true; currentChannelContainer.Clear(false); - chatTabControl.Current.Value = null; + channelTabControl.Current.Value = null; return; } textbox.Current.Disabled = channel.ReadOnly; - if (chatTabControl.Current.Value != channel) - Scheduler.Add(() => chatTabControl.Current.Value = channel); + if (channelTabControl.Current.Value != channel) + Scheduler.Add(() => channelTabControl.Current.Value = channel); var loaded = loadedChannels.Find(d => d.Channel == channel); if (loaded == null) @@ -329,7 +334,7 @@ namespace osu.Game.Overlays loading.Show(); this.channelManager = channelManager; - channelManager.CurrentChannel.ValueChanged += currentChatChanged; + channelManager.CurrentChannel.ValueChanged += currentChannelChanged; channelManager.JoinedChannels.CollectionChanged += joinedChannelsChanged; channelManager.AvailableChannels.CollectionChanged += (sender, args) => channelSelection.UpdateAvailableChannels(channelManager.AvailableChannels); From 8c0bcb8e3c01e92b554e2251e85e4f3e76ff18d1 Mon Sep 17 00:00:00 2001 From: miterosan Date: Sun, 29 Jul 2018 21:40:43 +0200 Subject: [PATCH 069/155] Fix drawable crash and lload the inital messages of newly joined channels --- osu.Game/Online/Chat/ChannelManager.cs | 37 +++++++++++--------------- osu.Game/Overlays/ChatOverlay.cs | 5 +++- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index f34321f597..7d3d21554e 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -180,21 +180,6 @@ namespace osu.Game.Online.Chat privateMessagesHandler.RequestNewMessages(api); } - private void fetchMessages(Func messagesRequest, Action> handler) - { - if (messagesRequest == null) - throw new ArgumentNullException(nameof(messagesRequest)); - if (handler == null) - throw new ArgumentNullException(nameof(handler)); - - var messagesReq = messagesRequest.Invoke(); - - messagesReq.Success += handler.Invoke; - messagesReq.Failure += exception => Logger.Error(exception, "Fetching messages failed."); - - api.Queue(messagesReq); - } - private void handleUserMessages(IEnumerable messages) { var joinedPrivateChannels = JoinedChannels.Where(c => c.Target == TargetType.User).ToList(); @@ -279,12 +264,7 @@ namespace osu.Game.Online.Chat { JoinedChannels.Add(channel); - // TODO: remove this when the API supports returning initial fetch messages for more than one channel. - // right now it caps out at 50 messages and therefore only returns one channel's worth of content. - var fetchInitialMsgReq = new GetMessagesRequest(new[] { channel }, null); - fetchInitialMsgReq.Success += handleChannelMessages; - fetchInitialMsgReq.Failure += exception => Logger.Error(exception, "Failed to fetch inital messages."); - api.Queue(fetchInitialMsgReq); + FetchInitalMessages(channel); } } @@ -300,6 +280,21 @@ namespace osu.Game.Online.Chat api.Queue(req); } + /// + /// Fetches inital messages of a channel + /// + /// TODO: remove this when the API supports returning initial fetch messages for more than one channel by specifying the last message id per channel instead of one last message id globally. + /// right now it caps out at 50 messages and therefore only returns one channel's worth of content. + /// + /// The channel + public void FetchInitalMessages(Channel channel) + { + var fetchInitialMsgReq = new GetMessagesRequest(new[] { channel }, null); + fetchInitialMsgReq.Success += handleChannelMessages; + fetchInitialMsgReq.Failure += exception => Logger.Error(exception, $"Failed to fetch inital messages for the channel {channel.Name}"); + api.Queue(fetchInitialMsgReq); + } + public void APIStateChanged(APIAccess api, APIState state) { switch (state) diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 99f392a183..d3277fb0a9 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -184,7 +184,10 @@ namespace osu.Game.Overlays channelSelection.OnRequestJoin = channel => { if (!channelManager.JoinedChannels.Contains(channel)) + { channelManager.JoinedChannels.Add(channel); + channelManager.FetchInitalMessages(channel); + } }; channelSelection.OnRequestLeave = channel => channelManager.JoinedChannels.Remove(channel); } @@ -248,7 +251,7 @@ namespace osu.Game.Overlays else { currentChannelContainer.Clear(false); - currentChannelContainer.Add(loaded); + Scheduler.Add(() => currentChannelContainer.Add(loaded)); } } From 8bccecc2e58bf48889ba694ddee131ec203d170f Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 30 Jul 2018 00:13:32 +0200 Subject: [PATCH 070/155] Add some more testing. --- osu.Game.Tests/Visual/TestCaseChannelTabControl.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseChannelTabControl.cs b/osu.Game.Tests/Visual/TestCaseChannelTabControl.cs index 35f4037ed2..bdb32e95c9 100644 --- a/osu.Game.Tests/Visual/TestCaseChannelTabControl.cs +++ b/osu.Game.Tests/Visual/TestCaseChannelTabControl.cs @@ -74,9 +74,13 @@ namespace osu.Game.Tests.Visual channelTabControl.OnRequestLeave += channel => channelTabControl.RemoveChannel(channel); channelTabControl.Current.ValueChanged += channel => currentText.Text = "Currently selected channel: " + channel.ToString(); - AddStep("Add random user", addRandomUser); - AddRepeatStep("Add 3 random users", addRandomUser, 3); - AddStep("Add random channel", () => addChannel(RNG.Next().ToString())); + AddStep("Add random private channel", addRandomUser); + AddAssert("There is only one channels", () => channelTabControl.Items.Count() == 2); + AddRepeatStep("Add 3 random private channels", addRandomUser, 3); + AddAssert("There are four channels", () => channelTabControl.Items.Count() == 5); + AddStep("Add random public channel", () => addChannel(RNG.Next().ToString())); + + AddRepeatStep("Select a random channel", () => channelTabControl.Current.Value = channelTabControl.Items.ElementAt(RNG.Next(channelTabControl.Count + 1)), 20); } private List users; From 358c3469238e6abf73c43b2e76c3161a5aecdb86 Mon Sep 17 00:00:00 2001 From: miterosan Date: Sat, 4 Aug 2018 00:44:16 +0200 Subject: [PATCH 071/155] Use TabItem.Items.Count --- osu.Game.Tests/Visual/TestCaseChannelTabControl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/TestCaseChannelTabControl.cs b/osu.Game.Tests/Visual/TestCaseChannelTabControl.cs index bdb32e95c9..3347b2ad2e 100644 --- a/osu.Game.Tests/Visual/TestCaseChannelTabControl.cs +++ b/osu.Game.Tests/Visual/TestCaseChannelTabControl.cs @@ -80,7 +80,7 @@ namespace osu.Game.Tests.Visual AddAssert("There are four channels", () => channelTabControl.Items.Count() == 5); AddStep("Add random public channel", () => addChannel(RNG.Next().ToString())); - AddRepeatStep("Select a random channel", () => channelTabControl.Current.Value = channelTabControl.Items.ElementAt(RNG.Next(channelTabControl.Count + 1)), 20); + AddRepeatStep("Select a random channel", () => channelTabControl.Current.Value = channelTabControl.Items.ElementAt(RNG.Next(channelTabControl.Items.Count() + 1)), 20); } private List users; From b414bff86481a537197eaea26e2e06622fc4d0ff Mon Sep 17 00:00:00 2001 From: miterosan Date: Sat, 4 Aug 2018 01:00:46 +0200 Subject: [PATCH 072/155] Fix the testcase --- .../Visual/TestCaseChannelTabControl.cs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseChannelTabControl.cs b/osu.Game.Tests/Visual/TestCaseChannelTabControl.cs index 3347b2ad2e..1c1675a67c 100644 --- a/osu.Game.Tests/Visual/TestCaseChannelTabControl.cs +++ b/osu.Game.Tests/Visual/TestCaseChannelTabControl.cs @@ -80,17 +80,23 @@ namespace osu.Game.Tests.Visual AddAssert("There are four channels", () => channelTabControl.Items.Count() == 5); AddStep("Add random public channel", () => addChannel(RNG.Next().ToString())); - AddRepeatStep("Select a random channel", () => channelTabControl.Current.Value = channelTabControl.Items.ElementAt(RNG.Next(channelTabControl.Items.Count() + 1)), 20); + AddRepeatStep("Select a random channel", () => channelTabControl.Current.Value = channelTabControl.Items.ElementAt(RNG.Next(channelTabControl.Items.Count())), 20); } private List users; private void addRandomUser() { - if (users == null || users.Count == 0) - return; - - channelTabControl.AddChannel(new PrivateChannel { User = users[RNG.Next(0, users.Count - 1)] }); + channelTabControl.AddChannel(new PrivateChannel + { + User = users?.Count > 0 + ? users[RNG.Next(0, users.Count - 1)] + : new User + { + Id = RNG.Next(), + Username = "testuser" + RNG.Next(1000) + } + }); } private void addChannel(string name) From 119f81b86e560004ae106330172b3887768680b4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Sep 2018 15:56:04 +0900 Subject: [PATCH 073/155] Fix disposal issues in ChatOverlay testcase --- osu.Game/Overlays/ChatOverlay.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index d3277fb0a9..47262068d1 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -339,13 +339,26 @@ namespace osu.Game.Overlays this.channelManager = channelManager; channelManager.CurrentChannel.ValueChanged += currentChannelChanged; channelManager.JoinedChannels.CollectionChanged += joinedChannelsChanged; - channelManager.AvailableChannels.CollectionChanged += (sender, args) => channelSelection.UpdateAvailableChannels(channelManager.AvailableChannels); + channelManager.AvailableChannels.CollectionChanged += availableChannelsChanged; //for the case that channelmanager was faster at fetching the channels than our attachment to CollectionChanged. channelSelection.UpdateAvailableChannels(channelManager.AvailableChannels); joinedChannelsChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, channelManager.JoinedChannels)); } + private void availableChannelsChanged(object sender, NotifyCollectionChangedEventArgs e) + { + channelSelection.UpdateAvailableChannels(channelManager.AvailableChannels); + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + channelManager.CurrentChannel.ValueChanged -= currentChannelChanged; + channelManager.JoinedChannels.CollectionChanged -= joinedChannelsChanged; + channelManager.AvailableChannels.CollectionChanged -= availableChannelsChanged; + } + private void postMessage(TextBox textbox, bool newText) { var text = textbox.Text.Trim(); From 93e2d8f30984d1cdb880a5bb2fcd180cc4a8a35f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Sep 2018 15:56:27 +0900 Subject: [PATCH 074/155] Allow testing of all chat-related classes dynamically --- osu.Game.Tests/Visual/TestCaseChatDisplay.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/osu.Game.Tests/Visual/TestCaseChatDisplay.cs b/osu.Game.Tests/Visual/TestCaseChatDisplay.cs index c03b12bdc1..dc47055a87 100644 --- a/osu.Game.Tests/Visual/TestCaseChatDisplay.cs +++ b/osu.Game.Tests/Visual/TestCaseChatDisplay.cs @@ -1,15 +1,31 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; +using System.Collections.Generic; using System.ComponentModel; using osu.Framework.Graphics.Containers; using osu.Game.Overlays; +using osu.Game.Overlays.Chat; +using osu.Game.Overlays.Chat.Tabs; namespace osu.Game.Tests.Visual { [Description("Testing chat api and overlay")] public class TestCaseChatDisplay : OsuTestCase { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(ChatOverlay), + typeof(ChatLine), + typeof(DrawableChannel), + typeof(ChannelSelectorTabItem), + typeof(ChannelTabControl), + typeof(ChannelTabItem), + typeof(PrivateChannelTabItem), + typeof(TabCloseButton) + }; + public TestCaseChatDisplay() { Add(new ChatOverlay From 6a668ffe33389acf30ce304bfceb33928f478b97 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Sep 2018 16:21:31 +0900 Subject: [PATCH 075/155] Allow PrivateChannelTab to derive from ChannelTab --- osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs | 178 +++++++++------- .../Chat/Tabs/PrivateChannelTabItem.cs | 201 ++++-------------- 2 files changed, 138 insertions(+), 241 deletions(-) diff --git a/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs b/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs index 28a1f91df4..13913baefe 100644 --- a/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs +++ b/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs @@ -20,7 +20,6 @@ namespace osu.Game.Overlays.Chat.Tabs { public class ChannelTabItem : TabItem { - protected Color4 BackgroundInactive; private Color4 backgroundHover; protected Color4 BackgroundActive; @@ -29,81 +28,15 @@ namespace osu.Game.Overlays.Chat.Tabs protected readonly SpriteText Text; protected readonly SpriteText TextBold; - private readonly ClickableContainer closeButton; + protected readonly ClickableContainer CloseButton; private readonly Box box; private readonly Box highlightBox; protected readonly SpriteIcon Icon; public Action OnRequestClose; + private readonly Container content; - private void updateState() - { - if (Active) - fadeActive(); - else - fadeInactive(); - } - - private const float transition_length = 400; - - private void fadeActive() - { - this.ResizeTo(new Vector2(Width, 1.1f), transition_length, Easing.OutQuint); - - box.FadeColour(BackgroundActive, transition_length, Easing.OutQuint); - highlightBox.FadeIn(transition_length, Easing.OutQuint); - - Text.FadeOut(transition_length, Easing.OutQuint); - TextBold.FadeIn(transition_length, Easing.OutQuint); - } - - private void fadeInactive() - { - this.ResizeTo(new Vector2(Width, 1), transition_length, Easing.OutQuint); - - box.FadeColour(BackgroundInactive, transition_length, Easing.OutQuint); - highlightBox.FadeOut(transition_length, Easing.OutQuint); - - Text.FadeIn(transition_length, Easing.OutQuint); - TextBold.FadeOut(transition_length, Easing.OutQuint); - } - - protected override bool OnHover(InputState state) - { - if (IsRemovable) - closeButton.FadeIn(200, Easing.OutQuint); - - if (!Active) - box.FadeColour(backgroundHover, transition_length, Easing.OutQuint); - return true; - } - - protected override void OnHoverLost(InputState state) - { - closeButton.FadeOut(200, Easing.OutQuint); - updateState(); - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - BackgroundActive = colours.ChatBlue; - BackgroundInactive = colours.Gray4; - backgroundHover = colours.Gray7; - - highlightBox.Colour = colours.Yellow; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - updateState(); - } - - protected override void OnActivated() => updateState(); - - protected override void OnDeactivated() => updateState(); + protected override Container Content => content; public ChannelTabItem(Channel value) : base(value) @@ -118,14 +51,8 @@ namespace osu.Game.Overlays.Chat.Tabs Shear = new Vector2(ChannelTabControl.SHEAR_WIDTH / ChatOverlay.TAB_AREA_HEIGHT, 0); Masking = true; - EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Shadow, - Radius = 10, - Colour = Color4.Black.Opacity(0.2f), - }; - Children = new Drawable[] + InternalChildren = new Drawable[] { box = new Box { @@ -141,7 +68,7 @@ namespace osu.Game.Overlays.Chat.Tabs EdgeSmoothness = new Vector2(1, 0), RelativeSizeAxes = Axes.Y, }, - new Container + content = new Container { Shear = new Vector2(-ChannelTabControl.SHEAR_WIDTH / ChatOverlay.TAB_AREA_HEIGHT, 0), RelativeSizeAxes = Axes.Both, @@ -149,7 +76,7 @@ namespace osu.Game.Overlays.Chat.Tabs { Icon = new SpriteIcon { - Icon = FontAwesome.fa_hashtag, + Icon = DisplayIcon, Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, Colour = Color4.Black, @@ -175,7 +102,7 @@ namespace osu.Game.Overlays.Chat.Tabs Font = @"Exo2.0-Bold", TextSize = 18, }, - closeButton = new TabCloseButton + CloseButton = new TabCloseButton { Alpha = 0, Margin = new MarginPadding { Right = 20 }, @@ -190,5 +117,96 @@ namespace osu.Game.Overlays.Chat.Tabs }, }; } + + protected virtual FontAwesome DisplayIcon => FontAwesome.fa_hashtag; + + protected virtual bool ShowCloseOnHover => true; + + protected override bool OnHover(InputState state) + { + if (IsRemovable && ShowCloseOnHover) + CloseButton.FadeIn(200, Easing.OutQuint); + + if (!Active) + box.FadeColour(backgroundHover, TRANSITION_LENGTH, Easing.OutQuint); + return true; + } + + protected override void OnHoverLost(InputState state) + { + CloseButton.FadeOut(200, Easing.OutQuint); + updateState(); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + BackgroundActive = colours.ChatBlue; + BackgroundInactive = colours.Gray4; + backgroundHover = colours.Gray7; + + highlightBox.Colour = colours.Yellow; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + updateState(); + FinishTransforms(true); + } + + private void updateState() + { + if (Active) + FadeActive(); + else + FadeInactive(); + } + + protected const float TRANSITION_LENGTH = 400; + + private readonly EdgeEffectParameters activateEdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Radius = 15, + Colour = Color4.Black.Opacity(0.4f), + }; + + private readonly EdgeEffectParameters deactivateEdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Radius = 10, + Colour = Color4.Black.Opacity(0.2f), + }; + + protected virtual void FadeActive() + { + this.ResizeHeightTo(1.1f, TRANSITION_LENGTH, Easing.OutQuint); + + TweenEdgeEffectTo(activateEdgeEffect, TRANSITION_LENGTH); + + box.FadeColour(BackgroundActive, TRANSITION_LENGTH, Easing.OutQuint); + highlightBox.FadeIn(TRANSITION_LENGTH, Easing.OutQuint); + + Text.FadeOut(TRANSITION_LENGTH, Easing.OutQuint); + TextBold.FadeIn(TRANSITION_LENGTH, Easing.OutQuint); + } + + protected virtual void FadeInactive() + { + this.ResizeHeightTo(1, TRANSITION_LENGTH, Easing.OutQuint); + + TweenEdgeEffectTo(deactivateEdgeEffect, TRANSITION_LENGTH); + + box.FadeColour(BackgroundInactive, TRANSITION_LENGTH, Easing.OutQuint); + highlightBox.FadeOut(TRANSITION_LENGTH, Easing.OutQuint); + + Text.FadeIn(TRANSITION_LENGTH, Easing.OutQuint); + TextBold.FadeOut(TRANSITION_LENGTH, Easing.OutQuint); + } + + protected override void OnActivated() => updateState(); + protected override void OnDeactivated() => updateState(); } } diff --git a/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs b/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs index 3b837d0a79..14d43d4205 100644 --- a/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs +++ b/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs @@ -7,29 +7,20 @@ using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Online.Chat; -using osu.Game.Screens.Menu; using osu.Game.Users; using OpenTK; -using OpenTK.Graphics; namespace osu.Game.Overlays.Chat.Tabs { - public class PrivateChannelTabItem : TabItem + public class PrivateChannelTabItem : ChannelTabItem { - private static readonly Vector2 shear = new Vector2(1f / 5f, 0); - public override bool IsRemovable => true; - - private readonly Box highlightBox; - private readonly Container backgroundContainer; - private readonly Box backgroundBox; private readonly OsuSpriteText username; private readonly Avatar avatarContainer; - private readonly TabCloseButton closeButton; + + protected override FontAwesome DisplayIcon => FontAwesome.fa_at; public PrivateChannelTabItem(Channel value) : base(value) @@ -37,174 +28,61 @@ namespace osu.Game.Overlays.Chat.Tabs if (value.Target != TargetType.User) throw new ArgumentException("Argument value needs to have the targettype user!"); - AutoSizeAxes = Axes.X; - Height = 50; - Origin = Anchor.BottomLeft; - Anchor = Anchor.BottomLeft; - EdgeEffect = activateEdgeEffect; - Masking = true; - Shear = shear; - Children = new Drawable[] + AddRange(new Drawable[] { new Container { - RelativeSizeAxes = Axes.Both, + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + Margin = new MarginPadding + { + Horizontal = 3 + }, + Origin = Anchor.BottomLeft, + Anchor = Anchor.BottomLeft, Children = new Drawable[] { - backgroundBox = new Box + new CircularContainer { - RelativeSizeAxes = Axes.Both, - Origin = Anchor.BottomLeft, - Anchor = Anchor.BottomLeft, - EdgeSmoothness = new Vector2(1, 0), + Scale = new Vector2(0.95f), + Size = new Vector2(ChatOverlay.TAB_AREA_HEIGHT), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Masking = true, + Child = new DelayedLoadWrapper(new Avatar(value.JoinedUsers.First()) + { + RelativeSizeAxes = Axes.Both, + OnLoadComplete = d => d.FadeInFromZero(300, Easing.OutQuint), + }) + { + RelativeSizeAxes = Axes.Both, + } }, } }, - highlightBox = new Box - { - Width = 5, - BypassAutoSizeAxes = Axes.X, - Alpha = 0, - Anchor = Anchor.BottomRight, - Origin = Anchor.BottomRight, - EdgeSmoothness = new Vector2(1, 0), - RelativeSizeAxes = Axes.Y, - Colour = new OsuColour().Yellow - }, - new Container - { - Masking = true, - AutoSizeAxes = Axes.X, - RelativeSizeAxes = Axes.Y, - Child = new FlowContainerWithOrigin - { - AutoSizeAxes = Axes.X, - RelativeSizeAxes = Axes.Y, - X = -5, - Direction = FillDirection.Horizontal, - Origin = Anchor.TopLeft, - Anchor = Anchor.TopLeft, - Shear = -shear, - Children = new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.Y, - AutoSizeAxes = Axes.X, - Margin = new MarginPadding - { - Horizontal = 5 - }, - Origin = Anchor.BottomLeft, - Anchor = Anchor.BottomLeft, - Children = new Drawable[] - { - new SpriteIcon - { - Icon = FontAwesome.fa_at, - Origin = Anchor.Centre, - Scale = new Vector2(1.2f), - X = -5, - Y = 5, - Anchor = Anchor.Centre, - Colour = new OsuColour().BlueDarker, - RelativeSizeAxes = Axes.Both, - }, - new CircularContainer - { - RelativeSizeAxes = Axes.Y, - Scale = new Vector2(0.95f), - AutoSizeAxes = Axes.X, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Masking = true, - Child = new DelayedLoadWrapper(new Avatar(value.JoinedUsers.First()) - { - Size = new Vector2(ChatOverlay.TAB_AREA_HEIGHT), - OnLoadComplete = d => d.FadeInFromZero(300, Easing.OutQuint), - }) - { - Size = new Vector2(ChatOverlay.TAB_AREA_HEIGHT), - } - }, - } - }, - username = new OsuSpriteText - { - Origin = Anchor.CentreLeft, - Anchor = Anchor.CentreLeft, - Text = value.Name, - Margin = new MarginPadding(1), - TextSize = 18, - Alpha = 0, - }, - closeButton = new TabCloseButton - { - Height = 1, - Origin = Anchor.BottomLeft, - Anchor = Anchor.BottomLeft, - Alpha = 0, - Margin = new MarginPadding - { - Right = 5 - }, - RelativeSizeAxes = Axes.Y, - Action = delegate - { - if (IsRemovable) OnRequestClose?.Invoke(this); - }, - }, - } - } - } - }; + }); - username.ScaleTo(new Vector2(0, 1)); - closeButton.ScaleTo(new Vector2(0, 1)); + Text.X = ChatOverlay.TAB_AREA_HEIGHT; + TextBold.X = ChatOverlay.TAB_AREA_HEIGHT; } - public Action OnRequestClose; + protected override bool ShowCloseOnHover => false; - private readonly EdgeEffectParameters activateEdgeEffect = new EdgeEffectParameters + protected override void FadeActive() { - Type = EdgeEffectType.Shadow, - Radius = 15, - Colour = Color4.Black.Opacity(0.4f), - }; + base.FadeActive(); - protected override void OnActivated() - { - const int activate_length = 1000; - - backgroundBox.ResizeHeightTo(1.1f, activate_length, Easing.OutQuint); - highlightBox.ResizeHeightTo(1.1f, activate_length, Easing.OutQuint); - highlightBox.FadeIn(activate_length, Easing.OutQuint); - username.FadeIn(activate_length, Easing.OutQuint); - username.ScaleTo(new Vector2(1, 1), activate_length, Easing.OutQuint); - closeButton.ScaleTo(new Vector2(1, 1), activate_length, Easing.OutQuint); - closeButton.FadeIn(activate_length, Easing.OutQuint); - TweenEdgeEffectTo(activateEdgeEffect, activate_length); + this.ResizeWidthTo(200, TRANSITION_LENGTH * 2, Easing.OutQuint); + CloseButton.FadeIn(TRANSITION_LENGTH, Easing.OutQuint); } - private readonly EdgeEffectParameters deactivateEdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Shadow, - Radius = 10, - Colour = Color4.Black.Opacity(0.2f), - }; - protected override void OnDeactivated() + protected override void FadeInactive() { - const int deactivate_length = 500; + base.FadeInactive(); - backgroundBox.ResizeHeightTo(1, deactivate_length, Easing.OutQuint); - highlightBox.ResizeHeightTo(1, deactivate_length, Easing.OutQuint); - highlightBox.FadeOut(deactivate_length, Easing.OutQuint); - username.FadeOut(deactivate_length, Easing.OutQuint); - username.ScaleTo(new Vector2(0, 1), deactivate_length, Easing.OutQuint); - closeButton.FadeOut(deactivate_length, Easing.OutQuint); - closeButton.ScaleTo(new Vector2(0, 1), deactivate_length, Easing.OutQuint); - TweenEdgeEffectTo(deactivateEdgeEffect, deactivate_length); + this.ResizeWidthTo(ChatOverlay.TAB_AREA_HEIGHT + 10, TRANSITION_LENGTH, Easing.OutQuint); + CloseButton.FadeOut(TRANSITION_LENGTH, Easing.OutQuint); } [BackgroundDependencyLoader] @@ -212,7 +90,8 @@ namespace osu.Game.Overlays.Chat.Tabs { var user = Value.JoinedUsers.First(); - backgroundBox.Colour = user.Colour != null ? OsuColour.FromHex(user.Colour) : colours.BlueDark; + BackgroundActive = user.Colour != null ? OsuColour.FromHex(user.Colour) : colours.BlueDark; + BackgroundInactive = BackgroundActive.Darken(0.5f); } } } From 016e3957879af6012d0a82cea655ce0eed2f9ae8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Sep 2018 17:11:23 +0900 Subject: [PATCH 076/155] Fix disposal logic --- osu.Game/Overlays/ChatOverlay.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 47262068d1..912734ba0c 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -354,9 +354,13 @@ namespace osu.Game.Overlays protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); - channelManager.CurrentChannel.ValueChanged -= currentChannelChanged; - channelManager.JoinedChannels.CollectionChanged -= joinedChannelsChanged; - channelManager.AvailableChannels.CollectionChanged -= availableChannelsChanged; + + if (channelManager != null) + { + channelManager.CurrentChannel.ValueChanged -= currentChannelChanged; + channelManager.JoinedChannels.CollectionChanged -= joinedChannelsChanged; + channelManager.AvailableChannels.CollectionChanged -= availableChannelsChanged; + } } private void postMessage(TextBox textbox, bool newText) From 0cefd89ef78a3b5e558550f0f2f80a5432859bc8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Sep 2018 17:22:51 +0900 Subject: [PATCH 077/155] Change transition to match, looks better --- osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs b/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs index 14d43d4205..7492de0123 100644 --- a/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs +++ b/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs @@ -72,7 +72,7 @@ namespace osu.Game.Overlays.Chat.Tabs { base.FadeActive(); - this.ResizeWidthTo(200, TRANSITION_LENGTH * 2, Easing.OutQuint); + this.ResizeWidthTo(200, TRANSITION_LENGTH, Easing.OutQuint); CloseButton.FadeIn(TRANSITION_LENGTH, Easing.OutQuint); } From be1365fb187f5a11117c6ae7f170615827ce8572 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Sep 2018 11:58:23 +0900 Subject: [PATCH 078/155] Improve exception text --- osu.Game/Graphics/Containers/LinkFlowContainer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/Containers/LinkFlowContainer.cs b/osu.Game/Graphics/Containers/LinkFlowContainer.cs index 8d3c7d1caf..38d82e26ec 100644 --- a/osu.Game/Graphics/Containers/LinkFlowContainer.cs +++ b/osu.Game/Graphics/Containers/LinkFlowContainer.cs @@ -86,11 +86,11 @@ namespace osu.Game.Graphics.Containers case LinkAction.OpenChannel: try { - channelManager.OpenChannel(linkArgument); + channelManager?.OpenChannel(linkArgument); } catch (ChannelNotFoundException e) { - Logger.Error(e, "It should not be possible that the user is able to click a invalid channel link."); + Logger.Log($"The requested channel \"{linkArgument}\" does not exist"); } break; From 3c8c7a0459e4ce0181418222313027022b896d68 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Sep 2018 12:06:04 +0900 Subject: [PATCH 079/155] Move ChannelManager to OsuGame There's no reason for it to exist at OsuGameBase --- osu.Game.Tests/Visual/TestCaseChatDisplay.cs | 16 ++++++++++---- osu.Game/Online/Chat/ChannelManager.cs | 22 ++++++++++---------- osu.Game/OsuGame.cs | 6 ++++++ osu.Game/OsuGameBase.cs | 5 ----- 4 files changed, 29 insertions(+), 20 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseChatDisplay.cs b/osu.Game.Tests/Visual/TestCaseChatDisplay.cs index dc47055a87..e3bd4026b3 100644 --- a/osu.Game.Tests/Visual/TestCaseChatDisplay.cs +++ b/osu.Game.Tests/Visual/TestCaseChatDisplay.cs @@ -4,7 +4,10 @@ using System; using System.Collections.Generic; using System.ComponentModel; +using osu.Framework.Allocation; +using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Online.Chat; using osu.Game.Overlays; using osu.Game.Overlays.Chat; using osu.Game.Overlays.Chat.Tabs; @@ -26,12 +29,17 @@ namespace osu.Game.Tests.Visual typeof(TabCloseButton) }; - public TestCaseChatDisplay() + [Cached] + private readonly ChannelManager channelManager = new ChannelManager(); + + [BackgroundDependencyLoader] + private void load() { - Add(new ChatOverlay + Children = new Drawable[] { - State = Visibility.Visible - }); + channelManager, + new ChatOverlay { State = Visibility.Visible } + }; } } } diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 7d3d21554e..21e1739c59 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -52,6 +52,17 @@ namespace osu.Game.Online.Chat private IAPIProvider api; private ScheduledDelegate fetchMessagesScheduleder; + public ChannelManager() + { + CurrentChannel.ValueChanged += currentChannelChanged; + + channelMessagesHandler = new IncomingMessagesHandler( + lastId => new GetMessagesRequest(JoinedChannels.Where(c => c.Target == TargetType.Channel), lastId), handleChannelMessages); + + privateMessagesHandler = new IncomingMessagesHandler( + lastId => new GetPrivateMessagesRequest(lastId),handleUserMessages); + } + /// /// Opens a channel or switches to the channel if already opened. /// @@ -79,17 +90,6 @@ namespace osu.Game.Online.Chat ?? new PrivateChannel { User = user }; } - public ChannelManager() - { - CurrentChannel.ValueChanged += currentChannelChanged; - - channelMessagesHandler = new IncomingMessagesHandler( - lastId => new GetMessagesRequest(JoinedChannels.Where(c => c.Target == TargetType.Channel), lastId), handleChannelMessages); - - privateMessagesHandler = new IncomingMessagesHandler( - lastId => new GetPrivateMessagesRequest(lastId),handleUserMessages); - } - private void currentChannelChanged(Channel channel) { if (!JoinedChannels.Contains(channel)) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index e823041c42..f08ee42c40 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -31,6 +31,7 @@ using osu.Game.Overlays.Notifications; using osu.Game.Rulesets; using osu.Game.Screens.Play; using osu.Game.Input.Bindings; +using osu.Game.Online.Chat; using osu.Game.Rulesets.Mods; using osu.Game.Skinning; using OpenTK.Graphics; @@ -339,6 +340,11 @@ 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(settings = new MainSettings { diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 84462bd8c2..9a5dac35b9 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -27,7 +27,6 @@ using osu.Game.Database; using osu.Game.Input; using osu.Game.Input.Bindings; using osu.Game.IO; -using osu.Game.Online.Chat; using osu.Game.Rulesets; using osu.Game.Rulesets.Scoring; using osu.Game.Skinning; @@ -152,10 +151,6 @@ namespace osu.Game dependencies.Cache(api); dependencies.CacheAs(api); - var channelManager = new ChannelManager(); - dependencies.Cache(channelManager); - AddInternal(channelManager); - 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)); From 4c9dcdf156afc9ab1b45c05db1cbe949311a3b37 Mon Sep 17 00:00:00 2001 From: gotopie Date: Fri, 2 Nov 2018 19:04:30 -0400 Subject: [PATCH 080/155] hide seekbar when no song is playing --- osu.Game/Overlays/MusicController.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index b32fd265cb..77a3ae88a4 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -245,10 +245,10 @@ namespace osu.Game.Overlays { base.Update(); - if (current?.TrackLoaded ?? false) - { - var track = current.Track; + var track = (current?.TrackLoaded ?? false) ? current.Track : null; + if (track != null && !track.IsDummyDevice) + { progressBar.EndTime = track.Length; progressBar.CurrentTime = track.CurrentTime; @@ -258,7 +258,11 @@ namespace osu.Game.Overlays next(); } else + { + progressBar.CurrentTime = 0; + progressBar.EndTime = 1; playButton.Icon = FontAwesome.fa_play_circle_o; + } } private void play() From 779e57f0cab8a91c18e4c40c38acb70067ae2a47 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 6 Nov 2018 16:32:11 +0900 Subject: [PATCH 081/155] Change .idea ignore rules to not ignore run configurations --- .gitignore | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 8f011deabe..f95a04e517 100644 --- a/.gitignore +++ b/.gitignore @@ -252,7 +252,11 @@ paket-files/ .fake/ # JetBrains Rider -.idea/ +.idea/.idea.osu/.idea/*.xml +.idea/.idea.osu/.idea/codeStyles/*.xml +.idea/.idea.osu/.idea/dataSources/*.xml +.idea/.idea.osu/.idea/dictionaries/*.xml +.idea/.idea.osu/*.iml *.sln.iml # CodeRush From faab744cbdecd773f2d3255b0a9602426d0b0206 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 6 Nov 2018 17:24:38 +0900 Subject: [PATCH 082/155] DragLayer -> DragBox --- osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs | 2 +- .../Compose/Layers/{DragLayer.cs => DragBox.cs} | 11 +++++------ .../Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs | 8 ++++---- 3 files changed, 10 insertions(+), 11 deletions(-) rename osu.Game/Screens/Edit/Screens/Compose/Layers/{DragLayer.cs => DragBox.cs} (86%) diff --git a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs index 61647ffdc5..64218233d0 100644 --- a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs +++ b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs @@ -29,7 +29,7 @@ namespace osu.Game.Tests.Visual public override IReadOnlyList RequiredTypes => new[] { typeof(MaskSelection), - typeof(DragLayer), + typeof(DragBox), typeof(HitObjectComposer), typeof(OsuHitObjectComposer), typeof(HitObjectMaskLayer), diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/DragLayer.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/DragBox.cs similarity index 86% rename from osu.Game/Screens/Edit/Screens/Compose/Layers/DragLayer.cs rename to osu.Game/Screens/Edit/Screens/Compose/Layers/DragBox.cs index fdc0dee0ce..13a3bdc379 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/DragLayer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Layers/DragBox.cs @@ -8,15 +8,14 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; -using osu.Game.Rulesets.Edit; using OpenTK.Graphics; namespace osu.Game.Screens.Edit.Screens.Compose.Layers { /// - /// A layer that handles and displays drag selection for a collection of s. + /// A box that displays the drag selection and provides selection events for users to handle. /// - public class DragLayer : CompositeDrawable + public class DragBox : CompositeDrawable { private readonly Action performSelection; @@ -28,10 +27,10 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers private Drawable box; /// - /// Creates a new . + /// Creates a new . /// - /// The selectable s. - public DragLayer(Action performSelection) + /// A delegate that performs drag selection. + public DragBox(Action performSelection) { this.performSelection = performSelection; diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs index 0392cb5952..30c4ad7cb9 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs @@ -37,15 +37,15 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers maskSelection.DeselectAll = maskContainer.DeselectAll; - var dragLayer = new DragLayer(maskContainer.Select); - dragLayer.DragEnd += () => maskSelection.UpdateVisibility(); + var dragBox = new DragBox(maskContainer.Select); + dragBox.DragEnd += () => maskSelection.UpdateVisibility(); InternalChildren = new[] { - dragLayer, + dragBox, maskSelection, maskContainer, - dragLayer.CreateProxy() + dragBox.CreateProxy() }; foreach (var obj in composer.HitObjects) From 26c9390c167cae9b3187e058f0ea6829d9b45b4b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 6 Nov 2018 17:36:10 +0900 Subject: [PATCH 083/155] HitObjectMaskLayer -> BlueprintContainer --- osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs | 2 +- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 8 ++++---- .../{HitObjectMaskLayer.cs => BlueprintContainer.cs} | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) rename osu.Game/Screens/Edit/Screens/Compose/Layers/{HitObjectMaskLayer.cs => BlueprintContainer.cs} (96%) diff --git a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs index 64218233d0..aa657c9309 100644 --- a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs +++ b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs @@ -32,7 +32,7 @@ namespace osu.Game.Tests.Visual typeof(DragBox), typeof(HitObjectComposer), typeof(OsuHitObjectComposer), - typeof(HitObjectMaskLayer), + typeof(BlueprintContainer), typeof(NotNullAttribute), typeof(HitCirclePiece), typeof(HitCircleSelectionMask), diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 13571bda84..a84b6a30a7 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -35,7 +35,7 @@ namespace osu.Game.Rulesets.Edit private EditRulesetContainer rulesetContainer; - private HitObjectMaskLayer maskLayer; + private BlueprintContainer blueprintContainer; private PlacementContainer placementContainer; internal HitObjectComposer(Ruleset ruleset) @@ -67,7 +67,7 @@ namespace osu.Game.Rulesets.Edit var layerAboveRuleset = CreateLayerContainer(); layerAboveRuleset.Children = new Drawable[] { - maskLayer = new HitObjectMaskLayer(), + blueprintContainer = new BlueprintContainer(), placementContainer = new PlacementContainer(), }; @@ -148,11 +148,11 @@ namespace osu.Game.Rulesets.Edit /// The to add. public void Add(HitObject hitObject) { - maskLayer.AddMaskFor(rulesetContainer.Add(hitObject)); + blueprintContainer.AddMaskFor(rulesetContainer.Add(hitObject)); placementContainer.Refresh(); } - public void Remove(HitObject hitObject) => maskLayer.RemoveMaskFor(rulesetContainer.Remove(hitObject)); + public void Remove(HitObject hitObject) => blueprintContainer.RemoveMaskFor(rulesetContainer.Remove(hitObject)); internal abstract EditRulesetContainer CreateRulesetContainer(); diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/BlueprintContainer.cs similarity index 96% rename from osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs rename to osu.Game/Screens/Edit/Screens/Compose/Layers/BlueprintContainer.cs index 30c4ad7cb9..ec3e05dc3c 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Layers/BlueprintContainer.cs @@ -11,14 +11,14 @@ using osu.Game.Rulesets.Objects.Drawables; namespace osu.Game.Screens.Edit.Screens.Compose.Layers { - public class HitObjectMaskLayer : CompositeDrawable + public class BlueprintContainer : CompositeDrawable { private MaskContainer maskContainer; [Resolved] private HitObjectComposer composer { get; set; } - public HitObjectMaskLayer() + public BlueprintContainer() { RelativeSizeAxes = Axes.Both; } From 65bb91dcf797417eb071c5c19d45ec8931edcab2 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 6 Nov 2018 17:51:26 +0900 Subject: [PATCH 084/155] Merge MaskContainer into BlueprintContainer --- .../Compose/Layers/BlueprintContainer.cs | 102 +++++++++++--- .../Screens/Compose/Layers/MaskContainer.cs | 128 ------------------ 2 files changed, 85 insertions(+), 145 deletions(-) delete mode 100644 osu.Game/Screens/Edit/Screens/Compose/Layers/MaskContainer.cs diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/BlueprintContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/BlueprintContainer.cs index ec3e05dc3c..6392ffaca1 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Layers/BlueprintContainer.cs @@ -1,19 +1,26 @@ // 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 System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Primitives; using osu.Framework.Input.Events; +using osu.Framework.Input.States; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects.Drawables; +using OpenTK; namespace osu.Game.Screens.Edit.Screens.Compose.Layers { public class BlueprintContainer : CompositeDrawable { - private MaskContainer maskContainer; + private SelectionBlueprintContainer selectionBlueprints; + private MaskSelection maskSelection; + + private IEnumerable aliveMasks => selectionBlueprints.Children.Where(c => c.IsAlive); [Resolved] private HitObjectComposer composer { get; set; } @@ -26,25 +33,17 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers [BackgroundDependencyLoader] private void load() { - maskContainer = new MaskContainer(); + maskSelection = composer.CreateMaskSelection(); + maskSelection.DeselectAll = deselectAll; - var maskSelection = composer.CreateMaskSelection(); - - maskContainer.MaskSelected += maskSelection.HandleSelected; - maskContainer.MaskDeselected += maskSelection.HandleDeselected; - maskContainer.MaskSelectionRequested += maskSelection.HandleSelectionRequested; - maskContainer.MaskDragRequested += maskSelection.HandleDrag; - - maskSelection.DeselectAll = maskContainer.DeselectAll; - - var dragBox = new DragBox(maskContainer.Select); + var dragBox = new DragBox(select); dragBox.DragEnd += () => maskSelection.UpdateVisibility(); InternalChildren = new[] { dragBox, maskSelection, - maskContainer, + selectionBlueprints = new SelectionBlueprintContainer { RelativeSizeAxes = Axes.Both }, dragBox.CreateProxy() }; @@ -54,7 +53,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers protected override bool OnClick(ClickEvent e) { - maskContainer.DeselectAll(); + deselectAll(); return true; } @@ -68,7 +67,12 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers if (mask == null) return; - maskContainer.Add(mask); + mask.Selected += onMaskSelected; + mask.Deselected += onMaskDeselected; + mask.SelectionRequested += onSelectionRequested; + mask.DragRequested += onDragRequested; + + selectionBlueprints.Add(mask); } /// @@ -77,12 +81,76 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers /// The for which to remove the mask. public void RemoveMaskFor(DrawableHitObject hitObject) { - var maskToRemove = maskContainer.Single(m => m.HitObject == hitObject); + var maskToRemove = selectionBlueprints.Single(m => m.HitObject == hitObject); if (maskToRemove == null) return; maskToRemove.Deselect(); - maskContainer.Remove(maskToRemove); + + maskToRemove.Selected -= onMaskSelected; + maskToRemove.Deselected -= onMaskDeselected; + maskToRemove.SelectionRequested -= onSelectionRequested; + maskToRemove.DragRequested -= onDragRequested; + + selectionBlueprints.Remove(maskToRemove); + } + + /// + /// Select all masks in a given rectangle selection area. + /// + /// The rectangle to perform a selection on in screen-space coordinates. + private void select(RectangleF rect) + { + foreach (var mask in aliveMasks.ToList()) + { + if (mask.IsPresent && rect.Contains(mask.SelectionPoint)) + mask.Select(); + else + mask.Deselect(); + } + } + + /// + /// Deselects all selected s. + /// + private void deselectAll() => aliveMasks.ToList().ForEach(m => m.Deselect()); + + private void onMaskSelected(SelectionMask mask) + { + maskSelection.HandleSelected(mask); + selectionBlueprints.ChangeChildDepth(mask, 1); + } + + private void onMaskDeselected(SelectionMask mask) + { + maskSelection.HandleDeselected(mask); + selectionBlueprints.ChangeChildDepth(mask, 0); + } + + private void onSelectionRequested(SelectionMask mask, InputState state) => maskSelection.HandleSelectionRequested(mask, state); + + private void onDragRequested(SelectionMask mask, Vector2 delta, InputState state) => maskSelection.HandleDrag(mask, delta, state); + + private class SelectionBlueprintContainer : Container + { + protected override int Compare(Drawable x, Drawable y) + { + if (!(x is SelectionMask xMask) || !(y is SelectionMask yMask)) + return base.Compare(x, y); + return Compare(xMask, yMask); + } + + public int Compare(SelectionMask x, SelectionMask y) + { + // dpeth is used to denote selected status (we always want selected masks to handle input first). + int d = x.Depth.CompareTo(y.Depth); + if (d != 0) + return d; + + // Put earlier hitobjects towards the end of the list, so they handle input first + int i = y.HitObject.HitObject.StartTime.CompareTo(x.HitObject.HitObject.StartTime); + return i == 0 ? CompareReverseChildID(x, y) : i; + } } } } diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskContainer.cs deleted file mode 100644 index 42a7757721..0000000000 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskContainer.cs +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System; -using System.Collections.Generic; -using System.Linq; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Input.States; -using osu.Game.Rulesets.Edit; -using OpenTK; -using RectangleF = osu.Framework.Graphics.Primitives.RectangleF; - -namespace osu.Game.Screens.Edit.Screens.Compose.Layers -{ - public class MaskContainer : Container - { - /// - /// Invoked when any is selected. - /// - public event Action MaskSelected; - - /// - /// Invoked when any is deselected. - /// - public event Action MaskDeselected; - - /// - /// Invoked when any requests selection. - /// - public event Action MaskSelectionRequested; - - /// - /// Invoked when any requests drag. - /// - public event Action MaskDragRequested; - - private IEnumerable aliveMasks => AliveInternalChildren.Cast(); - - public MaskContainer() - { - RelativeSizeAxes = Axes.Both; - } - - public override void Add(SelectionMask drawable) - { - if (drawable == null) throw new ArgumentNullException(nameof(drawable)); - - base.Add(drawable); - - drawable.Selected += onMaskSelected; - drawable.Deselected += onMaskDeselected; - drawable.SelectionRequested += onSelectionRequested; - drawable.DragRequested += onDragRequested; - } - - public override bool Remove(SelectionMask drawable) - { - if (drawable == null) throw new ArgumentNullException(nameof(drawable)); - - var result = base.Remove(drawable); - - if (result) - { - drawable.Selected -= onMaskSelected; - drawable.Deselected -= onMaskDeselected; - drawable.SelectionRequested -= onSelectionRequested; - drawable.DragRequested -= onDragRequested; - } - - return result; - } - - /// - /// Select all masks in a given rectangle selection area. - /// - /// The rectangle to perform a selection on in screen-space coordinates. - public void Select(RectangleF rect) - { - foreach (var mask in aliveMasks.ToList()) - { - if (mask.IsPresent && rect.Contains(mask.SelectionPoint)) - mask.Select(); - else - mask.Deselect(); - } - } - - /// - /// Deselects all selected s. - /// - public void DeselectAll() => aliveMasks.ToList().ForEach(m => m.Deselect()); - - private void onMaskSelected(SelectionMask mask) - { - MaskSelected?.Invoke(mask); - ChangeChildDepth(mask, 1); - } - - private void onMaskDeselected(SelectionMask mask) - { - MaskDeselected?.Invoke(mask); - ChangeChildDepth(mask, 0); - } - - private void onSelectionRequested(SelectionMask mask, InputState state) => MaskSelectionRequested?.Invoke(mask, state); - private void onDragRequested(SelectionMask mask, Vector2 delta, InputState state) => MaskDragRequested?.Invoke(mask, delta, state); - - protected override int Compare(Drawable x, Drawable y) - { - if (!(x is SelectionMask xMask) || !(y is SelectionMask yMask)) - return base.Compare(x, y); - return Compare(xMask, yMask); - } - - public int Compare(SelectionMask x, SelectionMask y) - { - // dpeth is used to denote selected status (we always want selected masks to handle input first). - int d = x.Depth.CompareTo(y.Depth); - if (d != 0) - return d; - - // Put earlier hitobjects towards the end of the list, so they handle input first - int i = y.HitObject.HitObject.StartTime.CompareTo(x.HitObject.HitObject.StartTime); - return i == 0 ? CompareReverseChildID(x, y) : i; - } - } -} From ad2836a61e7fcbe5ea0dad92089b504d78b3bcf0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 6 Nov 2018 17:52:47 +0900 Subject: [PATCH 085/155] MaskSelection -> SelectionBox --- .../Visual/TestCaseHitObjectComposer.cs | 2 +- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 4 ++-- .../Compose/Layers/BlueprintContainer.cs | 18 +++++++++--------- .../Edit/Screens/Compose/Layers/DragBox.cs | 2 +- .../{MaskSelection.cs => SelectionBox.cs} | 6 +++--- 5 files changed, 16 insertions(+), 16 deletions(-) rename osu.Game/Screens/Edit/Screens/Compose/Layers/{MaskSelection.cs => SelectionBox.cs} (97%) diff --git a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs index aa657c9309..c51ede719a 100644 --- a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs +++ b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs @@ -28,7 +28,7 @@ namespace osu.Game.Tests.Visual { public override IReadOnlyList RequiredTypes => new[] { - typeof(MaskSelection), + typeof(SelectionBox), typeof(DragBox), typeof(HitObjectComposer), typeof(OsuHitObjectComposer), diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index a84b6a30a7..82c8e26706 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -165,10 +165,10 @@ namespace osu.Game.Rulesets.Edit public virtual SelectionMask CreateMaskFor(DrawableHitObject hitObject) => null; /// - /// Creates a which outlines s + /// Creates a which outlines s /// and handles hitobject pattern adjustments. /// - public virtual MaskSelection CreateMaskSelection() => new MaskSelection(); + public virtual SelectionBox CreateMaskSelection() => new SelectionBox(); /// /// Creates a which provides a layer above or below the . diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/BlueprintContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/BlueprintContainer.cs index 6392ffaca1..9a17dc8007 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Layers/BlueprintContainer.cs @@ -18,7 +18,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers public class BlueprintContainer : CompositeDrawable { private SelectionBlueprintContainer selectionBlueprints; - private MaskSelection maskSelection; + private SelectionBox selectionBox; private IEnumerable aliveMasks => selectionBlueprints.Children.Where(c => c.IsAlive); @@ -33,16 +33,16 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers [BackgroundDependencyLoader] private void load() { - maskSelection = composer.CreateMaskSelection(); - maskSelection.DeselectAll = deselectAll; + selectionBox = composer.CreateMaskSelection(); + selectionBox.DeselectAll = deselectAll; var dragBox = new DragBox(select); - dragBox.DragEnd += () => maskSelection.UpdateVisibility(); + dragBox.DragEnd += () => selectionBox.UpdateVisibility(); InternalChildren = new[] { dragBox, - maskSelection, + selectionBox, selectionBlueprints = new SelectionBlueprintContainer { RelativeSizeAxes = Axes.Both }, dragBox.CreateProxy() }; @@ -117,19 +117,19 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers private void onMaskSelected(SelectionMask mask) { - maskSelection.HandleSelected(mask); + selectionBox.HandleSelected(mask); selectionBlueprints.ChangeChildDepth(mask, 1); } private void onMaskDeselected(SelectionMask mask) { - maskSelection.HandleDeselected(mask); + selectionBox.HandleDeselected(mask); selectionBlueprints.ChangeChildDepth(mask, 0); } - private void onSelectionRequested(SelectionMask mask, InputState state) => maskSelection.HandleSelectionRequested(mask, state); + private void onSelectionRequested(SelectionMask mask, InputState state) => selectionBox.HandleSelectionRequested(mask, state); - private void onDragRequested(SelectionMask mask, Vector2 delta, InputState state) => maskSelection.HandleDrag(mask, delta, state); + private void onDragRequested(SelectionMask mask, Vector2 delta, InputState state) => selectionBox.HandleDrag(mask, delta, state); private class SelectionBlueprintContainer : Container { diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/DragBox.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/DragBox.cs index 13a3bdc379..a97ffc3fcc 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/DragBox.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Layers/DragBox.cs @@ -46,7 +46,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers { Masking = true, BorderColour = Color4.White, - BorderThickness = MaskSelection.BORDER_RADIUS, + BorderThickness = SelectionBox.BORDER_RADIUS, Child = new Box { RelativeSizeAxes = Axes.Both, diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskSelection.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/SelectionBox.cs similarity index 97% rename from osu.Game/Screens/Edit/Screens/Compose/Layers/MaskSelection.cs rename to osu.Game/Screens/Edit/Screens/Compose/Layers/SelectionBox.cs index 17b34bfb49..267892f45d 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskSelection.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Layers/SelectionBox.cs @@ -21,7 +21,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers /// /// A box which surrounds s and provides interactive handles, context menus etc. /// - public class MaskSelection : CompositeDrawable + public class SelectionBox : CompositeDrawable { public const float BORDER_RADIUS = 2; @@ -32,7 +32,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers [Resolved] private IPlacementHandler placementHandler { get; set; } - public MaskSelection() + public SelectionBox() { selectedMasks = new List(); @@ -147,7 +147,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers #endregion /// - /// Updates whether this is visible. + /// Updates whether this is visible. /// internal void UpdateVisibility() { From f2a5f28ea2562f8e3c08fb02c22a391cae439f5a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 6 Nov 2018 17:56:04 +0900 Subject: [PATCH 086/155] SelectionMask -> SelectionBlueprint --- .../Edit/ManiaHitObjectComposer.cs | 6 +-- ...nMask.cs => HoldNoteSelectionBlueprint.cs} | 12 ++--- ...ctionMask.cs => NoteSelectionBlueprint.cs} | 4 +- .../TestCaseHitCircleSelectionMask.cs | 2 +- .../TestCaseSliderSelectionMask.cs | 6 +-- .../TestCaseSpinnerSelectionMask.cs | 4 +- ...Mask.cs => HitCircleSelectionBlueprint.cs} | 4 +- ...k.cs => SliderCircleSelectionBlueprint.cs} | 4 +- ...ionMask.cs => SliderSelectionBlueprint.cs} | 12 ++--- ...onMask.cs => SpinnerSelectionBlueprint.cs} | 4 +- .../Edit/OsuHitObjectComposer.cs | 8 +-- .../Visual/TestCaseHitObjectComposer.cs | 2 +- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 10 ++-- ...SelectionMask.cs => SelectionBlueprint.cs} | 30 +++++------ .../Compose/Layers/BlueprintContainer.cs | 50 +++++++++---------- .../Screens/Compose/Layers/SelectionBox.cs | 32 ++++++------ .../Visual/HitObjectSelectionMaskTestCase.cs | 14 +++--- 17 files changed, 102 insertions(+), 102 deletions(-) rename osu.Game.Rulesets.Mania/Edit/Masks/{HoldNoteSelectionMask.cs => HoldNoteSelectionBlueprint.cs} (86%) rename osu.Game.Rulesets.Mania/Edit/Masks/{NoteSelectionMask.cs => NoteSelectionBlueprint.cs} (88%) rename osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/{HitCircleSelectionMask.cs => HitCircleSelectionBlueprint.cs} (79%) rename osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/{SliderCircleSelectionMask.cs => SliderCircleSelectionBlueprint.cs} (79%) rename osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/{SliderSelectionMask.cs => SliderSelectionBlueprint.cs} (59%) rename osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/{SpinnerSelectionMask.cs => SpinnerSelectionBlueprint.cs} (84%) rename osu.Game/Rulesets/Edit/{SelectionMask.cs => SelectionBlueprint.cs} (78%) diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs index fcacde769b..76969ab2bf 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs @@ -38,14 +38,14 @@ namespace osu.Game.Rulesets.Mania.Edit protected override IReadOnlyList CompositionTools => Array.Empty(); - public override SelectionMask CreateMaskFor(DrawableHitObject hitObject) + public override SelectionBlueprint CreateMaskFor(DrawableHitObject hitObject) { switch (hitObject) { case DrawableNote note: - return new NoteSelectionMask(note); + return new NoteSelectionBlueprint(note); case DrawableHoldNote holdNote: - return new HoldNoteSelectionMask(holdNote); + return new HoldNoteSelectionBlueprint(holdNote); } return base.CreateMaskFor(hitObject); diff --git a/osu.Game.Rulesets.Mania/Edit/Masks/HoldNoteSelectionMask.cs b/osu.Game.Rulesets.Mania/Edit/Masks/HoldNoteSelectionBlueprint.cs similarity index 86% rename from osu.Game.Rulesets.Mania/Edit/Masks/HoldNoteSelectionMask.cs rename to osu.Game.Rulesets.Mania/Edit/Masks/HoldNoteSelectionBlueprint.cs index a2c01d7a0e..14f045a549 100644 --- a/osu.Game.Rulesets.Mania/Edit/Masks/HoldNoteSelectionMask.cs +++ b/osu.Game.Rulesets.Mania/Edit/Masks/HoldNoteSelectionBlueprint.cs @@ -15,7 +15,7 @@ using OpenTK.Graphics; namespace osu.Game.Rulesets.Mania.Edit.Masks { - public class HoldNoteSelectionMask : SelectionMask + public class HoldNoteSelectionBlueprint : SelectionBlueprint { public new DrawableHoldNote HitObject => (DrawableHoldNote)base.HitObject; @@ -23,13 +23,13 @@ namespace osu.Game.Rulesets.Mania.Edit.Masks private readonly BodyPiece body; - public HoldNoteSelectionMask(DrawableHoldNote hold) + public HoldNoteSelectionBlueprint(DrawableHoldNote hold) : base(hold) { InternalChildren = new Drawable[] { - new HoldNoteNoteSelectionMask(hold.Head), - new HoldNoteNoteSelectionMask(hold.Tail), + new HoldNoteNoteSelectionBlueprint(hold.Head), + new HoldNoteNoteSelectionBlueprint(hold.Tail), body = new BodyPiece { AccentColour = Color4.Transparent @@ -59,9 +59,9 @@ namespace osu.Game.Rulesets.Mania.Edit.Masks Y -= HitObject.Tail.DrawHeight; } - private class HoldNoteNoteSelectionMask : NoteSelectionMask + private class HoldNoteNoteSelectionBlueprint : NoteSelectionBlueprint { - public HoldNoteNoteSelectionMask(DrawableNote note) + public HoldNoteNoteSelectionBlueprint(DrawableNote note) : base(note) { Select(); diff --git a/osu.Game.Rulesets.Mania/Edit/Masks/NoteSelectionMask.cs b/osu.Game.Rulesets.Mania/Edit/Masks/NoteSelectionBlueprint.cs similarity index 88% rename from osu.Game.Rulesets.Mania/Edit/Masks/NoteSelectionMask.cs rename to osu.Game.Rulesets.Mania/Edit/Masks/NoteSelectionBlueprint.cs index 18f042a483..4be0da12e1 100644 --- a/osu.Game.Rulesets.Mania/Edit/Masks/NoteSelectionMask.cs +++ b/osu.Game.Rulesets.Mania/Edit/Masks/NoteSelectionBlueprint.cs @@ -9,9 +9,9 @@ using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; namespace osu.Game.Rulesets.Mania.Edit.Masks { - public class NoteSelectionMask : SelectionMask + public class NoteSelectionBlueprint : SelectionBlueprint { - public NoteSelectionMask(DrawableNote note) + public NoteSelectionBlueprint(DrawableNote note) : base(note) { Scale = note.Scale; diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleSelectionMask.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleSelectionMask.cs index e3d61623bf..330315a953 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleSelectionMask.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleSelectionMask.cs @@ -24,6 +24,6 @@ namespace osu.Game.Rulesets.Osu.Tests Add(drawableObject = new DrawableHitCircle(hitCircle)); } - protected override SelectionMask CreateMask() => new HitCircleSelectionMask(drawableObject); + protected override SelectionBlueprint CreateMask() => new HitCircleSelectionBlueprint(drawableObject); } } diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionMask.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionMask.cs index 87e0e1a7ec..0641ff7582 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionMask.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionMask.cs @@ -20,8 +20,8 @@ namespace osu.Game.Rulesets.Osu.Tests { public override IReadOnlyList RequiredTypes => new[] { - typeof(SliderSelectionMask), - typeof(SliderCircleSelectionMask), + typeof(SliderSelectionBlueprint), + typeof(SliderCircleSelectionBlueprint), typeof(SliderBodyPiece), typeof(SliderCircle), typeof(PathControlPointVisualiser), @@ -50,6 +50,6 @@ namespace osu.Game.Rulesets.Osu.Tests Add(drawableObject = new DrawableSlider(slider)); } - protected override SelectionMask CreateMask() => new SliderSelectionMask(drawableObject); + protected override SelectionBlueprint CreateMask() => new SliderSelectionBlueprint(drawableObject); } } diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerSelectionMask.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerSelectionMask.cs index b436ff0e9f..9b0be3cc9c 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerSelectionMask.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerSelectionMask.cs @@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Osu.Tests { public override IReadOnlyList RequiredTypes => new[] { - typeof(SpinnerSelectionMask), + typeof(SpinnerSelectionBlueprint), typeof(SpinnerPiece) }; @@ -45,6 +45,6 @@ namespace osu.Game.Rulesets.Osu.Tests }); } - protected override SelectionMask CreateMask() => new SpinnerSelectionMask(drawableSpinner) { Size = new Vector2(0.5f) }; + protected override SelectionBlueprint CreateMask() => new SpinnerSelectionBlueprint(drawableSpinner) { Size = new Vector2(0.5f) }; } } diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCircleSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCircleSelectionBlueprint.cs similarity index 79% rename from osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCircleSelectionMask.cs rename to osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCircleSelectionBlueprint.cs index da46da92a5..14eb97327c 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCircleSelectionMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCircleSelectionBlueprint.cs @@ -8,9 +8,9 @@ using osu.Game.Rulesets.Osu.Objects.Drawables; namespace osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks { - public class HitCircleSelectionMask : SelectionMask + public class HitCircleSelectionBlueprint : SelectionBlueprint { - public HitCircleSelectionMask(DrawableHitCircle hitCircle) + public HitCircleSelectionBlueprint(DrawableHitCircle hitCircle) : base(hitCircle) { InternalChild = new HitCirclePiece((HitCircle)hitCircle.HitObject); diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderCircleSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderCircleSelectionBlueprint.cs similarity index 79% rename from osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderCircleSelectionMask.cs rename to osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderCircleSelectionBlueprint.cs index a1b3fd545c..ab37079d42 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderCircleSelectionMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderCircleSelectionBlueprint.cs @@ -8,9 +8,9 @@ using osu.Game.Rulesets.Osu.Objects.Drawables; namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks { - public class SliderCircleSelectionMask : SelectionMask + public class SliderCircleSelectionBlueprint : SelectionBlueprint { - public SliderCircleSelectionMask(DrawableOsuHitObject hitObject, Slider slider, SliderPosition position) + public SliderCircleSelectionBlueprint(DrawableOsuHitObject hitObject, Slider slider, SliderPosition position) : base(hitObject) { InternalChild = new SliderCirclePiece(slider, position); diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderSelectionBlueprint.cs similarity index 59% rename from osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderSelectionMask.cs rename to osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderSelectionBlueprint.cs index b79b0ba1fb..adb8591550 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderSelectionMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderSelectionBlueprint.cs @@ -10,11 +10,11 @@ using OpenTK; namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks { - public class SliderSelectionMask : SelectionMask + public class SliderSelectionBlueprint : SelectionBlueprint { - private readonly SliderCircleSelectionMask headMask; + private readonly SliderCircleSelectionBlueprint headBlueprint; - public SliderSelectionMask(DrawableSlider slider) + public SliderSelectionBlueprint(DrawableSlider slider) : base(slider) { var sliderObject = (Slider)slider.HitObject; @@ -22,12 +22,12 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks InternalChildren = new Drawable[] { new SliderBodyPiece(sliderObject), - headMask = new SliderCircleSelectionMask(slider.HeadCircle, sliderObject, SliderPosition.Start), - new SliderCircleSelectionMask(slider.TailCircle, sliderObject, SliderPosition.End), + headBlueprint = new SliderCircleSelectionBlueprint(slider.HeadCircle, sliderObject, SliderPosition.Start), + new SliderCircleSelectionBlueprint(slider.TailCircle, sliderObject, SliderPosition.End), new PathControlPointVisualiser(sliderObject), }; } - public override Vector2 SelectionPoint => headMask.SelectionPoint; + public override Vector2 SelectionPoint => headBlueprint.SelectionPoint; } } diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerSelectionBlueprint.cs similarity index 84% rename from osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerSelectionMask.cs rename to osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerSelectionBlueprint.cs index 0e47bd2a8b..b3c550b1c1 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerSelectionMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerSelectionBlueprint.cs @@ -9,11 +9,11 @@ using OpenTK; namespace osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks { - public class SpinnerSelectionMask : SelectionMask + public class SpinnerSelectionBlueprint : SelectionBlueprint { private readonly SpinnerPiece piece; - public SpinnerSelectionMask(DrawableSpinner spinner) + public SpinnerSelectionBlueprint(DrawableSpinner spinner) : base(spinner) { InternalChild = piece = new SpinnerPiece((Spinner)spinner.HitObject); diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index 005ccec151..1ed3578ab4 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -37,16 +37,16 @@ namespace osu.Game.Rulesets.Osu.Edit protected override Container CreateLayerContainer() => new PlayfieldAdjustmentContainer { RelativeSizeAxes = Axes.Both }; - public override SelectionMask CreateMaskFor(DrawableHitObject hitObject) + public override SelectionBlueprint CreateMaskFor(DrawableHitObject hitObject) { switch (hitObject) { case DrawableHitCircle circle: - return new HitCircleSelectionMask(circle); + return new HitCircleSelectionBlueprint(circle); case DrawableSlider slider: - return new SliderSelectionMask(slider); + return new SliderSelectionBlueprint(slider); case DrawableSpinner spinner: - return new SpinnerSelectionMask(spinner); + return new SpinnerSelectionBlueprint(spinner); } return base.CreateMaskFor(hitObject); diff --git a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs index c51ede719a..ff82034648 100644 --- a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs +++ b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs @@ -35,7 +35,7 @@ namespace osu.Game.Tests.Visual typeof(BlueprintContainer), typeof(NotNullAttribute), typeof(HitCirclePiece), - typeof(HitCircleSelectionMask), + typeof(HitCircleSelectionBlueprint), typeof(HitCirclePlacementMask), }; diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 82c8e26706..0608afdeca 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -148,27 +148,27 @@ namespace osu.Game.Rulesets.Edit /// The to add. public void Add(HitObject hitObject) { - blueprintContainer.AddMaskFor(rulesetContainer.Add(hitObject)); + blueprintContainer.AddBlueprintFor(rulesetContainer.Add(hitObject)); placementContainer.Refresh(); } - public void Remove(HitObject hitObject) => blueprintContainer.RemoveMaskFor(rulesetContainer.Remove(hitObject)); + public void Remove(HitObject hitObject) => blueprintContainer.RemoveBlueprintFor(rulesetContainer.Remove(hitObject)); internal abstract EditRulesetContainer CreateRulesetContainer(); protected abstract IReadOnlyList CompositionTools { get; } /// - /// Creates a for a specific . + /// Creates a for a specific . /// /// The to create the overlay for. - public virtual SelectionMask CreateMaskFor(DrawableHitObject hitObject) => null; + public virtual SelectionBlueprint CreateMaskFor(DrawableHitObject hitObject) => null; /// /// Creates a which outlines s /// and handles hitobject pattern adjustments. /// - public virtual SelectionBox CreateMaskSelection() => new SelectionBox(); + public virtual SelectionBox CreateSelectionBox() => new SelectionBox(); /// /// Creates a which provides a layer above or below the . diff --git a/osu.Game/Rulesets/Edit/SelectionMask.cs b/osu.Game/Rulesets/Edit/SelectionBlueprint.cs similarity index 78% rename from osu.Game/Rulesets/Edit/SelectionMask.cs rename to osu.Game/Rulesets/Edit/SelectionBlueprint.cs index 3b78d5aaf6..dc879b3a16 100644 --- a/osu.Game/Rulesets/Edit/SelectionMask.cs +++ b/osu.Game/Rulesets/Edit/SelectionBlueprint.cs @@ -17,31 +17,31 @@ namespace osu.Game.Rulesets.Edit /// /// A mask placed above a adding editing functionality. /// - public class SelectionMask : CompositeDrawable, IStateful + public class SelectionBlueprint : CompositeDrawable, IStateful { /// - /// Invoked when this has been selected. + /// Invoked when this has been selected. /// - public event Action Selected; + public event Action Selected; /// - /// Invoked when this has been deselected. + /// Invoked when this has been deselected. /// - public event Action Deselected; + public event Action Deselected; /// - /// Invoked when this has requested selection. + /// Invoked when this has requested selection. /// Will fire even if already selected. Does not actually perform selection. /// - public event Action SelectionRequested; + public event Action SelectionRequested; /// - /// Invoked when this has requested drag. + /// Invoked when this has requested drag. /// - public event Action DragRequested; + public event Action DragRequested; /// - /// The which this applies to. + /// The which this applies to. /// public readonly DrawableHitObject HitObject; @@ -49,7 +49,7 @@ namespace osu.Game.Rulesets.Edit public override bool HandlePositionalInput => ShouldBeAlive; public override bool RemoveWhenNotAlive => false; - public SelectionMask(DrawableHitObject hitObject) + public SelectionBlueprint(DrawableHitObject hitObject) { HitObject = hitObject; @@ -86,12 +86,12 @@ namespace osu.Game.Rulesets.Edit } /// - /// Selects this , causing it to become visible. + /// Selects this , causing it to become visible. /// public void Select() => State = SelectionState.Selected; /// - /// Deselects this , causing it to become invisible. + /// Deselects this , causing it to become invisible. /// public void Deselect() => State = SelectionState.NotSelected; @@ -135,12 +135,12 @@ namespace osu.Game.Rulesets.Edit } /// - /// The screen-space point that causes this to be selected. + /// The screen-space point that causes this to be selected. /// public virtual Vector2 SelectionPoint => HitObject.ScreenSpaceDrawQuad.Centre; /// - /// The screen-space quad that outlines this for selections. + /// The screen-space quad that outlines this for selections. /// public virtual Quad SelectionQuad => HitObject.ScreenSpaceDrawQuad; } diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/BlueprintContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/BlueprintContainer.cs index 9a17dc8007..3473e66c2b 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Layers/BlueprintContainer.cs @@ -20,7 +20,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers private SelectionBlueprintContainer selectionBlueprints; private SelectionBox selectionBox; - private IEnumerable aliveMasks => selectionBlueprints.Children.Where(c => c.IsAlive); + private IEnumerable selections => selectionBlueprints.Children.Where(c => c.IsAlive); [Resolved] private HitObjectComposer composer { get; set; } @@ -33,7 +33,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers [BackgroundDependencyLoader] private void load() { - selectionBox = composer.CreateMaskSelection(); + selectionBox = composer.CreateSelectionBox(); selectionBox.DeselectAll = deselectAll; var dragBox = new DragBox(select); @@ -48,7 +48,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers }; foreach (var obj in composer.HitObjects) - AddMaskFor(obj); + AddBlueprintFor(obj); } protected override bool OnClick(ClickEvent e) @@ -61,14 +61,14 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers /// Adds a mask for a which adds movement support. /// /// The to create a mask for. - public void AddMaskFor(DrawableHitObject hitObject) + public void AddBlueprintFor(DrawableHitObject hitObject) { var mask = composer.CreateMaskFor(hitObject); if (mask == null) return; - mask.Selected += onMaskSelected; - mask.Deselected += onMaskDeselected; + mask.Selected += onBlueprintSelected; + mask.Deselected += onBlueprintDeselected; mask.SelectionRequested += onSelectionRequested; mask.DragRequested += onDragRequested; @@ -79,7 +79,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers /// Removes a mask for a . /// /// The for which to remove the mask. - public void RemoveMaskFor(DrawableHitObject hitObject) + public void RemoveBlueprintFor(DrawableHitObject hitObject) { var maskToRemove = selectionBlueprints.Single(m => m.HitObject == hitObject); if (maskToRemove == null) @@ -87,8 +87,8 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers maskToRemove.Deselect(); - maskToRemove.Selected -= onMaskSelected; - maskToRemove.Deselected -= onMaskDeselected; + maskToRemove.Selected -= onBlueprintSelected; + maskToRemove.Deselected -= onBlueprintDeselected; maskToRemove.SelectionRequested -= onSelectionRequested; maskToRemove.DragRequested -= onDragRequested; @@ -101,7 +101,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers /// The rectangle to perform a selection on in screen-space coordinates. private void select(RectangleF rect) { - foreach (var mask in aliveMasks.ToList()) + foreach (var mask in selections.ToList()) { if (mask.IsPresent && rect.Contains(mask.SelectionPoint)) mask.Select(); @@ -111,38 +111,38 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers } /// - /// Deselects all selected s. + /// Deselects all selected s. /// - private void deselectAll() => aliveMasks.ToList().ForEach(m => m.Deselect()); + private void deselectAll() => selections.ToList().ForEach(m => m.Deselect()); - private void onMaskSelected(SelectionMask mask) + private void onBlueprintSelected(SelectionBlueprint blueprint) { - selectionBox.HandleSelected(mask); - selectionBlueprints.ChangeChildDepth(mask, 1); + selectionBox.HandleSelected(blueprint); + selectionBlueprints.ChangeChildDepth(blueprint, 1); } - private void onMaskDeselected(SelectionMask mask) + private void onBlueprintDeselected(SelectionBlueprint blueprint) { - selectionBox.HandleDeselected(mask); - selectionBlueprints.ChangeChildDepth(mask, 0); + selectionBox.HandleDeselected(blueprint); + selectionBlueprints.ChangeChildDepth(blueprint, 0); } - private void onSelectionRequested(SelectionMask mask, InputState state) => selectionBox.HandleSelectionRequested(mask, state); + private void onSelectionRequested(SelectionBlueprint blueprint, InputState state) => selectionBox.HandleSelectionRequested(blueprint, state); - private void onDragRequested(SelectionMask mask, Vector2 delta, InputState state) => selectionBox.HandleDrag(mask, delta, state); + private void onDragRequested(SelectionBlueprint blueprint, Vector2 delta, InputState state) => selectionBox.HandleDrag(blueprint, delta, state); - private class SelectionBlueprintContainer : Container + private class SelectionBlueprintContainer : Container { protected override int Compare(Drawable x, Drawable y) { - if (!(x is SelectionMask xMask) || !(y is SelectionMask yMask)) + if (!(x is SelectionBlueprint xBlueprint) || !(y is SelectionBlueprint yBlueprint)) return base.Compare(x, y); - return Compare(xMask, yMask); + return Compare(xBlueprint, yBlueprint); } - public int Compare(SelectionMask x, SelectionMask y) + public int Compare(SelectionBlueprint x, SelectionBlueprint y) { - // dpeth is used to denote selected status (we always want selected masks to handle input first). + // dpeth is used to denote selected status (we always want selected blueprints to handle input first). int d = x.Depth.CompareTo(y.Depth); if (d != 0) return d; diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/SelectionBox.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/SelectionBox.cs index 267892f45d..6aef47d690 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/SelectionBox.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Layers/SelectionBox.cs @@ -19,13 +19,13 @@ using OpenTK.Input; namespace osu.Game.Screens.Edit.Screens.Compose.Layers { /// - /// A box which surrounds s and provides interactive handles, context menus etc. + /// A box which surrounds s and provides interactive handles, context menus etc. /// public class SelectionBox : CompositeDrawable { public const float BORDER_RADIUS = 2; - private readonly List selectedMasks; + private readonly List selectedMasks; private Drawable outline; @@ -34,7 +34,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers public SelectionBox() { - selectedMasks = new List(); + selectedMasks = new List(); RelativeSizeAxes = Axes.Both; AlwaysPresent = true; @@ -60,7 +60,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers #region User Input Handling - public void HandleDrag(SelectionMask m, Vector2 delta, InputState state) + public void HandleDrag(SelectionBlueprint m, Vector2 delta, InputState state) { // Todo: Various forms of snapping @@ -103,16 +103,16 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers /// /// Handle a mask becoming selected. /// - /// The mask. - public void HandleSelected(SelectionMask mask) => selectedMasks.Add(mask); + /// The mask. + public void HandleSelected(SelectionBlueprint blueprint) => selectedMasks.Add(blueprint); /// /// Handle a mask becoming deselected. /// - /// The mask. - public void HandleDeselected(SelectionMask mask) + /// The mask. + public void HandleDeselected(SelectionBlueprint blueprint) { - selectedMasks.Remove(mask); + selectedMasks.Remove(blueprint); // We don't want to update visibility if > 0, since we may be deselecting masks during drag-selection if (selectedMasks.Count == 0) @@ -122,23 +122,23 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers /// /// Handle a mask requesting selection. /// - /// The mask. - public void HandleSelectionRequested(SelectionMask mask, InputState state) + /// The mask. + public void HandleSelectionRequested(SelectionBlueprint blueprint, InputState state) { if (state.Keyboard.ControlPressed) { - if (mask.IsSelected) - mask.Deselect(); + if (blueprint.IsSelected) + blueprint.Deselect(); else - mask.Select(); + blueprint.Select(); } else { - if (mask.IsSelected) + if (blueprint.IsSelected) return; DeselectAll?.Invoke(); - mask.Select(); + blueprint.Select(); } UpdateVisibility(); diff --git a/osu.Game/Tests/Visual/HitObjectSelectionMaskTestCase.cs b/osu.Game/Tests/Visual/HitObjectSelectionMaskTestCase.cs index 3ba6841280..707ebaa96b 100644 --- a/osu.Game/Tests/Visual/HitObjectSelectionMaskTestCase.cs +++ b/osu.Game/Tests/Visual/HitObjectSelectionMaskTestCase.cs @@ -12,7 +12,7 @@ namespace osu.Game.Tests.Visual { public abstract class HitObjectSelectionMaskTestCase : OsuTestCase { - private SelectionMask mask; + private SelectionBlueprint blueprint; protected override Container Content => content ?? base.Content; private readonly Container content; @@ -29,19 +29,19 @@ namespace osu.Game.Tests.Visual [BackgroundDependencyLoader] private void load() { - base.Content.Add(mask = CreateMask()); - mask.SelectionRequested += (_, __) => mask.Select(); + base.Content.Add(blueprint = CreateMask()); + blueprint.SelectionRequested += (_, __) => blueprint.Select(); - AddStep("Select", () => mask.Select()); - AddStep("Deselect", () => mask.Deselect()); + AddStep("Select", () => blueprint.Select()); + AddStep("Deselect", () => blueprint.Deselect()); } protected override bool OnClick(ClickEvent e) { - mask.Deselect(); + blueprint.Deselect(); return true; } - protected abstract SelectionMask CreateMask(); + protected abstract SelectionBlueprint CreateMask(); } } From 90c813618a84851627c432a0f62a6c208edcb712 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 6 Nov 2018 18:02:55 +0900 Subject: [PATCH 087/155] Merge PlacementContainer into BlueprintContainer --- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 17 +-- .../Compose/Layers/BlueprintContainer.cs | 106 ++++++++++++------ .../Compose/Layers/PlacementContainer.cs | 50 --------- 3 files changed, 75 insertions(+), 98 deletions(-) delete mode 100644 osu.Game/Screens/Edit/Screens/Compose/Layers/PlacementContainer.cs diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 0608afdeca..7072e31e16 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -36,7 +36,6 @@ namespace osu.Game.Rulesets.Edit private EditRulesetContainer rulesetContainer; private BlueprintContainer blueprintContainer; - private PlacementContainer placementContainer; internal HitObjectComposer(Ruleset ruleset) { @@ -65,11 +64,7 @@ namespace osu.Game.Rulesets.Edit layerBelowRuleset.Child = new BorderLayer { RelativeSizeAxes = Axes.Both }; var layerAboveRuleset = CreateLayerContainer(); - layerAboveRuleset.Children = new Drawable[] - { - blueprintContainer = new BlueprintContainer(), - placementContainer = new PlacementContainer(), - }; + layerAboveRuleset.Child = new BlueprintContainer(); layerContainers.Add(layerBelowRuleset); layerContainers.Add(layerAboveRuleset); @@ -112,8 +107,8 @@ namespace osu.Game.Rulesets.Edit }; toolboxCollection.Items = - CompositionTools.Select(t => new RadioButton(t.Name, () => placementContainer.CurrentTool = t)) - .Prepend(new RadioButton("Select", () => placementContainer.CurrentTool = null)) + CompositionTools.Select(t => new RadioButton(t.Name, () => blueprintContainer.CurrentTool = t)) + .Prepend(new RadioButton("Select", () => blueprintContainer.CurrentTool = null)) .ToList(); toolboxCollection.Items[0].Select(); @@ -146,11 +141,7 @@ namespace osu.Game.Rulesets.Edit /// Adds a to the and visualises it. /// /// The to add. - public void Add(HitObject hitObject) - { - blueprintContainer.AddBlueprintFor(rulesetContainer.Add(hitObject)); - placementContainer.Refresh(); - } + public void Add(HitObject hitObject) => blueprintContainer.AddBlueprintFor(rulesetContainer.Add(hitObject)); public void Remove(HitObject hitObject) => blueprintContainer.RemoveBlueprintFor(rulesetContainer.Remove(hitObject)); diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/BlueprintContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/BlueprintContainer.cs index 3473e66c2b..5c7d840f3d 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Layers/BlueprintContainer.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics.Primitives; using osu.Framework.Input.Events; using osu.Framework.Input.States; using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Edit.Tools; using osu.Game.Rulesets.Objects.Drawables; using OpenTK; @@ -18,6 +19,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers public class BlueprintContainer : CompositeDrawable { private SelectionBlueprintContainer selectionBlueprints; + private Container placementBlueprintContainer; private SelectionBox selectionBox; private IEnumerable selections => selectionBlueprints.Children.Where(c => c.IsAlive); @@ -44,6 +46,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers dragBox, selectionBox, selectionBlueprints = new SelectionBlueprintContainer { RelativeSizeAxes = Axes.Both }, + placementBlueprintContainer = new Container { RelativeSizeAxes = Axes.Both }, dragBox.CreateProxy() }; @@ -51,6 +54,64 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers AddBlueprintFor(obj); } + private HitObjectCompositionTool currentTool; + + /// + /// The current placement tool. + /// + public HitObjectCompositionTool CurrentTool + { + get => currentTool; + set + { + if (currentTool == value) + return; + currentTool = value; + + refreshTool(); + } + } + + /// + /// Adds a blueprint for a which adds movement support. + /// + /// The to create a blueprint for. + public void AddBlueprintFor(DrawableHitObject hitObject) + { + refreshTool(); + + var blueprint = composer.CreateMaskFor(hitObject); + if (blueprint == null) + return; + + blueprint.Selected += onBlueprintSelected; + blueprint.Deselected += onBlueprintDeselected; + blueprint.SelectionRequested += onSelectionRequested; + blueprint.DragRequested += onDragRequested; + + selectionBlueprints.Add(blueprint); + } + + /// + /// Removes a blueprint for a . + /// + /// The for which to remove the blueprint. + public void RemoveBlueprintFor(DrawableHitObject hitObject) + { + var blueprint = selectionBlueprints.Single(m => m.HitObject == hitObject); + if (blueprint == null) + return; + + blueprint.Deselect(); + + blueprint.Selected -= onBlueprintSelected; + blueprint.Deselected -= onBlueprintDeselected; + blueprint.SelectionRequested -= onSelectionRequested; + blueprint.DragRequested -= onDragRequested; + + selectionBlueprints.Remove(blueprint); + } + protected override bool OnClick(ClickEvent e) { deselectAll(); @@ -58,42 +119,17 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers } /// - /// Adds a mask for a which adds movement support. + /// Refreshes the current placement tool. /// - /// The to create a mask for. - public void AddBlueprintFor(DrawableHitObject hitObject) + private void refreshTool() { - var mask = composer.CreateMaskFor(hitObject); - if (mask == null) - return; + placementBlueprintContainer.Clear(); - mask.Selected += onBlueprintSelected; - mask.Deselected += onBlueprintDeselected; - mask.SelectionRequested += onSelectionRequested; - mask.DragRequested += onDragRequested; - - selectionBlueprints.Add(mask); + var blueprint = CurrentTool?.CreatePlacementMask(); + if (blueprint != null) + placementBlueprintContainer.Child = blueprint; } - /// - /// Removes a mask for a . - /// - /// The for which to remove the mask. - public void RemoveBlueprintFor(DrawableHitObject hitObject) - { - var maskToRemove = selectionBlueprints.Single(m => m.HitObject == hitObject); - if (maskToRemove == null) - return; - - maskToRemove.Deselect(); - - maskToRemove.Selected -= onBlueprintSelected; - maskToRemove.Deselected -= onBlueprintDeselected; - maskToRemove.SelectionRequested -= onSelectionRequested; - maskToRemove.DragRequested -= onDragRequested; - - selectionBlueprints.Remove(maskToRemove); - } /// /// Select all masks in a given rectangle selection area. @@ -101,12 +137,12 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers /// The rectangle to perform a selection on in screen-space coordinates. private void select(RectangleF rect) { - foreach (var mask in selections.ToList()) + foreach (var blueprint in selections.ToList()) { - if (mask.IsPresent && rect.Contains(mask.SelectionPoint)) - mask.Select(); + if (blueprint.IsPresent && rect.Contains(blueprint.SelectionPoint)) + blueprint.Select(); else - mask.Deselect(); + blueprint.Deselect(); } } diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/PlacementContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/PlacementContainer.cs deleted file mode 100644 index ea167a5c6b..0000000000 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/PlacementContainer.cs +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Rulesets.Edit.Tools; -using Container = System.ComponentModel.Container; - -namespace osu.Game.Screens.Edit.Screens.Compose.Layers -{ - public class PlacementContainer : CompositeDrawable - { - private readonly Container maskContainer; - - public PlacementContainer() - { - RelativeSizeAxes = Axes.Both; - } - - private HitObjectCompositionTool currentTool; - - /// - /// The current placement tool. - /// - public HitObjectCompositionTool CurrentTool - { - get => currentTool; - set - { - if (currentTool == value) - return; - currentTool = value; - - Refresh(); - } - } - - /// - /// Refreshes the current placement tool. - /// - public void Refresh() - { - ClearInternal(); - - var mask = CurrentTool?.CreatePlacementMask(); - if (mask != null) - InternalChild = mask; - } - } -} From 11be820efe67fd36e62cbbee76d7eb9441b1c8cf Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 6 Nov 2018 18:03:21 +0900 Subject: [PATCH 088/155] CreateMaskFor -> CreateBlueprintFor --- osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs | 4 ++-- osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs | 4 ++-- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 2 +- .../Screens/Edit/Screens/Compose/Layers/BlueprintContainer.cs | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs index 76969ab2bf..7420a3c64c 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs @@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Mania.Edit protected override IReadOnlyList CompositionTools => Array.Empty(); - public override SelectionBlueprint CreateMaskFor(DrawableHitObject hitObject) + public override SelectionBlueprint CreateBlueprintFor(DrawableHitObject hitObject) { switch (hitObject) { @@ -48,7 +48,7 @@ namespace osu.Game.Rulesets.Mania.Edit return new HoldNoteSelectionBlueprint(holdNote); } - return base.CreateMaskFor(hitObject); + return base.CreateBlueprintFor(hitObject); } } } diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index 1ed3578ab4..1d806aba90 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Osu.Edit protected override Container CreateLayerContainer() => new PlayfieldAdjustmentContainer { RelativeSizeAxes = Axes.Both }; - public override SelectionBlueprint CreateMaskFor(DrawableHitObject hitObject) + public override SelectionBlueprint CreateBlueprintFor(DrawableHitObject hitObject) { switch (hitObject) { @@ -49,7 +49,7 @@ namespace osu.Game.Rulesets.Osu.Edit return new SpinnerSelectionBlueprint(spinner); } - return base.CreateMaskFor(hitObject); + return base.CreateBlueprintFor(hitObject); } } } diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 7072e31e16..f1b1948b5e 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -153,7 +153,7 @@ namespace osu.Game.Rulesets.Edit /// Creates a for a specific . /// /// The to create the overlay for. - public virtual SelectionBlueprint CreateMaskFor(DrawableHitObject hitObject) => null; + public virtual SelectionBlueprint CreateBlueprintFor(DrawableHitObject hitObject) => null; /// /// Creates a which outlines s diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/BlueprintContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/BlueprintContainer.cs index 5c7d840f3d..730dedb53f 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Layers/BlueprintContainer.cs @@ -80,7 +80,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers { refreshTool(); - var blueprint = composer.CreateMaskFor(hitObject); + var blueprint = composer.CreateBlueprintFor(hitObject); if (blueprint == null) return; From bd775af274224e708e9de31db080d128c8dcd829 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 6 Nov 2018 18:04:03 +0900 Subject: [PATCH 089/155] PlacementMask -> PlacementBlueprint --- .../TestCaseHitCirclePlacementMask.cs | 2 +- .../TestCaseSliderPlacementMask.cs | 2 +- .../TestCaseSpinnerPlacementMask.cs | 2 +- osu.Game.Rulesets.Osu/Edit/HitCircleCompositionTool.cs | 2 +- ...PlacementMask.cs => HitCirclePlacementBlueprint.cs} | 4 ++-- ...derPlacementMask.cs => SliderPlacementBlueprint.cs} | 4 ++-- ...erPlacementMask.cs => SpinnerPlacementBlueprint.cs} | 4 ++-- osu.Game.Rulesets.Osu/Edit/SliderCompositionTool.cs | 2 +- osu.Game.Rulesets.Osu/Edit/SpinnerCompositionTool.cs | 2 +- osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs | 2 +- .../Edit/{PlacementMask.cs => PlacementBlueprint.cs} | 6 +++--- .../Rulesets/Edit/Tools/HitObjectCompositionTool.cs | 2 +- .../Edit/Screens/Compose/Layers/BlueprintContainer.cs | 4 ++-- .../Tests/Visual/HitObjectPlacementMaskTestCase.cs | 10 +++++----- 14 files changed, 24 insertions(+), 24 deletions(-) rename osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/{HitCirclePlacementMask.cs => HitCirclePlacementBlueprint.cs} (91%) rename osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/{SliderPlacementMask.cs => SliderPlacementBlueprint.cs} (98%) rename osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/{SpinnerPlacementMask.cs => SpinnerPlacementBlueprint.cs} (91%) rename osu.Game/Rulesets/Edit/{PlacementMask.cs => PlacementBlueprint.cs} (90%) diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseHitCirclePlacementMask.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseHitCirclePlacementMask.cs index be0b94c4c8..8e41a28440 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseHitCirclePlacementMask.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseHitCirclePlacementMask.cs @@ -14,6 +14,6 @@ namespace osu.Game.Rulesets.Osu.Tests public class TestCaseHitCirclePlacementMask : HitObjectPlacementMaskTestCase { protected override DrawableHitObject CreateHitObject(HitObject hitObject) => new DrawableHitCircle((HitCircle)hitObject); - protected override PlacementMask CreateMask() => new HitCirclePlacementMask(); + protected override PlacementBlueprint CreateMask() => new HitCirclePlacementBlueprint(); } } diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderPlacementMask.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSliderPlacementMask.cs index 889ea0c311..5dd7a99aad 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderPlacementMask.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSliderPlacementMask.cs @@ -14,6 +14,6 @@ namespace osu.Game.Rulesets.Osu.Tests public class TestCaseSliderPlacementMask : HitObjectPlacementMaskTestCase { protected override DrawableHitObject CreateHitObject(HitObject hitObject) => new DrawableSlider((Slider)hitObject); - protected override PlacementMask CreateMask() => new SliderPlacementMask(); + protected override PlacementBlueprint CreateMask() => new SliderPlacementBlueprint(); } } diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerPlacementMask.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerPlacementMask.cs index c2c7942c57..1ca203e474 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerPlacementMask.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerPlacementMask.cs @@ -15,6 +15,6 @@ namespace osu.Game.Rulesets.Osu.Tests { protected override DrawableHitObject CreateHitObject(HitObject hitObject) => new DrawableSpinner((Spinner)hitObject); - protected override PlacementMask CreateMask() => new SpinnerPlacementMask(); + protected override PlacementBlueprint CreateMask() => new SpinnerPlacementBlueprint(); } } diff --git a/osu.Game.Rulesets.Osu/Edit/HitCircleCompositionTool.cs b/osu.Game.Rulesets.Osu/Edit/HitCircleCompositionTool.cs index 767c7db5da..d7a4c7a6b7 100644 --- a/osu.Game.Rulesets.Osu/Edit/HitCircleCompositionTool.cs +++ b/osu.Game.Rulesets.Osu/Edit/HitCircleCompositionTool.cs @@ -15,6 +15,6 @@ namespace osu.Game.Rulesets.Osu.Edit { } - public override PlacementMask CreatePlacementMask() => new HitCirclePlacementMask(); + public override PlacementBlueprint CreatePlacementMask() => new HitCirclePlacementBlueprint(); } } diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCirclePlacementMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCirclePlacementBlueprint.cs similarity index 91% rename from osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCirclePlacementMask.cs rename to osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCirclePlacementBlueprint.cs index 0d0acbed7d..ec32b7d74d 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCirclePlacementMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCirclePlacementBlueprint.cs @@ -8,11 +8,11 @@ using osu.Game.Rulesets.Osu.Objects; namespace osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks { - public class HitCirclePlacementMask : PlacementMask + public class HitCirclePlacementBlueprint : PlacementBlueprint { public new HitCircle HitObject => (HitCircle)base.HitObject; - public HitCirclePlacementMask() + public HitCirclePlacementBlueprint() : base(new HitCircle()) { InternalChild = new HitCirclePiece(HitObject); diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPlacementMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPlacementBlueprint.cs similarity index 98% rename from osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPlacementMask.cs rename to osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPlacementBlueprint.cs index 12e768d58e..bf2acc2f3c 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPlacementMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPlacementBlueprint.cs @@ -18,7 +18,7 @@ using OpenTK.Input; namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks { - public class SliderPlacementMask : PlacementMask + public class SliderPlacementBlueprint : PlacementBlueprint { public new Objects.Slider HitObject => (Objects.Slider)base.HitObject; @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks private PlacementState state; - public SliderPlacementMask() + public SliderPlacementBlueprint() : base(new Objects.Slider()) { RelativeSizeAxes = Axes.Both; diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerPlacementMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerPlacementBlueprint.cs similarity index 91% rename from osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerPlacementMask.cs rename to osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerPlacementBlueprint.cs index cd5d6cff04..ca7a2f7b01 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerPlacementMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerPlacementBlueprint.cs @@ -10,7 +10,7 @@ using osu.Game.Rulesets.Osu.UI; namespace osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks { - public class SpinnerPlacementMask : PlacementMask + public class SpinnerPlacementBlueprint : PlacementBlueprint { public new Spinner HitObject => (Spinner)base.HitObject; @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks private bool isPlacingEnd; - public SpinnerPlacementMask() + public SpinnerPlacementBlueprint() : base(new Spinner { Position = OsuPlayfield.BASE_SIZE / 2 }) { InternalChild = piece = new SpinnerPiece(HitObject) { Alpha = 0.5f }; diff --git a/osu.Game.Rulesets.Osu/Edit/SliderCompositionTool.cs b/osu.Game.Rulesets.Osu/Edit/SliderCompositionTool.cs index fd0430ce4c..050c538329 100644 --- a/osu.Game.Rulesets.Osu/Edit/SliderCompositionTool.cs +++ b/osu.Game.Rulesets.Osu/Edit/SliderCompositionTool.cs @@ -15,6 +15,6 @@ namespace osu.Game.Rulesets.Osu.Edit { } - public override PlacementMask CreatePlacementMask() => new SliderPlacementMask(); + public override PlacementBlueprint CreatePlacementMask() => new SliderPlacementBlueprint(); } } diff --git a/osu.Game.Rulesets.Osu/Edit/SpinnerCompositionTool.cs b/osu.Game.Rulesets.Osu/Edit/SpinnerCompositionTool.cs index a1419fe281..4401496327 100644 --- a/osu.Game.Rulesets.Osu/Edit/SpinnerCompositionTool.cs +++ b/osu.Game.Rulesets.Osu/Edit/SpinnerCompositionTool.cs @@ -15,6 +15,6 @@ namespace osu.Game.Rulesets.Osu.Edit { } - public override PlacementMask CreatePlacementMask() => new SpinnerPlacementMask(); + public override PlacementBlueprint CreatePlacementMask() => new SpinnerPlacementBlueprint(); } } diff --git a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs index ff82034648..0e337acd2f 100644 --- a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs +++ b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs @@ -36,7 +36,7 @@ namespace osu.Game.Tests.Visual typeof(NotNullAttribute), typeof(HitCirclePiece), typeof(HitCircleSelectionBlueprint), - typeof(HitCirclePlacementMask), + typeof(HitCirclePlacementBlueprint), }; private HitObjectComposer composer; diff --git a/osu.Game/Rulesets/Edit/PlacementMask.cs b/osu.Game/Rulesets/Edit/PlacementBlueprint.cs similarity index 90% rename from osu.Game/Rulesets/Edit/PlacementMask.cs rename to osu.Game/Rulesets/Edit/PlacementBlueprint.cs index 97c6a74c92..7e5a592a0d 100644 --- a/osu.Game/Rulesets/Edit/PlacementMask.cs +++ b/osu.Game/Rulesets/Edit/PlacementBlueprint.cs @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Edit /// /// A mask which governs the creation of a new to actualisation. /// - public abstract class PlacementMask : CompositeDrawable, IRequireHighFrequencyMousePosition + public abstract class PlacementBlueprint : CompositeDrawable, IRequireHighFrequencyMousePosition { /// /// The that is being placed. @@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Edit [Resolved] private IPlacementHandler placementHandler { get; set; } - protected PlacementMask(HitObject hitObject) + protected PlacementBlueprint(HitObject hitObject) { HitObject = hitObject; @@ -62,7 +62,7 @@ namespace osu.Game.Rulesets.Edit /// /// Signals that the placement of has finished. - /// This will destroy this , and add the to the . + /// This will destroy this , and add the to the . /// protected void EndPlacement() { diff --git a/osu.Game/Rulesets/Edit/Tools/HitObjectCompositionTool.cs b/osu.Game/Rulesets/Edit/Tools/HitObjectCompositionTool.cs index c5d64e3d4d..1a20f165c0 100644 --- a/osu.Game/Rulesets/Edit/Tools/HitObjectCompositionTool.cs +++ b/osu.Game/Rulesets/Edit/Tools/HitObjectCompositionTool.cs @@ -12,6 +12,6 @@ namespace osu.Game.Rulesets.Edit.Tools Name = name; } - public abstract PlacementMask CreatePlacementMask(); + public abstract PlacementBlueprint CreatePlacementMask(); } } diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/BlueprintContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/BlueprintContainer.cs index 730dedb53f..f781da0c60 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Layers/BlueprintContainer.cs @@ -19,7 +19,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers public class BlueprintContainer : CompositeDrawable { private SelectionBlueprintContainer selectionBlueprints; - private Container placementBlueprintContainer; + private Container placementBlueprintContainer; private SelectionBox selectionBox; private IEnumerable selections => selectionBlueprints.Children.Where(c => c.IsAlive); @@ -46,7 +46,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers dragBox, selectionBox, selectionBlueprints = new SelectionBlueprintContainer { RelativeSizeAxes = Axes.Both }, - placementBlueprintContainer = new Container { RelativeSizeAxes = Axes.Both }, + placementBlueprintContainer = new Container { RelativeSizeAxes = Axes.Both }, dragBox.CreateProxy() }; diff --git a/osu.Game/Tests/Visual/HitObjectPlacementMaskTestCase.cs b/osu.Game/Tests/Visual/HitObjectPlacementMaskTestCase.cs index adf74b9a7d..e33d92da88 100644 --- a/osu.Game/Tests/Visual/HitObjectPlacementMaskTestCase.cs +++ b/osu.Game/Tests/Visual/HitObjectPlacementMaskTestCase.cs @@ -16,7 +16,7 @@ namespace osu.Game.Tests.Visual public abstract class HitObjectPlacementMaskTestCase : OsuTestCase, IPlacementHandler { private readonly Container hitObjectContainer; - private PlacementMask currentMask; + private PlacementBlueprint currentBlueprint; protected HitObjectPlacementMaskTestCase() { @@ -32,7 +32,7 @@ namespace osu.Game.Tests.Visual [BackgroundDependencyLoader] private void load() { - Add(currentMask = CreateMask()); + Add(currentBlueprint = CreateMask()); } protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) @@ -51,8 +51,8 @@ namespace osu.Game.Tests.Visual { hitObjectContainer.Add(CreateHitObject(hitObject)); - Remove(currentMask); - Add(currentMask = CreateMask()); + Remove(currentBlueprint); + Add(currentBlueprint = CreateMask()); } public void Delete(HitObject hitObject) @@ -60,6 +60,6 @@ namespace osu.Game.Tests.Visual } protected abstract DrawableHitObject CreateHitObject(HitObject hitObject); - protected abstract PlacementMask CreateMask(); + protected abstract PlacementBlueprint CreateMask(); } } From b3fa7c111b631ee21952ba9a1e00c6a95be0247b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 6 Nov 2018 18:06:13 +0900 Subject: [PATCH 090/155] Rename testcases --- ...lacementMask.cs => TestCaseHitCirclePlacementBlueprint.cs} | 2 +- ...electionMask.cs => TestCaseHitCircleSelectionBlueprint.cs} | 4 ++-- ...erPlacementMask.cs => TestCaseSliderPlacementBlueprint.cs} | 2 +- ...erSelectionMask.cs => TestCaseSliderSelectionBlueprint.cs} | 4 ++-- ...rPlacementMask.cs => TestCaseSpinnerPlacementBlueprint.cs} | 2 +- ...rSelectionMask.cs => TestCaseSpinnerSelectionBlueprint.cs} | 4 ++-- ...PlacementMaskTestCase.cs => PlacementBlueprintTestCase.cs} | 4 ++-- ...SelectionMaskTestCase.cs => SelectionBlueprintTestCase.cs} | 4 ++-- 8 files changed, 13 insertions(+), 13 deletions(-) rename osu.Game.Rulesets.Osu.Tests/{TestCaseHitCirclePlacementMask.cs => TestCaseHitCirclePlacementBlueprint.cs} (89%) rename osu.Game.Rulesets.Osu.Tests/{TestCaseHitCircleSelectionMask.cs => TestCaseHitCircleSelectionBlueprint.cs} (87%) rename osu.Game.Rulesets.Osu.Tests/{TestCaseSliderPlacementMask.cs => TestCaseSliderPlacementBlueprint.cs} (89%) rename osu.Game.Rulesets.Osu.Tests/{TestCaseSliderSelectionMask.cs => TestCaseSliderSelectionBlueprint.cs} (92%) rename osu.Game.Rulesets.Osu.Tests/{TestCaseSpinnerPlacementMask.cs => TestCaseSpinnerPlacementBlueprint.cs} (89%) rename osu.Game.Rulesets.Osu.Tests/{TestCaseSpinnerSelectionMask.cs => TestCaseSpinnerSelectionBlueprint.cs} (92%) rename osu.Game/Tests/Visual/{HitObjectPlacementMaskTestCase.cs => PlacementBlueprintTestCase.cs} (93%) rename osu.Game/Tests/Visual/{HitObjectSelectionMaskTestCase.cs => SelectionBlueprintTestCase.cs} (91%) diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseHitCirclePlacementMask.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseHitCirclePlacementBlueprint.cs similarity index 89% rename from osu.Game.Rulesets.Osu.Tests/TestCaseHitCirclePlacementMask.cs rename to osu.Game.Rulesets.Osu.Tests/TestCaseHitCirclePlacementBlueprint.cs index 8e41a28440..3aaccb3c45 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseHitCirclePlacementMask.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseHitCirclePlacementBlueprint.cs @@ -11,7 +11,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Osu.Tests { - public class TestCaseHitCirclePlacementMask : HitObjectPlacementMaskTestCase + public class TestCaseHitCirclePlacementBlueprint : PlacementBlueprintTestCase { protected override DrawableHitObject CreateHitObject(HitObject hitObject) => new DrawableHitCircle((HitCircle)hitObject); protected override PlacementBlueprint CreateMask() => new HitCirclePlacementBlueprint(); diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleSelectionMask.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleSelectionBlueprint.cs similarity index 87% rename from osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleSelectionMask.cs rename to osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleSelectionBlueprint.cs index 330315a953..843b6e83f2 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleSelectionMask.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleSelectionBlueprint.cs @@ -12,11 +12,11 @@ using OpenTK; namespace osu.Game.Rulesets.Osu.Tests { - public class TestCaseHitCircleSelectionMask : HitObjectSelectionMaskTestCase + public class TestCaseHitCircleSelectionBlueprint : SelectionBlueprintTestCase { private readonly DrawableHitCircle drawableObject; - public TestCaseHitCircleSelectionMask() + public TestCaseHitCircleSelectionBlueprint() { var hitCircle = new HitCircle { Position = new Vector2(256, 192) }; hitCircle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 2 }); diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderPlacementMask.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSliderPlacementBlueprint.cs similarity index 89% rename from osu.Game.Rulesets.Osu.Tests/TestCaseSliderPlacementMask.cs rename to osu.Game.Rulesets.Osu.Tests/TestCaseSliderPlacementBlueprint.cs index 5dd7a99aad..43f2718c9a 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderPlacementMask.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSliderPlacementBlueprint.cs @@ -11,7 +11,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Osu.Tests { - public class TestCaseSliderPlacementMask : HitObjectPlacementMaskTestCase + public class TestCaseSliderPlacementBlueprint : PlacementBlueprintTestCase { protected override DrawableHitObject CreateHitObject(HitObject hitObject) => new DrawableSlider((Slider)hitObject); protected override PlacementBlueprint CreateMask() => new SliderPlacementBlueprint(); diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionMask.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionBlueprint.cs similarity index 92% rename from osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionMask.cs rename to osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionBlueprint.cs index 0641ff7582..43c11b4441 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionMask.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionBlueprint.cs @@ -16,7 +16,7 @@ using OpenTK; namespace osu.Game.Rulesets.Osu.Tests { - public class TestCaseSliderSelectionMask : HitObjectSelectionMaskTestCase + public class TestCaseSliderSelectionBlueprint : SelectionBlueprintTestCase { public override IReadOnlyList RequiredTypes => new[] { @@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Osu.Tests private readonly DrawableSlider drawableObject; - public TestCaseSliderSelectionMask() + public TestCaseSliderSelectionBlueprint() { var slider = new Slider { diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerPlacementMask.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerPlacementBlueprint.cs similarity index 89% rename from osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerPlacementMask.cs rename to osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerPlacementBlueprint.cs index 1ca203e474..4b1dc62452 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerPlacementMask.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerPlacementBlueprint.cs @@ -11,7 +11,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Osu.Tests { - public class TestCaseSpinnerPlacementMask : HitObjectPlacementMaskTestCase + public class TestCaseSpinnerPlacementBlueprint : PlacementBlueprintTestCase { protected override DrawableHitObject CreateHitObject(HitObject hitObject) => new DrawableSpinner((Spinner)hitObject); diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerSelectionMask.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerSelectionBlueprint.cs similarity index 92% rename from osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerSelectionMask.cs rename to osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerSelectionBlueprint.cs index 9b0be3cc9c..f94939b585 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerSelectionMask.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerSelectionBlueprint.cs @@ -17,7 +17,7 @@ using OpenTK; namespace osu.Game.Rulesets.Osu.Tests { - public class TestCaseSpinnerSelectionMask : HitObjectSelectionMaskTestCase + public class TestCaseSpinnerSelectionBlueprint : SelectionBlueprintTestCase { public override IReadOnlyList RequiredTypes => new[] { @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Osu.Tests private readonly DrawableSpinner drawableSpinner; - public TestCaseSpinnerSelectionMask() + public TestCaseSpinnerSelectionBlueprint() { var spinner = new Spinner { diff --git a/osu.Game/Tests/Visual/HitObjectPlacementMaskTestCase.cs b/osu.Game/Tests/Visual/PlacementBlueprintTestCase.cs similarity index 93% rename from osu.Game/Tests/Visual/HitObjectPlacementMaskTestCase.cs rename to osu.Game/Tests/Visual/PlacementBlueprintTestCase.cs index e33d92da88..6cc8408998 100644 --- a/osu.Game/Tests/Visual/HitObjectPlacementMaskTestCase.cs +++ b/osu.Game/Tests/Visual/PlacementBlueprintTestCase.cs @@ -13,12 +13,12 @@ using osu.Game.Screens.Edit.Screens.Compose; namespace osu.Game.Tests.Visual { [Cached(Type = typeof(IPlacementHandler))] - public abstract class HitObjectPlacementMaskTestCase : OsuTestCase, IPlacementHandler + public abstract class PlacementBlueprintTestCase : OsuTestCase, IPlacementHandler { private readonly Container hitObjectContainer; private PlacementBlueprint currentBlueprint; - protected HitObjectPlacementMaskTestCase() + protected PlacementBlueprintTestCase() { Beatmap.Value.BeatmapInfo.BaseDifficulty.CircleSize = 2; diff --git a/osu.Game/Tests/Visual/HitObjectSelectionMaskTestCase.cs b/osu.Game/Tests/Visual/SelectionBlueprintTestCase.cs similarity index 91% rename from osu.Game/Tests/Visual/HitObjectSelectionMaskTestCase.cs rename to osu.Game/Tests/Visual/SelectionBlueprintTestCase.cs index 707ebaa96b..1879b0c37f 100644 --- a/osu.Game/Tests/Visual/HitObjectSelectionMaskTestCase.cs +++ b/osu.Game/Tests/Visual/SelectionBlueprintTestCase.cs @@ -10,14 +10,14 @@ using osu.Game.Rulesets.Edit; namespace osu.Game.Tests.Visual { - public abstract class HitObjectSelectionMaskTestCase : OsuTestCase + public abstract class SelectionBlueprintTestCase : OsuTestCase { private SelectionBlueprint blueprint; protected override Container Content => content ?? base.Content; private readonly Container content; - protected HitObjectSelectionMaskTestCase() + protected SelectionBlueprintTestCase() { base.Content.Add(content = new Container { From 85f96ad62fcf559d9b2f669bf3ee29329c3c2f8c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 6 Nov 2018 18:06:34 +0900 Subject: [PATCH 091/155] Fix a few missed renames --- .../Edit/HitCircleCompositionTool.cs | 2 +- .../Edit/SliderCompositionTool.cs | 2 +- .../Edit/SpinnerCompositionTool.cs | 2 +- osu.Game/Rulesets/Edit/PlacementBlueprint.cs | 2 +- osu.Game/Rulesets/Edit/SelectionBlueprint.cs | 2 +- .../Edit/Tools/HitObjectCompositionTool.cs | 2 +- .../Compose/Layers/BlueprintContainer.cs | 2 +- .../Screens/Compose/Layers/SelectionBox.cs | 42 +++++++++---------- 8 files changed, 28 insertions(+), 28 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/HitCircleCompositionTool.cs b/osu.Game.Rulesets.Osu/Edit/HitCircleCompositionTool.cs index d7a4c7a6b7..1a48a0b6a9 100644 --- a/osu.Game.Rulesets.Osu/Edit/HitCircleCompositionTool.cs +++ b/osu.Game.Rulesets.Osu/Edit/HitCircleCompositionTool.cs @@ -15,6 +15,6 @@ namespace osu.Game.Rulesets.Osu.Edit { } - public override PlacementBlueprint CreatePlacementMask() => new HitCirclePlacementBlueprint(); + public override PlacementBlueprint CreatePlacementBlueprint() => new HitCirclePlacementBlueprint(); } } diff --git a/osu.Game.Rulesets.Osu/Edit/SliderCompositionTool.cs b/osu.Game.Rulesets.Osu/Edit/SliderCompositionTool.cs index 050c538329..0cf98ea9d7 100644 --- a/osu.Game.Rulesets.Osu/Edit/SliderCompositionTool.cs +++ b/osu.Game.Rulesets.Osu/Edit/SliderCompositionTool.cs @@ -15,6 +15,6 @@ namespace osu.Game.Rulesets.Osu.Edit { } - public override PlacementBlueprint CreatePlacementMask() => new SliderPlacementBlueprint(); + public override PlacementBlueprint CreatePlacementBlueprint() => new SliderPlacementBlueprint(); } } diff --git a/osu.Game.Rulesets.Osu/Edit/SpinnerCompositionTool.cs b/osu.Game.Rulesets.Osu/Edit/SpinnerCompositionTool.cs index 4401496327..b3677c7612 100644 --- a/osu.Game.Rulesets.Osu/Edit/SpinnerCompositionTool.cs +++ b/osu.Game.Rulesets.Osu/Edit/SpinnerCompositionTool.cs @@ -15,6 +15,6 @@ namespace osu.Game.Rulesets.Osu.Edit { } - public override PlacementBlueprint CreatePlacementMask() => new SpinnerPlacementBlueprint(); + public override PlacementBlueprint CreatePlacementBlueprint() => new SpinnerPlacementBlueprint(); } } diff --git a/osu.Game/Rulesets/Edit/PlacementBlueprint.cs b/osu.Game/Rulesets/Edit/PlacementBlueprint.cs index 7e5a592a0d..fe27d37640 100644 --- a/osu.Game/Rulesets/Edit/PlacementBlueprint.cs +++ b/osu.Game/Rulesets/Edit/PlacementBlueprint.cs @@ -16,7 +16,7 @@ using OpenTK; namespace osu.Game.Rulesets.Edit { /// - /// A mask which governs the creation of a new to actualisation. + /// A blueprint which governs the creation of a new to actualisation. /// public abstract class PlacementBlueprint : CompositeDrawable, IRequireHighFrequencyMousePosition { diff --git a/osu.Game/Rulesets/Edit/SelectionBlueprint.cs b/osu.Game/Rulesets/Edit/SelectionBlueprint.cs index dc879b3a16..6e0d136e1f 100644 --- a/osu.Game/Rulesets/Edit/SelectionBlueprint.cs +++ b/osu.Game/Rulesets/Edit/SelectionBlueprint.cs @@ -15,7 +15,7 @@ using OpenTK; namespace osu.Game.Rulesets.Edit { /// - /// A mask placed above a adding editing functionality. + /// A blueprint placed above a adding editing functionality. /// public class SelectionBlueprint : CompositeDrawable, IStateful { diff --git a/osu.Game/Rulesets/Edit/Tools/HitObjectCompositionTool.cs b/osu.Game/Rulesets/Edit/Tools/HitObjectCompositionTool.cs index 1a20f165c0..1cb3c4c451 100644 --- a/osu.Game/Rulesets/Edit/Tools/HitObjectCompositionTool.cs +++ b/osu.Game/Rulesets/Edit/Tools/HitObjectCompositionTool.cs @@ -12,6 +12,6 @@ namespace osu.Game.Rulesets.Edit.Tools Name = name; } - public abstract PlacementBlueprint CreatePlacementMask(); + public abstract PlacementBlueprint CreatePlacementBlueprint(); } } diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/BlueprintContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/BlueprintContainer.cs index f781da0c60..2d99851b71 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Layers/BlueprintContainer.cs @@ -125,7 +125,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers { placementBlueprintContainer.Clear(); - var blueprint = CurrentTool?.CreatePlacementMask(); + var blueprint = CurrentTool?.CreatePlacementBlueprint(); if (blueprint != null) placementBlueprintContainer.Child = blueprint; } diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/SelectionBox.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/SelectionBox.cs index 6aef47d690..59a7f3094c 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/SelectionBox.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Layers/SelectionBox.cs @@ -25,7 +25,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers { public const float BORDER_RADIUS = 2; - private readonly List selectedMasks; + private readonly List selectedBlueprints; private Drawable outline; @@ -34,7 +34,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers public SelectionBox() { - selectedMasks = new List(); + selectedBlueprints = new List(); RelativeSizeAxes = Axes.Both; AlwaysPresent = true; @@ -64,9 +64,9 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers { // Todo: Various forms of snapping - foreach (var mask in selectedMasks) + foreach (var blueprint in selectedBlueprints) { - switch (mask.HitObject.HitObject) + switch (blueprint.HitObject.HitObject) { case IHasEditablePosition editablePosition: editablePosition.OffsetPosition(delta); @@ -83,7 +83,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers switch (e.Key) { case Key.Delete: - foreach (var h in selectedMasks.ToList()) + foreach (var h in selectedBlueprints.ToList()) placementHandler.Delete(h.HitObject.HitObject); return true; } @@ -96,33 +96,33 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers #region Selection Handling /// - /// Bind an action to deselect all selected masks. + /// Bind an action to deselect all selected blueprints. /// public Action DeselectAll { private get; set; } /// - /// Handle a mask becoming selected. + /// Handle a blueprint becoming selected. /// - /// The mask. - public void HandleSelected(SelectionBlueprint blueprint) => selectedMasks.Add(blueprint); + /// The blueprint. + public void HandleSelected(SelectionBlueprint blueprint) => selectedBlueprints.Add(blueprint); /// - /// Handle a mask becoming deselected. + /// Handle a blueprint becoming deselected. /// - /// The mask. + /// The blueprint. public void HandleDeselected(SelectionBlueprint blueprint) { - selectedMasks.Remove(blueprint); + selectedBlueprints.Remove(blueprint); - // We don't want to update visibility if > 0, since we may be deselecting masks during drag-selection - if (selectedMasks.Count == 0) + // We don't want to update visibility if > 0, since we may be deselecting blueprints during drag-selection + if (selectedBlueprints.Count == 0) UpdateVisibility(); } /// - /// Handle a mask requesting selection. + /// Handle a blueprint requesting selection. /// - /// The mask. + /// The blueprint. public void HandleSelectionRequested(SelectionBlueprint blueprint, InputState state) { if (state.Keyboard.ControlPressed) @@ -151,7 +151,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers /// internal void UpdateVisibility() { - if (selectedMasks.Count > 0) + if (selectedBlueprints.Count > 0) Show(); else Hide(); @@ -161,7 +161,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers { base.Update(); - if (selectedMasks.Count == 0) + if (selectedBlueprints.Count == 0) return; // Move the rectangle to cover the hitobjects @@ -170,10 +170,10 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers bool hasSelection = false; - foreach (var mask in selectedMasks) + foreach (var blueprint in selectedBlueprints) { - topLeft = Vector2.ComponentMin(topLeft, ToLocalSpace(mask.SelectionQuad.TopLeft)); - bottomRight = Vector2.ComponentMax(bottomRight, ToLocalSpace(mask.SelectionQuad.BottomRight)); + topLeft = Vector2.ComponentMin(topLeft, ToLocalSpace(blueprint.SelectionQuad.TopLeft)); + bottomRight = Vector2.ComponentMax(bottomRight, ToLocalSpace(blueprint.SelectionQuad.BottomRight)); } topLeft -= new Vector2(5); From 27d82052f4db02109233f7699fe4065400718706 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 6 Nov 2018 18:10:46 +0900 Subject: [PATCH 092/155] BorderLayer -> EditorPlayfieldBorder --- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 2 +- .../Screens/Compose/Layers/BorderLayer.cs | 38 ------------------- .../Compose/Layers/EditorPlayfieldBorder.cs | 32 ++++++++++++++++ 3 files changed, 33 insertions(+), 39 deletions(-) delete mode 100644 osu.Game/Screens/Edit/Screens/Compose/Layers/BorderLayer.cs create mode 100644 osu.Game/Screens/Edit/Screens/Compose/Layers/EditorPlayfieldBorder.cs diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index f1b1948b5e..64f2648ca1 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -61,7 +61,7 @@ namespace osu.Game.Rulesets.Edit } var layerBelowRuleset = CreateLayerContainer(); - layerBelowRuleset.Child = new BorderLayer { RelativeSizeAxes = Axes.Both }; + layerBelowRuleset.Child = new EditorPlayfieldBorder { RelativeSizeAxes = Axes.Both }; var layerAboveRuleset = CreateLayerContainer(); layerAboveRuleset.Child = new BlueprintContainer(); diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/BorderLayer.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/BorderLayer.cs deleted file mode 100644 index c46f9a1b7f..0000000000 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/BorderLayer.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using OpenTK.Graphics; - -namespace osu.Game.Screens.Edit.Screens.Compose.Layers -{ - public class BorderLayer : Container - { - protected override Container Content => content; - private readonly Container content; - - public BorderLayer() - { - InternalChildren = new Drawable[] - { - new Container - { - Name = "Border", - RelativeSizeAxes = Axes.Both, - Masking = true, - BorderColour = Color4.White, - BorderThickness = 2, - Child = new Box - { - RelativeSizeAxes = Axes.Both, - Alpha = 0, - AlwaysPresent = true - } - }, - content = new Container { RelativeSizeAxes = Axes.Both } - }; - } - } -} diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/EditorPlayfieldBorder.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/EditorPlayfieldBorder.cs new file mode 100644 index 0000000000..22cdfa9328 --- /dev/null +++ b/osu.Game/Screens/Edit/Screens/Compose/Layers/EditorPlayfieldBorder.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 osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using OpenTK.Graphics; + +namespace osu.Game.Screens.Edit.Screens.Compose.Layers +{ + /// + /// Provides a border around the playfield. + /// + public class EditorPlayfieldBorder : CompositeDrawable + { + public EditorPlayfieldBorder() + { + RelativeSizeAxes = Axes.Both; + + Masking = true; + BorderColour = Color4.White; + BorderThickness = 2; + + InternalChild = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + AlwaysPresent = true + }; + } + } +} From ac25718c5a112ba7cf77dcdb2ac59f280f36071f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 6 Nov 2018 18:14:46 +0900 Subject: [PATCH 093/155] Renamespace compose-mode components --- osu.Game.Tests/Visual/TestCaseBeatDivisorControl.cs | 1 + osu.Game.Tests/Visual/TestCaseEditorComposeRadioButtons.cs | 2 +- osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs | 2 +- osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs | 2 +- osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs | 2 +- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 4 ++-- .../RadioButtons/DrawableRadioButton.cs | 6 +++--- .../Compose => Components}/RadioButtons/RadioButton.cs | 2 +- .../RadioButtons/RadioButtonCollection.cs | 4 ++-- .../Screens/Compose/{ => Components}/BeatDivisorControl.cs | 2 +- .../Compose/{Layers => Components}/BlueprintContainer.cs | 2 +- .../Edit/Screens/Compose/{Layers => Components}/DragBox.cs | 2 +- .../Compose/{Layers => Components}/EditorPlayfieldBorder.cs | 2 +- .../Screens/Compose/{Layers => Components}/SelectionBox.cs | 2 +- .../Compose/{ => Components}/Timeline/CentreMarker.cs | 2 +- .../Screens/Compose/{ => Components}/Timeline/Timeline.cs | 2 +- .../Compose/{ => Components}/Timeline/TimelineArea.cs | 4 ++-- .../Compose/{ => Components}/Timeline/TimelineButton.cs | 6 +++--- .../{ => Components}/Timeline/ZoomableScrollContainer.cs | 2 +- osu.Game/Screens/Edit/Screens/Compose/Compose.cs | 3 ++- 20 files changed, 28 insertions(+), 26 deletions(-) rename osu.Game/Screens/Edit/{Screens/Compose => Components}/RadioButtons/DrawableRadioButton.cs (98%) rename osu.Game/Screens/Edit/{Screens/Compose => Components}/RadioButtons/RadioButton.cs (95%) rename osu.Game/Screens/Edit/{Screens/Compose => Components}/RadioButtons/RadioButtonCollection.cs (96%) rename osu.Game/Screens/Edit/Screens/Compose/{ => Components}/BeatDivisorControl.cs (99%) rename osu.Game/Screens/Edit/Screens/Compose/{Layers => Components}/BlueprintContainer.cs (99%) rename osu.Game/Screens/Edit/Screens/Compose/{Layers => Components}/DragBox.cs (97%) rename osu.Game/Screens/Edit/Screens/Compose/{Layers => Components}/EditorPlayfieldBorder.cs (93%) rename osu.Game/Screens/Edit/Screens/Compose/{Layers => Components}/SelectionBox.cs (98%) rename osu.Game/Screens/Edit/Screens/Compose/{ => Components}/Timeline/CentreMarker.cs (95%) rename osu.Game/Screens/Edit/Screens/Compose/{ => Components}/Timeline/Timeline.cs (98%) rename osu.Game/Screens/Edit/Screens/Compose/{ => Components}/Timeline/TimelineArea.cs (98%) rename osu.Game/Screens/Edit/Screens/Compose/{ => Components}/Timeline/TimelineButton.cs (95%) rename osu.Game/Screens/Edit/Screens/Compose/{ => Components}/Timeline/ZoomableScrollContainer.cs (98%) diff --git a/osu.Game.Tests/Visual/TestCaseBeatDivisorControl.cs b/osu.Game.Tests/Visual/TestCaseBeatDivisorControl.cs index 1effa14e76..9709721686 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatDivisorControl.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatDivisorControl.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Screens.Edit.Screens.Compose; +using osu.Game.Screens.Edit.Screens.Compose.Components; using OpenTK; namespace osu.Game.Tests.Visual diff --git a/osu.Game.Tests/Visual/TestCaseEditorComposeRadioButtons.cs b/osu.Game.Tests/Visual/TestCaseEditorComposeRadioButtons.cs index 09f390ab74..9df36b0bc1 100644 --- a/osu.Game.Tests/Visual/TestCaseEditorComposeRadioButtons.cs +++ b/osu.Game.Tests/Visual/TestCaseEditorComposeRadioButtons.cs @@ -5,7 +5,7 @@ using System; using System.Collections.Generic; using NUnit.Framework; using osu.Framework.Graphics; -using osu.Game.Screens.Edit.Screens.Compose.RadioButtons; +using osu.Game.Screens.Edit.Components.RadioButtons; namespace osu.Game.Tests.Visual { diff --git a/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs b/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs index 9ad8bf7b92..ef5341ed44 100644 --- a/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs +++ b/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs @@ -13,7 +13,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; using osu.Framework.Timing; using osu.Game.Beatmaps; -using osu.Game.Screens.Edit.Screens.Compose.Timeline; +using osu.Game.Screens.Edit.Screens.Compose.Components.Timeline; using OpenTK.Graphics; namespace osu.Game.Tests.Visual diff --git a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs index 0e337acd2f..6525a7a634 100644 --- a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs +++ b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs @@ -17,7 +17,7 @@ using osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks; using osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks.Components; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Screens.Edit.Screens.Compose; -using osu.Game.Screens.Edit.Screens.Compose.Layers; +using osu.Game.Screens.Edit.Screens.Compose.Components; using osu.Game.Tests.Beatmaps; namespace osu.Game.Tests.Visual diff --git a/osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs b/osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs index 8bd1b79a84..0f1ad197ac 100644 --- a/osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs +++ b/osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs @@ -10,7 +10,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.MathUtils; using osu.Game.Graphics; using osu.Game.Graphics.Cursor; -using osu.Game.Screens.Edit.Screens.Compose.Timeline; +using osu.Game.Screens.Edit.Screens.Compose.Components.Timeline; using OpenTK; using OpenTK.Graphics; diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 64f2648ca1..b515e9a257 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -16,8 +16,8 @@ using osu.Game.Rulesets.Edit.Tools; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.UI; -using osu.Game.Screens.Edit.Screens.Compose.Layers; -using osu.Game.Screens.Edit.Screens.Compose.RadioButtons; +using osu.Game.Screens.Edit.Components.RadioButtons; +using osu.Game.Screens.Edit.Screens.Compose.Components; namespace osu.Game.Rulesets.Edit { diff --git a/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/DrawableRadioButton.cs b/osu.Game/Screens/Edit/Components/RadioButtons/DrawableRadioButton.cs similarity index 98% rename from osu.Game/Screens/Edit/Screens/Compose/RadioButtons/DrawableRadioButton.cs rename to osu.Game/Screens/Edit/Components/RadioButtons/DrawableRadioButton.cs index 2c7e2043fc..22f8417735 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/DrawableRadioButton.cs +++ b/osu.Game/Screens/Edit/Components/RadioButtons/DrawableRadioButton.cs @@ -2,8 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; -using OpenTK; -using OpenTK.Graphics; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -14,8 +12,10 @@ using osu.Framework.Input.Events; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using OpenTK; +using OpenTK.Graphics; -namespace osu.Game.Screens.Edit.Screens.Compose.RadioButtons +namespace osu.Game.Screens.Edit.Components.RadioButtons { public class DrawableRadioButton : TriangleButton { diff --git a/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButton.cs b/osu.Game/Screens/Edit/Components/RadioButtons/RadioButton.cs similarity index 95% rename from osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButton.cs rename to osu.Game/Screens/Edit/Components/RadioButtons/RadioButton.cs index 09fe34bedc..c671fa71c2 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButton.cs +++ b/osu.Game/Screens/Edit/Components/RadioButtons/RadioButton.cs @@ -4,7 +4,7 @@ using System; using osu.Framework.Configuration; -namespace osu.Game.Screens.Edit.Screens.Compose.RadioButtons +namespace osu.Game.Screens.Edit.Components.RadioButtons { public class RadioButton { diff --git a/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButtonCollection.cs b/osu.Game/Screens/Edit/Components/RadioButtons/RadioButtonCollection.cs similarity index 96% rename from osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButtonCollection.cs rename to osu.Game/Screens/Edit/Components/RadioButtons/RadioButtonCollection.cs index 7ba16b3d3e..9bb2e11430 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButtonCollection.cs +++ b/osu.Game/Screens/Edit/Components/RadioButtons/RadioButtonCollection.cs @@ -2,12 +2,12 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System.Collections.Generic; -using OpenTK; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using OpenTK; -namespace osu.Game.Screens.Edit.Screens.Compose.RadioButtons +namespace osu.Game.Screens.Edit.Components.RadioButtons { public class RadioButtonCollection : CompositeDrawable { diff --git a/osu.Game/Screens/Edit/Screens/Compose/BeatDivisorControl.cs b/osu.Game/Screens/Edit/Screens/Compose/Components/BeatDivisorControl.cs similarity index 99% rename from osu.Game/Screens/Edit/Screens/Compose/BeatDivisorControl.cs rename to osu.Game/Screens/Edit/Screens/Compose/Components/BeatDivisorControl.cs index e46be9f7c1..b64bbaf215 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/BeatDivisorControl.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Components/BeatDivisorControl.cs @@ -19,7 +19,7 @@ using OpenTK; using OpenTK.Graphics; using OpenTK.Input; -namespace osu.Game.Screens.Edit.Screens.Compose +namespace osu.Game.Screens.Edit.Screens.Compose.Components { public class BeatDivisorControl : CompositeDrawable { diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/BlueprintContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Components/BlueprintContainer.cs similarity index 99% rename from osu.Game/Screens/Edit/Screens/Compose/Layers/BlueprintContainer.cs rename to osu.Game/Screens/Edit/Screens/Compose/Components/BlueprintContainer.cs index 2d99851b71..079d755318 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Components/BlueprintContainer.cs @@ -14,7 +14,7 @@ using osu.Game.Rulesets.Edit.Tools; using osu.Game.Rulesets.Objects.Drawables; using OpenTK; -namespace osu.Game.Screens.Edit.Screens.Compose.Layers +namespace osu.Game.Screens.Edit.Screens.Compose.Components { public class BlueprintContainer : CompositeDrawable { diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/DragBox.cs b/osu.Game/Screens/Edit/Screens/Compose/Components/DragBox.cs similarity index 97% rename from osu.Game/Screens/Edit/Screens/Compose/Layers/DragBox.cs rename to osu.Game/Screens/Edit/Screens/Compose/Components/DragBox.cs index a97ffc3fcc..d13030d7bb 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/DragBox.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Components/DragBox.cs @@ -10,7 +10,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; using OpenTK.Graphics; -namespace osu.Game.Screens.Edit.Screens.Compose.Layers +namespace osu.Game.Screens.Edit.Screens.Compose.Components { /// /// A box that displays the drag selection and provides selection events for users to handle. diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/EditorPlayfieldBorder.cs b/osu.Game/Screens/Edit/Screens/Compose/Components/EditorPlayfieldBorder.cs similarity index 93% rename from osu.Game/Screens/Edit/Screens/Compose/Layers/EditorPlayfieldBorder.cs rename to osu.Game/Screens/Edit/Screens/Compose/Components/EditorPlayfieldBorder.cs index 22cdfa9328..f1fb3633e2 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/EditorPlayfieldBorder.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Components/EditorPlayfieldBorder.cs @@ -6,7 +6,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using OpenTK.Graphics; -namespace osu.Game.Screens.Edit.Screens.Compose.Layers +namespace osu.Game.Screens.Edit.Screens.Compose.Components { /// /// Provides a border around the playfield. diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/SelectionBox.cs b/osu.Game/Screens/Edit/Screens/Compose/Components/SelectionBox.cs similarity index 98% rename from osu.Game/Screens/Edit/Screens/Compose/Layers/SelectionBox.cs rename to osu.Game/Screens/Edit/Screens/Compose/Components/SelectionBox.cs index 59a7f3094c..95906546db 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/SelectionBox.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Components/SelectionBox.cs @@ -16,7 +16,7 @@ using osu.Game.Rulesets.Edit.Types; using OpenTK; using OpenTK.Input; -namespace osu.Game.Screens.Edit.Screens.Compose.Layers +namespace osu.Game.Screens.Edit.Screens.Compose.Components { /// /// A box which surrounds s and provides interactive handles, context menus etc. diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/CentreMarker.cs b/osu.Game/Screens/Edit/Screens/Compose/Components/Timeline/CentreMarker.cs similarity index 95% rename from osu.Game/Screens/Edit/Screens/Compose/Timeline/CentreMarker.cs rename to osu.Game/Screens/Edit/Screens/Compose/Components/Timeline/CentreMarker.cs index 8e932f307d..c1ba10d5d3 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/CentreMarker.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Components/Timeline/CentreMarker.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using OpenTK; -namespace osu.Game.Screens.Edit.Screens.Compose.Timeline +namespace osu.Game.Screens.Edit.Screens.Compose.Components.Timeline { public class CentreMarker : CompositeDrawable { diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Screens/Compose/Components/Timeline/Timeline.cs similarity index 98% rename from osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs rename to osu.Game/Screens/Edit/Screens/Compose/Components/Timeline/Timeline.cs index da95564975..b27fa5d0c5 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Components/Timeline/Timeline.cs @@ -12,7 +12,7 @@ using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Graphics; -namespace osu.Game.Screens.Edit.Screens.Compose.Timeline +namespace osu.Game.Screens.Edit.Screens.Compose.Components.Timeline { public class Timeline : ZoomableScrollContainer { diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/TimelineArea.cs b/osu.Game/Screens/Edit/Screens/Compose/Components/Timeline/TimelineArea.cs similarity index 98% rename from osu.Game/Screens/Edit/Screens/Compose/Timeline/TimelineArea.cs rename to osu.Game/Screens/Edit/Screens/Compose/Components/Timeline/TimelineArea.cs index ecf760be8e..51a713bc91 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/TimelineArea.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Components/Timeline/TimelineArea.cs @@ -1,14 +1,14 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using OpenTK; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; +using OpenTK; -namespace osu.Game.Screens.Edit.Screens.Compose.Timeline +namespace osu.Game.Screens.Edit.Screens.Compose.Components.Timeline { public class TimelineArea : CompositeDrawable { diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/TimelineButton.cs b/osu.Game/Screens/Edit/Screens/Compose/Components/Timeline/TimelineButton.cs similarity index 95% rename from osu.Game/Screens/Edit/Screens/Compose/Timeline/TimelineButton.cs rename to osu.Game/Screens/Edit/Screens/Compose/Components/Timeline/TimelineButton.cs index 5928fbaa1b..fbabbd54a0 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/TimelineButton.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Components/Timeline/TimelineButton.cs @@ -2,15 +2,15 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; -using OpenTK; -using OpenTK.Graphics; using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; +using OpenTK; +using OpenTK.Graphics; -namespace osu.Game.Screens.Edit.Screens.Compose.Timeline +namespace osu.Game.Screens.Edit.Screens.Compose.Components.Timeline { public class TimelineButton : CompositeDrawable { diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Components/Timeline/ZoomableScrollContainer.cs similarity index 98% rename from osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs rename to osu.Game/Screens/Edit/Screens/Compose/Components/Timeline/ZoomableScrollContainer.cs index bbba439ca7..a85bbb0198 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Components/Timeline/ZoomableScrollContainer.cs @@ -9,7 +9,7 @@ using osu.Framework.Input.Events; using osu.Framework.MathUtils; using OpenTK; -namespace osu.Game.Screens.Edit.Screens.Compose.Timeline +namespace osu.Game.Screens.Edit.Screens.Compose.Components.Timeline { public class ZoomableScrollContainer : ScrollContainer { diff --git a/osu.Game/Screens/Edit/Screens/Compose/Compose.cs b/osu.Game/Screens/Edit/Screens/Compose/Compose.cs index ae42942d24..1e6e9792f3 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Compose.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Compose.cs @@ -11,7 +11,8 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Logging; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; -using osu.Game.Screens.Edit.Screens.Compose.Timeline; +using osu.Game.Screens.Edit.Screens.Compose.Components; +using osu.Game.Screens.Edit.Screens.Compose.Components.Timeline; namespace osu.Game.Screens.Edit.Screens.Compose { From 52f4923c8e71876119b6e62c2779ff1db4d038a7 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 6 Nov 2018 18:28:22 +0900 Subject: [PATCH 094/155] Remove intermediate Screens namespace --- osu.Game.Tests/Visual/TestCaseBeatDivisorControl.cs | 4 ++-- osu.Game.Tests/Visual/TestCaseEditorCompose.cs | 2 +- osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs | 2 +- osu.Game.Tests/Visual/TestCaseEditorMenuBar.cs | 2 +- osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs | 4 ++-- osu.Game.Tests/Visual/TestCaseLabelledTextBox.cs | 2 +- osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs | 2 +- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 2 +- osu.Game/Rulesets/Edit/PlacementBlueprint.cs | 2 +- .../Edit/{Screens/Compose => }/BindableBeatDivisor.cs | 2 +- .../Screens/Edit/{ => Components}/Menus/EditorMenuBar.cs | 7 +++---- .../Edit/{ => Components}/Menus/EditorMenuItem.cs | 2 +- .../Edit/{ => Components}/Menus/EditorMenuItemSpacer.cs | 2 +- .../{ => Components}/Menus/ScreenSelectionTabControl.cs | 5 ++--- .../Compose/Components/BeatDivisorControl.cs | 2 +- .../Compose/Components/BlueprintContainer.cs | 2 +- .../Edit/{Screens => }/Compose/Components/DragBox.cs | 2 +- .../Compose/Components/EditorPlayfieldBorder.cs | 2 +- .../{Screens => }/Compose/Components/SelectionBox.cs | 2 +- .../Compose/Components/Timeline/CentreMarker.cs | 2 +- .../Compose/Components/Timeline/Timeline.cs | 2 +- .../Compose/Components/Timeline/TimelineArea.cs | 2 +- .../Compose/Components/Timeline/TimelineButton.cs | 2 +- .../Components/Timeline/ZoomableScrollContainer.cs | 2 +- osu.Game/Screens/Edit/{Screens => }/Compose/Compose.cs | 8 ++++---- .../Edit/{Screens => }/Compose/IPlacementHandler.cs | 2 +- osu.Game/Screens/Edit/{Screens => }/Design/Design.cs | 2 +- osu.Game/Screens/Edit/Editor.cs | 9 +++------ osu.Game/Screens/Edit/EditorClock.cs | 1 - osu.Game/Screens/Edit/{Screens => }/EditorScreen.cs | 2 +- osu.Game/Screens/Edit/{Screens => }/EditorScreenMode.cs | 2 +- .../Components/LabelledComponents/LabelledTextBox.cs | 4 ++-- osu.Game/Tests/Visual/EditorClockTestCase.cs | 1 - osu.Game/Tests/Visual/EditorTestCase.cs | 1 - osu.Game/Tests/Visual/PlacementBlueprintTestCase.cs | 2 +- 35 files changed, 43 insertions(+), 51 deletions(-) rename osu.Game/Screens/Edit/{Screens/Compose => }/BindableBeatDivisor.cs (96%) rename osu.Game/Screens/Edit/{ => Components}/Menus/EditorMenuBar.cs (98%) rename osu.Game/Screens/Edit/{ => Components}/Menus/EditorMenuItem.cs (92%) rename osu.Game/Screens/Edit/{ => Components}/Menus/EditorMenuItemSpacer.cs (86%) rename osu.Game/Screens/Edit/{ => Components}/Menus/ScreenSelectionTabControl.cs (96%) rename osu.Game/Screens/Edit/{Screens => }/Compose/Components/BeatDivisorControl.cs (99%) rename osu.Game/Screens/Edit/{Screens => }/Compose/Components/BlueprintContainer.cs (99%) rename osu.Game/Screens/Edit/{Screens => }/Compose/Components/DragBox.cs (97%) rename osu.Game/Screens/Edit/{Screens => }/Compose/Components/EditorPlayfieldBorder.cs (93%) rename osu.Game/Screens/Edit/{Screens => }/Compose/Components/SelectionBox.cs (98%) rename osu.Game/Screens/Edit/{Screens => }/Compose/Components/Timeline/CentreMarker.cs (95%) rename osu.Game/Screens/Edit/{Screens => }/Compose/Components/Timeline/Timeline.cs (98%) rename osu.Game/Screens/Edit/{Screens => }/Compose/Components/Timeline/TimelineArea.cs (98%) rename osu.Game/Screens/Edit/{Screens => }/Compose/Components/Timeline/TimelineButton.cs (95%) rename osu.Game/Screens/Edit/{Screens => }/Compose/Components/Timeline/ZoomableScrollContainer.cs (98%) rename osu.Game/Screens/Edit/{Screens => }/Compose/Compose.cs (96%) rename osu.Game/Screens/Edit/{Screens => }/Compose/IPlacementHandler.cs (95%) rename osu.Game/Screens/Edit/{Screens => }/Design/Design.cs (97%) rename osu.Game/Screens/Edit/{Screens => }/EditorScreen.cs (97%) rename osu.Game/Screens/Edit/{Screens => }/EditorScreenMode.cs (91%) rename osu.Game/Screens/Edit/{Screens => }/Setup/Components/LabelledComponents/LabelledTextBox.cs (98%) diff --git a/osu.Game.Tests/Visual/TestCaseBeatDivisorControl.cs b/osu.Game.Tests/Visual/TestCaseBeatDivisorControl.cs index 9709721686..6c607acd11 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatDivisorControl.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatDivisorControl.cs @@ -5,8 +5,8 @@ using System; using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Game.Screens.Edit.Screens.Compose; -using osu.Game.Screens.Edit.Screens.Compose.Components; +using osu.Game.Screens.Edit; +using osu.Game.Screens.Edit.Compose.Components; using OpenTK; namespace osu.Game.Tests.Visual diff --git a/osu.Game.Tests/Visual/TestCaseEditorCompose.cs b/osu.Game.Tests/Visual/TestCaseEditorCompose.cs index e7bcfbf500..3e35ff3289 100644 --- a/osu.Game.Tests/Visual/TestCaseEditorCompose.cs +++ b/osu.Game.Tests/Visual/TestCaseEditorCompose.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; using NUnit.Framework; using osu.Framework.Allocation; using osu.Game.Rulesets.Osu; -using osu.Game.Screens.Edit.Screens.Compose; +using osu.Game.Screens.Edit.Compose; using osu.Game.Tests.Beatmaps; namespace osu.Game.Tests.Visual diff --git a/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs b/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs index ef5341ed44..d2c1127f4c 100644 --- a/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs +++ b/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs @@ -13,7 +13,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; using osu.Framework.Timing; using osu.Game.Beatmaps; -using osu.Game.Screens.Edit.Screens.Compose.Components.Timeline; +using osu.Game.Screens.Edit.Compose.Components.Timeline; using OpenTK.Graphics; namespace osu.Game.Tests.Visual diff --git a/osu.Game.Tests/Visual/TestCaseEditorMenuBar.cs b/osu.Game.Tests/Visual/TestCaseEditorMenuBar.cs index cb4438b2ba..eab799011d 100644 --- a/osu.Game.Tests/Visual/TestCaseEditorMenuBar.cs +++ b/osu.Game.Tests/Visual/TestCaseEditorMenuBar.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics.UserInterface; -using osu.Game.Screens.Edit.Menus; +using osu.Game.Screens.Edit.Components.Menus; namespace osu.Game.Tests.Visual { diff --git a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs index 6525a7a634..ae9a28fcaf 100644 --- a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs +++ b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs @@ -16,8 +16,8 @@ using osu.Game.Rulesets.Osu.Edit; using osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks; using osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks.Components; using osu.Game.Rulesets.Osu.Objects; -using osu.Game.Screens.Edit.Screens.Compose; -using osu.Game.Screens.Edit.Screens.Compose.Components; +using osu.Game.Screens.Edit.Compose; +using osu.Game.Screens.Edit.Compose.Components; using osu.Game.Tests.Beatmaps; namespace osu.Game.Tests.Visual diff --git a/osu.Game.Tests/Visual/TestCaseLabelledTextBox.cs b/osu.Game.Tests/Visual/TestCaseLabelledTextBox.cs index d41739bfb5..e1470a860e 100644 --- a/osu.Game.Tests/Visual/TestCaseLabelledTextBox.cs +++ b/osu.Game.Tests/Visual/TestCaseLabelledTextBox.cs @@ -5,9 +5,9 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Screens.Edit.Screens.Setup.Components.LabelledComponents; using System; using System.Collections.Generic; +using osu.Game.Screens.Edit.Setup.Components.LabelledComponents; namespace osu.Game.Tests.Visual { diff --git a/osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs b/osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs index 0f1ad197ac..3bf809ebde 100644 --- a/osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs +++ b/osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs @@ -10,7 +10,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.MathUtils; using osu.Game.Graphics; using osu.Game.Graphics.Cursor; -using osu.Game.Screens.Edit.Screens.Compose.Components.Timeline; +using osu.Game.Screens.Edit.Compose.Components.Timeline; using OpenTK; using OpenTK.Graphics; diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index b515e9a257..485c1921cf 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -17,7 +17,7 @@ using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.UI; using osu.Game.Screens.Edit.Components.RadioButtons; -using osu.Game.Screens.Edit.Screens.Compose.Components; +using osu.Game.Screens.Edit.Compose.Components; namespace osu.Game.Rulesets.Edit { diff --git a/osu.Game/Rulesets/Edit/PlacementBlueprint.cs b/osu.Game/Rulesets/Edit/PlacementBlueprint.cs index fe27d37640..b726b683ea 100644 --- a/osu.Game/Rulesets/Edit/PlacementBlueprint.cs +++ b/osu.Game/Rulesets/Edit/PlacementBlueprint.cs @@ -10,7 +10,7 @@ using osu.Framework.Input.Events; using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Rulesets.Objects; -using osu.Game.Screens.Edit.Screens.Compose; +using osu.Game.Screens.Edit.Compose; using OpenTK; namespace osu.Game.Rulesets.Edit diff --git a/osu.Game/Screens/Edit/Screens/Compose/BindableBeatDivisor.cs b/osu.Game/Screens/Edit/BindableBeatDivisor.cs similarity index 96% rename from osu.Game/Screens/Edit/Screens/Compose/BindableBeatDivisor.cs rename to osu.Game/Screens/Edit/BindableBeatDivisor.cs index b7dce8c96e..3124482c73 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/BindableBeatDivisor.cs +++ b/osu.Game/Screens/Edit/BindableBeatDivisor.cs @@ -5,7 +5,7 @@ using System; using System.Linq; using osu.Framework.Configuration; -namespace osu.Game.Screens.Edit.Screens.Compose +namespace osu.Game.Screens.Edit { public class BindableBeatDivisor : BindableNumber { diff --git a/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs b/osu.Game/Screens/Edit/Components/Menus/EditorMenuBar.cs similarity index 98% rename from osu.Game/Screens/Edit/Menus/EditorMenuBar.cs rename to osu.Game/Screens/Edit/Components/Menus/EditorMenuBar.cs index af0a7b6694..4b5c13efbd 100644 --- a/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs +++ b/osu.Game/Screens/Edit/Components/Menus/EditorMenuBar.cs @@ -2,19 +2,18 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Allocation; +using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input.Events; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; using OpenTK; using OpenTK.Graphics; -using osu.Framework.Configuration; -using osu.Framework.Input.Events; -using osu.Game.Screens.Edit.Screens; -namespace osu.Game.Screens.Edit.Menus +namespace osu.Game.Screens.Edit.Components.Menus { public class EditorMenuBar : OsuMenu { diff --git a/osu.Game/Screens/Edit/Menus/EditorMenuItem.cs b/osu.Game/Screens/Edit/Components/Menus/EditorMenuItem.cs similarity index 92% rename from osu.Game/Screens/Edit/Menus/EditorMenuItem.cs rename to osu.Game/Screens/Edit/Components/Menus/EditorMenuItem.cs index 0ef1ad8c6b..1c9253cce7 100644 --- a/osu.Game/Screens/Edit/Menus/EditorMenuItem.cs +++ b/osu.Game/Screens/Edit/Components/Menus/EditorMenuItem.cs @@ -4,7 +4,7 @@ using System; using osu.Game.Graphics.UserInterface; -namespace osu.Game.Screens.Edit.Menus +namespace osu.Game.Screens.Edit.Components.Menus { public class EditorMenuItem : OsuMenuItem { diff --git a/osu.Game/Screens/Edit/Menus/EditorMenuItemSpacer.cs b/osu.Game/Screens/Edit/Components/Menus/EditorMenuItemSpacer.cs similarity index 86% rename from osu.Game/Screens/Edit/Menus/EditorMenuItemSpacer.cs rename to osu.Game/Screens/Edit/Components/Menus/EditorMenuItemSpacer.cs index 91b40a2cfb..17ee88241e 100644 --- a/osu.Game/Screens/Edit/Menus/EditorMenuItemSpacer.cs +++ b/osu.Game/Screens/Edit/Components/Menus/EditorMenuItemSpacer.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 -namespace osu.Game.Screens.Edit.Menus +namespace osu.Game.Screens.Edit.Components.Menus { public class EditorMenuItemSpacer : EditorMenuItem { diff --git a/osu.Game/Screens/Edit/Menus/ScreenSelectionTabControl.cs b/osu.Game/Screens/Edit/Components/Menus/ScreenSelectionTabControl.cs similarity index 96% rename from osu.Game/Screens/Edit/Menus/ScreenSelectionTabControl.cs rename to osu.Game/Screens/Edit/Components/Menus/ScreenSelectionTabControl.cs index f58e5b39eb..4ff01c0f90 100644 --- a/osu.Game/Screens/Edit/Menus/ScreenSelectionTabControl.cs +++ b/osu.Game/Screens/Edit/Components/Menus/ScreenSelectionTabControl.cs @@ -1,7 +1,6 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using OpenTK.Graphics; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -9,10 +8,10 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; -using osu.Game.Screens.Edit.Screens; using OpenTK; +using OpenTK.Graphics; -namespace osu.Game.Screens.Edit.Menus +namespace osu.Game.Screens.Edit.Components.Menus { public class ScreenSelectionTabControl : OsuTabControl { diff --git a/osu.Game/Screens/Edit/Screens/Compose/Components/BeatDivisorControl.cs b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs similarity index 99% rename from osu.Game/Screens/Edit/Screens/Compose/Components/BeatDivisorControl.cs rename to osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs index b64bbaf215..a5a1f590bf 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Components/BeatDivisorControl.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs @@ -19,7 +19,7 @@ using OpenTK; using OpenTK.Graphics; using OpenTK.Input; -namespace osu.Game.Screens.Edit.Screens.Compose.Components +namespace osu.Game.Screens.Edit.Compose.Components { public class BeatDivisorControl : CompositeDrawable { diff --git a/osu.Game/Screens/Edit/Screens/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs similarity index 99% rename from osu.Game/Screens/Edit/Screens/Compose/Components/BlueprintContainer.cs rename to osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index 079d755318..45003545a3 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -14,7 +14,7 @@ using osu.Game.Rulesets.Edit.Tools; using osu.Game.Rulesets.Objects.Drawables; using OpenTK; -namespace osu.Game.Screens.Edit.Screens.Compose.Components +namespace osu.Game.Screens.Edit.Compose.Components { public class BlueprintContainer : CompositeDrawable { diff --git a/osu.Game/Screens/Edit/Screens/Compose/Components/DragBox.cs b/osu.Game/Screens/Edit/Compose/Components/DragBox.cs similarity index 97% rename from osu.Game/Screens/Edit/Screens/Compose/Components/DragBox.cs rename to osu.Game/Screens/Edit/Compose/Components/DragBox.cs index d13030d7bb..1a58f476ac 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Components/DragBox.cs +++ b/osu.Game/Screens/Edit/Compose/Components/DragBox.cs @@ -10,7 +10,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; using OpenTK.Graphics; -namespace osu.Game.Screens.Edit.Screens.Compose.Components +namespace osu.Game.Screens.Edit.Compose.Components { /// /// A box that displays the drag selection and provides selection events for users to handle. diff --git a/osu.Game/Screens/Edit/Screens/Compose/Components/EditorPlayfieldBorder.cs b/osu.Game/Screens/Edit/Compose/Components/EditorPlayfieldBorder.cs similarity index 93% rename from osu.Game/Screens/Edit/Screens/Compose/Components/EditorPlayfieldBorder.cs rename to osu.Game/Screens/Edit/Compose/Components/EditorPlayfieldBorder.cs index f1fb3633e2..4956b7759f 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Components/EditorPlayfieldBorder.cs +++ b/osu.Game/Screens/Edit/Compose/Components/EditorPlayfieldBorder.cs @@ -6,7 +6,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using OpenTK.Graphics; -namespace osu.Game.Screens.Edit.Screens.Compose.Components +namespace osu.Game.Screens.Edit.Compose.Components { /// /// Provides a border around the playfield. diff --git a/osu.Game/Screens/Edit/Screens/Compose/Components/SelectionBox.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs similarity index 98% rename from osu.Game/Screens/Edit/Screens/Compose/Components/SelectionBox.cs rename to osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs index 95906546db..e2a70a9ee7 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Components/SelectionBox.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs @@ -16,7 +16,7 @@ using osu.Game.Rulesets.Edit.Types; using OpenTK; using OpenTK.Input; -namespace osu.Game.Screens.Edit.Screens.Compose.Components +namespace osu.Game.Screens.Edit.Compose.Components { /// /// A box which surrounds s and provides interactive handles, context menus etc. diff --git a/osu.Game/Screens/Edit/Screens/Compose/Components/Timeline/CentreMarker.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/CentreMarker.cs similarity index 95% rename from osu.Game/Screens/Edit/Screens/Compose/Components/Timeline/CentreMarker.cs rename to osu.Game/Screens/Edit/Compose/Components/Timeline/CentreMarker.cs index c1ba10d5d3..b2c6f02058 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Components/Timeline/CentreMarker.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/CentreMarker.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using OpenTK; -namespace osu.Game.Screens.Edit.Screens.Compose.Components.Timeline +namespace osu.Game.Screens.Edit.Compose.Components.Timeline { public class CentreMarker : CompositeDrawable { diff --git a/osu.Game/Screens/Edit/Screens/Compose/Components/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs similarity index 98% rename from osu.Game/Screens/Edit/Screens/Compose/Components/Timeline/Timeline.cs rename to osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs index b27fa5d0c5..0c626f2c54 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Components/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs @@ -12,7 +12,7 @@ using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Graphics; -namespace osu.Game.Screens.Edit.Screens.Compose.Components.Timeline +namespace osu.Game.Screens.Edit.Compose.Components.Timeline { public class Timeline : ZoomableScrollContainer { diff --git a/osu.Game/Screens/Edit/Screens/Compose/Components/Timeline/TimelineArea.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineArea.cs similarity index 98% rename from osu.Game/Screens/Edit/Screens/Compose/Components/Timeline/TimelineArea.cs rename to osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineArea.cs index 51a713bc91..5b98140a3b 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Components/Timeline/TimelineArea.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineArea.cs @@ -8,7 +8,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; using OpenTK; -namespace osu.Game.Screens.Edit.Screens.Compose.Components.Timeline +namespace osu.Game.Screens.Edit.Compose.Components.Timeline { public class TimelineArea : CompositeDrawable { diff --git a/osu.Game/Screens/Edit/Screens/Compose/Components/Timeline/TimelineButton.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineButton.cs similarity index 95% rename from osu.Game/Screens/Edit/Screens/Compose/Components/Timeline/TimelineButton.cs rename to osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineButton.cs index fbabbd54a0..d481934347 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Components/Timeline/TimelineButton.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineButton.cs @@ -10,7 +10,7 @@ using osu.Game.Graphics.UserInterface; using OpenTK; using OpenTK.Graphics; -namespace osu.Game.Screens.Edit.Screens.Compose.Components.Timeline +namespace osu.Game.Screens.Edit.Compose.Components.Timeline { public class TimelineButton : CompositeDrawable { diff --git a/osu.Game/Screens/Edit/Screens/Compose/Components/Timeline/ZoomableScrollContainer.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs similarity index 98% rename from osu.Game/Screens/Edit/Screens/Compose/Components/Timeline/ZoomableScrollContainer.cs rename to osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs index a85bbb0198..8d39f61d89 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Components/Timeline/ZoomableScrollContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs @@ -9,7 +9,7 @@ using osu.Framework.Input.Events; using osu.Framework.MathUtils; using OpenTK; -namespace osu.Game.Screens.Edit.Screens.Compose.Components.Timeline +namespace osu.Game.Screens.Edit.Compose.Components.Timeline { public class ZoomableScrollContainer : ScrollContainer { diff --git a/osu.Game/Screens/Edit/Screens/Compose/Compose.cs b/osu.Game/Screens/Edit/Compose/Compose.cs similarity index 96% rename from osu.Game/Screens/Edit/Screens/Compose/Compose.cs rename to osu.Game/Screens/Edit/Compose/Compose.cs index 1e6e9792f3..f11bd89ec5 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Compose.cs +++ b/osu.Game/Screens/Edit/Compose/Compose.cs @@ -3,7 +3,6 @@ using JetBrains.Annotations; using osu.Framework.Allocation; -using OpenTK.Graphics; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -11,10 +10,11 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Logging; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; -using osu.Game.Screens.Edit.Screens.Compose.Components; -using osu.Game.Screens.Edit.Screens.Compose.Components.Timeline; +using osu.Game.Screens.Edit.Compose.Components; +using osu.Game.Screens.Edit.Compose.Components.Timeline; +using OpenTK.Graphics; -namespace osu.Game.Screens.Edit.Screens.Compose +namespace osu.Game.Screens.Edit.Compose { [Cached(Type = typeof(IPlacementHandler))] public class Compose : EditorScreen, IPlacementHandler diff --git a/osu.Game/Screens/Edit/Screens/Compose/IPlacementHandler.cs b/osu.Game/Screens/Edit/Compose/IPlacementHandler.cs similarity index 95% rename from osu.Game/Screens/Edit/Screens/Compose/IPlacementHandler.cs rename to osu.Game/Screens/Edit/Compose/IPlacementHandler.cs index cd213c2885..f93b294536 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/IPlacementHandler.cs +++ b/osu.Game/Screens/Edit/Compose/IPlacementHandler.cs @@ -3,7 +3,7 @@ using osu.Game.Rulesets.Objects; -namespace osu.Game.Screens.Edit.Screens.Compose +namespace osu.Game.Screens.Edit.Compose { public interface IPlacementHandler { diff --git a/osu.Game/Screens/Edit/Screens/Design/Design.cs b/osu.Game/Screens/Edit/Design/Design.cs similarity index 97% rename from osu.Game/Screens/Edit/Screens/Design/Design.cs rename to osu.Game/Screens/Edit/Design/Design.cs index 052a1c1d90..4204286f9a 100644 --- a/osu.Game/Screens/Edit/Screens/Design/Design.cs +++ b/osu.Game/Screens/Edit/Design/Design.cs @@ -7,7 +7,7 @@ using osu.Framework.Graphics.Shapes; using osu.Game.Graphics.Sprites; using OpenTK.Graphics; -namespace osu.Game.Screens.Edit.Screens.Design +namespace osu.Game.Screens.Edit.Design { public class Design : EditorScreen { diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 62cf76ef69..19211e82aa 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -8,7 +8,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; -using osu.Game.Screens.Edit.Menus; using osu.Game.Screens.Edit.Components.Timelines.Summary; using osu.Framework.Allocation; using osu.Framework.Graphics.UserInterface; @@ -16,10 +15,8 @@ using osu.Framework.Input.Events; using osu.Framework.Platform; using osu.Framework.Timing; using osu.Game.Graphics.UserInterface; -using osu.Game.Screens.Edit.Screens; -using osu.Game.Screens.Edit.Screens.Compose; -using osu.Game.Screens.Edit.Screens.Design; using osu.Game.Screens.Edit.Components; +using osu.Game.Screens.Edit.Components.Menus; namespace osu.Game.Screens.Edit { @@ -169,10 +166,10 @@ namespace osu.Game.Screens.Edit switch (mode) { case EditorScreenMode.Compose: - currentScreen = new Compose(); + currentScreen = new Compose.Compose(); break; case EditorScreenMode.Design: - currentScreen = new Design(); + currentScreen = new Design.Design(); break; default: currentScreen = new EditorScreen(); diff --git a/osu.Game/Screens/Edit/EditorClock.cs b/osu.Game/Screens/Edit/EditorClock.cs index 1c40181ec9..5fa29d6005 100644 --- a/osu.Game/Screens/Edit/EditorClock.cs +++ b/osu.Game/Screens/Edit/EditorClock.cs @@ -7,7 +7,6 @@ using osu.Framework.MathUtils; using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Screens.Edit.Screens.Compose; using OpenTK; namespace osu.Game.Screens.Edit diff --git a/osu.Game/Screens/Edit/Screens/EditorScreen.cs b/osu.Game/Screens/Edit/EditorScreen.cs similarity index 97% rename from osu.Game/Screens/Edit/Screens/EditorScreen.cs rename to osu.Game/Screens/Edit/EditorScreen.cs index f8402b9a9f..3a8fc3ef80 100644 --- a/osu.Game/Screens/Edit/Screens/EditorScreen.cs +++ b/osu.Game/Screens/Edit/EditorScreen.cs @@ -7,7 +7,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; -namespace osu.Game.Screens.Edit.Screens +namespace osu.Game.Screens.Edit { /// /// TODO: eventually make this inherit Screen and add a local scren stack inside the Editor. diff --git a/osu.Game/Screens/Edit/Screens/EditorScreenMode.cs b/osu.Game/Screens/Edit/EditorScreenMode.cs similarity index 91% rename from osu.Game/Screens/Edit/Screens/EditorScreenMode.cs rename to osu.Game/Screens/Edit/EditorScreenMode.cs index be8363680d..17de6c4125 100644 --- a/osu.Game/Screens/Edit/Screens/EditorScreenMode.cs +++ b/osu.Game/Screens/Edit/EditorScreenMode.cs @@ -3,7 +3,7 @@ using System.ComponentModel; -namespace osu.Game.Screens.Edit.Screens +namespace osu.Game.Screens.Edit { public enum EditorScreenMode { diff --git a/osu.Game/Screens/Edit/Screens/Setup/Components/LabelledComponents/LabelledTextBox.cs b/osu.Game/Screens/Edit/Setup/Components/LabelledComponents/LabelledTextBox.cs similarity index 98% rename from osu.Game/Screens/Edit/Screens/Setup/Components/LabelledComponents/LabelledTextBox.cs rename to osu.Game/Screens/Edit/Setup/Components/LabelledComponents/LabelledTextBox.cs index 94200b7f4e..626c59981c 100644 --- a/osu.Game/Screens/Edit/Screens/Setup/Components/LabelledComponents/LabelledTextBox.cs +++ b/osu.Game/Screens/Edit/Setup/Components/LabelledComponents/LabelledTextBox.cs @@ -2,7 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Allocation; -using OpenTK.Graphics; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -10,8 +9,9 @@ using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using OpenTK.Graphics; -namespace osu.Game.Screens.Edit.Screens.Setup.Components.LabelledComponents +namespace osu.Game.Screens.Edit.Setup.Components.LabelledComponents { public class LabelledTextBox : CompositeDrawable { diff --git a/osu.Game/Tests/Visual/EditorClockTestCase.cs b/osu.Game/Tests/Visual/EditorClockTestCase.cs index ebede74171..479ed385e2 100644 --- a/osu.Game/Tests/Visual/EditorClockTestCase.cs +++ b/osu.Game/Tests/Visual/EditorClockTestCase.cs @@ -7,7 +7,6 @@ using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Screens.Edit; -using osu.Game.Screens.Edit.Screens.Compose; namespace osu.Game.Tests.Visual { diff --git a/osu.Game/Tests/Visual/EditorTestCase.cs b/osu.Game/Tests/Visual/EditorTestCase.cs index 2ab121fcc9..2d02509b58 100644 --- a/osu.Game/Tests/Visual/EditorTestCase.cs +++ b/osu.Game/Tests/Visual/EditorTestCase.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using osu.Framework.Allocation; using osu.Game.Rulesets; using osu.Game.Screens.Edit; -using osu.Game.Screens.Edit.Screens; using osu.Game.Tests.Beatmaps; namespace osu.Game.Tests.Visual diff --git a/osu.Game/Tests/Visual/PlacementBlueprintTestCase.cs b/osu.Game/Tests/Visual/PlacementBlueprintTestCase.cs index 6cc8408998..5c6cb96e44 100644 --- a/osu.Game/Tests/Visual/PlacementBlueprintTestCase.cs +++ b/osu.Game/Tests/Visual/PlacementBlueprintTestCase.cs @@ -8,7 +8,7 @@ using osu.Framework.Timing; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; -using osu.Game.Screens.Edit.Screens.Compose; +using osu.Game.Screens.Edit.Compose; namespace osu.Game.Tests.Visual { From 7f73fc2d39d731466b311a16be832ecc1cd75ea3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 7 Nov 2018 01:47:02 +0900 Subject: [PATCH 095/155] Require holding back button to quit gameplay Avoids accidental presses and streamlines logic with on-screen element. --- ...Button.cs => TestCaseHoldForMenuButton.cs} | 14 ++++---- .../{QuitButton.cs => HoldForMenuButton.cs} | 32 +++++++++++++++++-- osu.Game/Screens/Play/HUDOverlay.cs | 6 ++-- osu.Game/Screens/Play/Player.cs | 2 ++ 4 files changed, 41 insertions(+), 13 deletions(-) rename osu.Game.Tests/Visual/{TestCaseQuitButton.cs => TestCaseHoldForMenuButton.cs} (76%) rename osu.Game/Screens/Play/HUD/{QuitButton.cs => HoldForMenuButton.cs} (88%) diff --git a/osu.Game.Tests/Visual/TestCaseQuitButton.cs b/osu.Game.Tests/Visual/TestCaseHoldForMenuButton.cs similarity index 76% rename from osu.Game.Tests/Visual/TestCaseQuitButton.cs rename to osu.Game.Tests/Visual/TestCaseHoldForMenuButton.cs index a427b7a20a..019472f127 100644 --- a/osu.Game.Tests/Visual/TestCaseQuitButton.cs +++ b/osu.Game.Tests/Visual/TestCaseHoldForMenuButton.cs @@ -13,25 +13,25 @@ using OpenTK.Input; namespace osu.Game.Tests.Visual { [Description("'Hold to Quit' UI element")] - public class TestCaseQuitButton : ManualInputManagerTestCase + public class TestCaseHoldForMenuButton : ManualInputManagerTestCase { private bool exitAction; [BackgroundDependencyLoader] private void load() { - QuitButton quitButton; + HoldForMenuButton holdForMenuButton; - Add(quitButton = new QuitButton + Add(holdForMenuButton = new HoldForMenuButton { Origin = Anchor.BottomRight, Anchor = Anchor.BottomRight, Action = () => exitAction = true }); - var text = quitButton.Children.OfType().First(); + var text = holdForMenuButton.Children.OfType().First(); - AddStep("Trigger text fade in", () => InputManager.MoveMouseTo(quitButton)); + AddStep("Trigger text fade in", () => InputManager.MoveMouseTo(holdForMenuButton)); AddUntilStep(() => text.IsPresent && !exitAction, "Text visible"); AddStep("Trigger text fade out", () => InputManager.MoveMouseTo(Vector2.One)); AddUntilStep(() => !text.IsPresent && !exitAction, "Text is not visible"); @@ -39,7 +39,7 @@ namespace osu.Game.Tests.Visual AddStep("Trigger exit action", () => { exitAction = false; - InputManager.MoveMouseTo(quitButton); + InputManager.MoveMouseTo(holdForMenuButton); InputManager.PressButton(MouseButton.Left); }); @@ -47,7 +47,7 @@ namespace osu.Game.Tests.Visual AddAssert("action not triggered", () => !exitAction); AddStep("Trigger exit action", () => InputManager.PressButton(MouseButton.Left)); - AddUntilStep(() => exitAction, $"{nameof(quitButton.Action)} was triggered"); + AddUntilStep(() => exitAction, $"{nameof(holdForMenuButton.Action)} was triggered"); } } } diff --git a/osu.Game/Screens/Play/HUD/QuitButton.cs b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs similarity index 88% rename from osu.Game/Screens/Play/HUD/QuitButton.cs rename to osu.Game/Screens/Play/HUD/HoldForMenuButton.cs index 88547e0169..01f4551689 100644 --- a/osu.Game/Screens/Play/HUD/QuitButton.cs +++ b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs @@ -8,16 +8,18 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Framework.MathUtils; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; +using osu.Game.Input.Bindings; using OpenTK; namespace osu.Game.Screens.Play.HUD { - public class QuitButton : FillFlowContainer + public class HoldForMenuButton : FillFlowContainer { public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; @@ -30,7 +32,7 @@ namespace osu.Game.Screens.Play.HUD private readonly OsuSpriteText text; - public QuitButton() + public HoldForMenuButton() { Direction = FillDirection.Horizontal; Spacing = new Vector2(20, 0); @@ -79,7 +81,7 @@ namespace osu.Game.Screens.Play.HUD Alpha, MathHelper.Clamp(1 - positionalAdjust, 0.04f, 1), 0, 200, Easing.OutQuint); } - private class Button : HoldToConfirmContainer + private class Button : HoldToConfirmContainer, IKeyBindingHandler { private SpriteIcon icon; private CircularProgress circularProgress; @@ -90,6 +92,30 @@ namespace osu.Game.Screens.Play.HUD public Action HoverGained; public Action HoverLost; + public bool OnPressed(GlobalAction action) + { + switch (action) + { + case GlobalAction.Back: + BeginConfirm(); + return true; + } + + return false; + } + + public bool OnReleased(GlobalAction action) + { + switch (action) + { + case GlobalAction.Back: + AbortConfirm(); + return true; + } + + return false; + } + [BackgroundDependencyLoader] private void load(OsuColour colours) { diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 0f9f4fc20a..93d92d062d 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -34,7 +34,7 @@ namespace osu.Game.Screens.Play public readonly HealthDisplay HealthDisplay; public readonly SongProgress Progress; public readonly ModDisplay ModDisplay; - public readonly QuitButton HoldToQuit; + public readonly HoldForMenuButton HoldToQuit; public readonly PlayerSettingsOverlay PlayerSettingsOverlay; private Bindable showHud; @@ -69,7 +69,7 @@ namespace osu.Game.Screens.Play Children = new Drawable[] { KeyCounter = CreateKeyCounter(adjustableClock as IFrameBasedClock), - HoldToQuit = CreateQuitButton(), + HoldToQuit = CreateHoldForMenuButton(), } } } @@ -219,7 +219,7 @@ namespace osu.Game.Screens.Play RelativeSizeAxes = Axes.X, }; - protected virtual QuitButton CreateQuitButton() => new QuitButton + protected virtual HoldForMenuButton CreateHoldForMenuButton() => new HoldForMenuButton { Anchor = Anchor.BottomRight, Origin = Anchor.BottomRight, diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index b3cbeb3850..a220a05971 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -35,6 +35,8 @@ namespace osu.Game.Screens.Play { public class Player : ScreenWithBeatmapBackground, IProvideCursor { + protected override bool AllowBackButton => false; // handled by HoldForMenuButton + protected override float BackgroundParallaxAmount => 0.1f; protected override bool HideOverlaysOnEnter => true; From e9e50f41fbb0f9183d3683050dd0c3292cc9572c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 7 Nov 2018 13:04:17 +0900 Subject: [PATCH 096/155] Use Name/NameScreen format --- osu.Game.Tests/Visual/TestCaseEditorCompose.cs | 4 ++-- .../Screens/Edit/Compose/{Compose.cs => ComposeScreen.cs} | 2 +- osu.Game/Screens/Edit/Design/{Design.cs => DesignScreen.cs} | 4 ++-- osu.Game/Screens/Edit/Editor.cs | 6 ++++-- 4 files changed, 9 insertions(+), 7 deletions(-) rename osu.Game/Screens/Edit/Compose/{Compose.cs => ComposeScreen.cs} (98%) rename osu.Game/Screens/Edit/Design/{Design.cs => DesignScreen.cs} (95%) diff --git a/osu.Game.Tests/Visual/TestCaseEditorCompose.cs b/osu.Game.Tests/Visual/TestCaseEditorCompose.cs index 3e35ff3289..5c53fdfac4 100644 --- a/osu.Game.Tests/Visual/TestCaseEditorCompose.cs +++ b/osu.Game.Tests/Visual/TestCaseEditorCompose.cs @@ -14,13 +14,13 @@ namespace osu.Game.Tests.Visual [TestFixture] public class TestCaseEditorCompose : EditorClockTestCase { - public override IReadOnlyList RequiredTypes => new[] { typeof(Compose) }; + public override IReadOnlyList RequiredTypes => new[] { typeof(ComposeScreen) }; [BackgroundDependencyLoader] private void load() { Beatmap.Value = new TestWorkingBeatmap(new OsuRuleset().RulesetInfo); - Child = new Compose(); + Child = new ComposeScreen(); } } } diff --git a/osu.Game/Screens/Edit/Compose/Compose.cs b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs similarity index 98% rename from osu.Game/Screens/Edit/Compose/Compose.cs rename to osu.Game/Screens/Edit/Compose/ComposeScreen.cs index f11bd89ec5..30962d5536 100644 --- a/osu.Game/Screens/Edit/Compose/Compose.cs +++ b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs @@ -17,7 +17,7 @@ using OpenTK.Graphics; namespace osu.Game.Screens.Edit.Compose { [Cached(Type = typeof(IPlacementHandler))] - public class Compose : EditorScreen, IPlacementHandler + public class ComposeScreen : EditorScreen, IPlacementHandler { private const float vertical_margins = 10; private const float horizontal_margins = 20; diff --git a/osu.Game/Screens/Edit/Design/Design.cs b/osu.Game/Screens/Edit/Design/DesignScreen.cs similarity index 95% rename from osu.Game/Screens/Edit/Design/Design.cs rename to osu.Game/Screens/Edit/Design/DesignScreen.cs index 4204286f9a..e99e352653 100644 --- a/osu.Game/Screens/Edit/Design/Design.cs +++ b/osu.Game/Screens/Edit/Design/DesignScreen.cs @@ -9,9 +9,9 @@ using OpenTK.Graphics; namespace osu.Game.Screens.Edit.Design { - public class Design : EditorScreen + public class DesignScreen : EditorScreen { - public Design() + public DesignScreen() { Add(new Container { diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 19211e82aa..524f049284 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -17,6 +17,8 @@ using osu.Framework.Timing; using osu.Game.Graphics.UserInterface; using osu.Game.Screens.Edit.Components; using osu.Game.Screens.Edit.Components.Menus; +using osu.Game.Screens.Edit.Compose; +using osu.Game.Screens.Edit.Design; namespace osu.Game.Screens.Edit { @@ -166,10 +168,10 @@ namespace osu.Game.Screens.Edit switch (mode) { case EditorScreenMode.Compose: - currentScreen = new Compose.Compose(); + currentScreen = new ComposeScreen(); break; case EditorScreenMode.Design: - currentScreen = new Design.Design(); + currentScreen = new DesignScreen(); break; default: currentScreen = new EditorScreen(); From 4277cb0d59a40d6940ad6a003ec8f2a7df8bd878 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 7 Nov 2018 15:04:48 +0900 Subject: [PATCH 097/155] Adjust some missed renames --- .../TestCaseHitCirclePlacementBlueprint.cs | 2 +- .../TestCaseHitCircleSelectionBlueprint.cs | 2 +- .../TestCaseSliderPlacementBlueprint.cs | 2 +- .../TestCaseSliderSelectionBlueprint.cs | 2 +- .../TestCaseSpinnerPlacementBlueprint.cs | 2 +- .../TestCaseSpinnerSelectionBlueprint.cs | 2 +- osu.Game/Tests/Visual/PlacementBlueprintTestCase.cs | 6 +++--- osu.Game/Tests/Visual/SelectionBlueprintTestCase.cs | 4 ++-- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseHitCirclePlacementBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseHitCirclePlacementBlueprint.cs index 3aaccb3c45..06ff2cf186 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseHitCirclePlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseHitCirclePlacementBlueprint.cs @@ -14,6 +14,6 @@ namespace osu.Game.Rulesets.Osu.Tests public class TestCaseHitCirclePlacementBlueprint : PlacementBlueprintTestCase { protected override DrawableHitObject CreateHitObject(HitObject hitObject) => new DrawableHitCircle((HitCircle)hitObject); - protected override PlacementBlueprint CreateMask() => new HitCirclePlacementBlueprint(); + protected override PlacementBlueprint CreateBlueprint() => new HitCirclePlacementBlueprint(); } } diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleSelectionBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleSelectionBlueprint.cs index 843b6e83f2..674a7bdc3f 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleSelectionBlueprint.cs @@ -24,6 +24,6 @@ namespace osu.Game.Rulesets.Osu.Tests Add(drawableObject = new DrawableHitCircle(hitCircle)); } - protected override SelectionBlueprint CreateMask() => new HitCircleSelectionBlueprint(drawableObject); + protected override SelectionBlueprint CreateBlueprint() => new HitCircleSelectionBlueprint(drawableObject); } } diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderPlacementBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSliderPlacementBlueprint.cs index 43f2718c9a..97decfe114 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSliderPlacementBlueprint.cs @@ -14,6 +14,6 @@ namespace osu.Game.Rulesets.Osu.Tests public class TestCaseSliderPlacementBlueprint : PlacementBlueprintTestCase { protected override DrawableHitObject CreateHitObject(HitObject hitObject) => new DrawableSlider((Slider)hitObject); - protected override PlacementBlueprint CreateMask() => new SliderPlacementBlueprint(); + protected override PlacementBlueprint CreateBlueprint() => new SliderPlacementBlueprint(); } } diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionBlueprint.cs index 43c11b4441..ae16d90601 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionBlueprint.cs @@ -50,6 +50,6 @@ namespace osu.Game.Rulesets.Osu.Tests Add(drawableObject = new DrawableSlider(slider)); } - protected override SelectionBlueprint CreateMask() => new SliderSelectionBlueprint(drawableObject); + protected override SelectionBlueprint CreateBlueprint() => new SliderSelectionBlueprint(drawableObject); } } diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerPlacementBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerPlacementBlueprint.cs index 4b1dc62452..2abcb2d161 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerPlacementBlueprint.cs @@ -15,6 +15,6 @@ namespace osu.Game.Rulesets.Osu.Tests { protected override DrawableHitObject CreateHitObject(HitObject hitObject) => new DrawableSpinner((Spinner)hitObject); - protected override PlacementBlueprint CreateMask() => new SpinnerPlacementBlueprint(); + protected override PlacementBlueprint CreateBlueprint() => new SpinnerPlacementBlueprint(); } } diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerSelectionBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerSelectionBlueprint.cs index f94939b585..d8a0eb6796 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerSelectionBlueprint.cs @@ -45,6 +45,6 @@ namespace osu.Game.Rulesets.Osu.Tests }); } - protected override SelectionBlueprint CreateMask() => new SpinnerSelectionBlueprint(drawableSpinner) { Size = new Vector2(0.5f) }; + protected override SelectionBlueprint CreateBlueprint() => new SpinnerSelectionBlueprint(drawableSpinner) { Size = new Vector2(0.5f) }; } } diff --git a/osu.Game/Tests/Visual/PlacementBlueprintTestCase.cs b/osu.Game/Tests/Visual/PlacementBlueprintTestCase.cs index 5c6cb96e44..f893d8456b 100644 --- a/osu.Game/Tests/Visual/PlacementBlueprintTestCase.cs +++ b/osu.Game/Tests/Visual/PlacementBlueprintTestCase.cs @@ -32,7 +32,7 @@ namespace osu.Game.Tests.Visual [BackgroundDependencyLoader] private void load() { - Add(currentBlueprint = CreateMask()); + Add(currentBlueprint = CreateBlueprint()); } protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) @@ -52,7 +52,7 @@ namespace osu.Game.Tests.Visual hitObjectContainer.Add(CreateHitObject(hitObject)); Remove(currentBlueprint); - Add(currentBlueprint = CreateMask()); + Add(currentBlueprint = CreateBlueprint()); } public void Delete(HitObject hitObject) @@ -60,6 +60,6 @@ namespace osu.Game.Tests.Visual } protected abstract DrawableHitObject CreateHitObject(HitObject hitObject); - protected abstract PlacementBlueprint CreateMask(); + protected abstract PlacementBlueprint CreateBlueprint(); } } diff --git a/osu.Game/Tests/Visual/SelectionBlueprintTestCase.cs b/osu.Game/Tests/Visual/SelectionBlueprintTestCase.cs index 1879b0c37f..b1df849a67 100644 --- a/osu.Game/Tests/Visual/SelectionBlueprintTestCase.cs +++ b/osu.Game/Tests/Visual/SelectionBlueprintTestCase.cs @@ -29,7 +29,7 @@ namespace osu.Game.Tests.Visual [BackgroundDependencyLoader] private void load() { - base.Content.Add(blueprint = CreateMask()); + base.Content.Add(blueprint = CreateBlueprint()); blueprint.SelectionRequested += (_, __) => blueprint.Select(); AddStep("Select", () => blueprint.Select()); @@ -42,6 +42,6 @@ namespace osu.Game.Tests.Visual return true; } - protected abstract SelectionBlueprint CreateMask(); + protected abstract SelectionBlueprint CreateBlueprint(); } } From cf4dad0fe8fbc5b71b126de29bbe134a51332fbf Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 7 Nov 2018 15:42:40 +0900 Subject: [PATCH 098/155] Fix hitobjects not updating IsMaskedAway after being judged --- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index bcf84b375f..e9e9d93ed5 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -7,7 +7,6 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Extensions.TypeExtensions; -using osu.Framework.Graphics; using osu.Framework.Graphics.Primitives; using osu.Game.Audio; using osu.Game.Graphics; @@ -167,13 +166,7 @@ namespace osu.Game.Rulesets.Objects.Drawables } } - public override bool UpdateSubTreeMasking(Drawable source, RectangleF maskingBounds) - { - if (!AllJudged) - return false; - - return base.UpdateSubTreeMasking(source, maskingBounds); - } + protected override bool ComputeIsMaskedAway(RectangleF maskingBounds) => AllJudged && base.ComputeIsMaskedAway(maskingBounds); protected override void UpdateAfterChildren() { From 2612fd3099b642c2db042c001e856ef62f719688 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 7 Nov 2018 16:08:56 +0900 Subject: [PATCH 099/155] Adjust ruleset-specific namespaces --- .../{Masks => Blueprints}/HoldNoteSelectionBlueprint.cs | 2 +- .../Edit/{Masks => Blueprints}/NoteSelectionBlueprint.cs | 2 +- osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs | 2 +- .../TestCaseHitCirclePlacementBlueprint.cs | 2 +- .../TestCaseHitCircleSelectionBlueprint.cs | 2 +- .../TestCaseSliderPlacementBlueprint.cs | 2 +- .../TestCaseSliderSelectionBlueprint.cs | 4 ++-- .../TestCaseSpinnerPlacementBlueprint.cs | 2 +- .../TestCaseSpinnerSelectionBlueprint.cs | 4 ++-- .../HitCircles}/Components/HitCirclePiece.cs | 2 +- .../HitCircles}/HitCirclePlacementBlueprint.cs | 4 ++-- .../HitCircles}/HitCircleSelectionBlueprint.cs | 4 ++-- .../Sliders}/Components/PathControlPointPiece.cs | 2 +- .../Sliders}/Components/PathControlPointVisualiser.cs | 2 +- .../Sliders}/Components/SliderBodyPiece.cs | 2 +- .../Sliders}/Components/SliderCirclePiece.cs | 4 ++-- .../Sliders}/SliderCircleSelectionBlueprint.cs | 4 ++-- .../Sliders}/SliderPlacementBlueprint.cs | 4 ++-- .../SliderMasks => Blueprints/Sliders}/SliderPosition.cs | 2 +- .../Sliders}/SliderSelectionBlueprint.cs | 4 ++-- .../Spinners}/Components/SpinnerPiece.cs | 2 +- .../Spinners}/SpinnerPlacementBlueprint.cs | 4 ++-- .../Spinners}/SpinnerSelectionBlueprint.cs | 4 ++-- osu.Game.Rulesets.Osu/Edit/HitCircleCompositionTool.cs | 2 +- osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs | 6 +++--- osu.Game.Rulesets.Osu/Edit/SliderCompositionTool.cs | 2 +- osu.Game.Rulesets.Osu/Edit/SpinnerCompositionTool.cs | 2 +- osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs | 4 ++-- 28 files changed, 41 insertions(+), 41 deletions(-) rename osu.Game.Rulesets.Mania/Edit/{Masks => Blueprints}/HoldNoteSelectionBlueprint.cs (98%) rename osu.Game.Rulesets.Mania/Edit/{Masks => Blueprints}/NoteSelectionBlueprint.cs (95%) rename osu.Game.Rulesets.Osu/Edit/{Masks/HitCircleMasks => Blueprints/HitCircles}/Components/HitCirclePiece.cs (94%) rename osu.Game.Rulesets.Osu/Edit/{Masks/HitCircleMasks => Blueprints/HitCircles}/HitCirclePlacementBlueprint.cs (90%) rename osu.Game.Rulesets.Osu/Edit/{Masks/HitCircleMasks => Blueprints/HitCircles}/HitCircleSelectionBlueprint.cs (81%) rename osu.Game.Rulesets.Osu/Edit/{Masks/SliderMasks => Blueprints/Sliders}/Components/PathControlPointPiece.cs (98%) rename osu.Game.Rulesets.Osu/Edit/{Masks/SliderMasks => Blueprints/Sliders}/Components/PathControlPointVisualiser.cs (94%) rename osu.Game.Rulesets.Osu/Edit/{Masks/SliderMasks => Blueprints/Sliders}/Components/SliderBodyPiece.cs (95%) rename osu.Game.Rulesets.Osu/Edit/{Masks/SliderMasks => Blueprints/Sliders}/Components/SliderCirclePiece.cs (88%) rename osu.Game.Rulesets.Osu/Edit/{Masks/SliderMasks => Blueprints/Sliders}/SliderCircleSelectionBlueprint.cs (87%) rename osu.Game.Rulesets.Osu/Edit/{Masks/SliderMasks => Blueprints/Sliders}/SliderPlacementBlueprint.cs (97%) rename osu.Game.Rulesets.Osu/Edit/{Masks/SliderMasks => Blueprints/Sliders}/SliderPosition.cs (80%) rename osu.Game.Rulesets.Osu/Edit/{Masks/SliderMasks => Blueprints/Sliders}/SliderSelectionBlueprint.cs (90%) rename osu.Game.Rulesets.Osu/Edit/{Masks/SpinnerMasks => Blueprints/Spinners}/Components/SpinnerPiece.cs (96%) rename osu.Game.Rulesets.Osu/Edit/{Masks/SpinnerMasks => Blueprints/Spinners}/SpinnerPlacementBlueprint.cs (90%) rename osu.Game.Rulesets.Osu/Edit/{Masks/SpinnerMasks => Blueprints/Spinners}/SpinnerSelectionBlueprint.cs (85%) diff --git a/osu.Game.Rulesets.Mania/Edit/Masks/HoldNoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs similarity index 98% rename from osu.Game.Rulesets.Mania/Edit/Masks/HoldNoteSelectionBlueprint.cs rename to osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs index 14f045a549..0ede2a7b9d 100644 --- a/osu.Game.Rulesets.Mania/Edit/Masks/HoldNoteSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs @@ -13,7 +13,7 @@ using osu.Game.Rulesets.UI.Scrolling; using OpenTK; using OpenTK.Graphics; -namespace osu.Game.Rulesets.Mania.Edit.Masks +namespace osu.Game.Rulesets.Mania.Edit.Blueprints { public class HoldNoteSelectionBlueprint : SelectionBlueprint { diff --git a/osu.Game.Rulesets.Mania/Edit/Masks/NoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/NoteSelectionBlueprint.cs similarity index 95% rename from osu.Game.Rulesets.Mania/Edit/Masks/NoteSelectionBlueprint.cs rename to osu.Game.Rulesets.Mania/Edit/Blueprints/NoteSelectionBlueprint.cs index 4be0da12e1..19726a368d 100644 --- a/osu.Game.Rulesets.Mania/Edit/Masks/NoteSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/NoteSelectionBlueprint.cs @@ -7,7 +7,7 @@ using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; -namespace osu.Game.Rulesets.Mania.Edit.Masks +namespace osu.Game.Rulesets.Mania.Edit.Blueprints { public class NoteSelectionBlueprint : SelectionBlueprint { diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs index 7420a3c64c..06d67821a9 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs @@ -11,7 +11,7 @@ using osu.Game.Rulesets.Objects.Drawables; using System.Collections.Generic; using osu.Framework.Allocation; using osu.Game.Rulesets.Mania.Configuration; -using osu.Game.Rulesets.Mania.Edit.Masks; +using osu.Game.Rulesets.Mania.Edit.Blueprints; using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.UI; diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseHitCirclePlacementBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseHitCirclePlacementBlueprint.cs index 06ff2cf186..313438a337 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseHitCirclePlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseHitCirclePlacementBlueprint.cs @@ -4,7 +4,7 @@ using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; -using osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks; +using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Tests.Visual; diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleSelectionBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleSelectionBlueprint.cs index 674a7bdc3f..9662e0018f 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleSelectionBlueprint.cs @@ -4,7 +4,7 @@ using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks; +using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Tests.Visual; diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderPlacementBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSliderPlacementBlueprint.cs index 97decfe114..1f693ad9f4 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSliderPlacementBlueprint.cs @@ -4,7 +4,7 @@ using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; -using osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks; +using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Tests.Visual; diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionBlueprint.cs index ae16d90601..78e3d76313 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionBlueprint.cs @@ -7,8 +7,8 @@ using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects.Types; -using osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks; -using osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components; +using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders; +using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Tests.Visual; diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerPlacementBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerPlacementBlueprint.cs index 2abcb2d161..9a90be2582 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerPlacementBlueprint.cs @@ -4,7 +4,7 @@ using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; -using osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks; +using osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Tests.Visual; diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerSelectionBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerSelectionBlueprint.cs index d8a0eb6796..a0cfd4487e 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerSelectionBlueprint.cs @@ -8,8 +8,8 @@ using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks; -using osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks.Components; +using osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners; +using osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Tests.Visual; diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/Components/HitCirclePiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs similarity index 94% rename from osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/Components/HitCirclePiece.cs rename to osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs index c11ae096a7..9c33435285 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/Components/HitCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs @@ -9,7 +9,7 @@ using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; using OpenTK; -namespace osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks.Components +namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components { public class HitCirclePiece : CompositeDrawable { diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCirclePlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs similarity index 90% rename from osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCirclePlacementBlueprint.cs rename to osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs index ec32b7d74d..eddd399a4a 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCirclePlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs @@ -3,10 +3,10 @@ using osu.Framework.Input.Events; using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks.Components; +using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components; using osu.Game.Rulesets.Osu.Objects; -namespace osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks +namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles { public class HitCirclePlacementBlueprint : PlacementBlueprint { diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCircleSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCircleSelectionBlueprint.cs similarity index 81% rename from osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCircleSelectionBlueprint.cs rename to osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCircleSelectionBlueprint.cs index 14eb97327c..9c4b804d77 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCircleSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCircleSelectionBlueprint.cs @@ -2,11 +2,11 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks.Components; +using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; -namespace osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks +namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles { public class HitCircleSelectionBlueprint : SelectionBlueprint { diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/PathControlPointPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs similarity index 98% rename from osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/PathControlPointPiece.cs rename to osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs index 70156578b4..175e9d79f4 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/PathControlPointPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs @@ -12,7 +12,7 @@ using osu.Game.Graphics; using osu.Game.Rulesets.Osu.Objects; using OpenTK; -namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components +namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { public class PathControlPointPiece : CompositeDrawable { diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/PathControlPointVisualiser.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs similarity index 94% rename from osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/PathControlPointVisualiser.cs rename to osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs index 1d25f8cd39..db8e879126 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/PathControlPointVisualiser.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs @@ -5,7 +5,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Osu.Objects; -namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components +namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { public class PathControlPointVisualiser : CompositeDrawable { diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderBodyPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs similarity index 95% rename from osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderBodyPiece.cs rename to osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs index 006c256d53..6fc7d39e6c 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderBodyPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs @@ -10,7 +10,7 @@ using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; using OpenTK; using OpenTK.Graphics; -namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components +namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { public class SliderBodyPiece : CompositeDrawable { diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderCirclePiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderCirclePiece.cs similarity index 88% rename from osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderCirclePiece.cs rename to osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderCirclePiece.cs index 7864429d93..a91739737f 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderCirclePiece.cs @@ -1,10 +1,10 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks.Components; +using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components; using osu.Game.Rulesets.Osu.Objects; -namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components +namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { public class SliderCirclePiece : HitCirclePiece { diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderCircleSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleSelectionBlueprint.cs similarity index 87% rename from osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderCircleSelectionBlueprint.cs rename to osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleSelectionBlueprint.cs index ab37079d42..99ebfecd93 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderCircleSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleSelectionBlueprint.cs @@ -2,11 +2,11 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components; +using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; -namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks +namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { public class SliderCircleSelectionBlueprint : SelectionBlueprint { diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs similarity index 97% rename from osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPlacementBlueprint.cs rename to osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs index bf2acc2f3c..add9cb69f3 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs @@ -12,11 +12,11 @@ using osu.Framework.MathUtils; using osu.Game.Graphics; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects.Types; -using osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components; +using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components; using OpenTK; using OpenTK.Input; -namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks +namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { public class SliderPlacementBlueprint : PlacementBlueprint { diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPosition.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPosition.cs similarity index 80% rename from osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPosition.cs rename to osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPosition.cs index 01c1871131..a117a7056e 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPosition.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPosition.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 -namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks +namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { public enum SliderPosition { diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs similarity index 90% rename from osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderSelectionBlueprint.cs rename to osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index adb8591550..430ddbdc38 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -3,12 +3,12 @@ using osu.Framework.Graphics; using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components; +using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using OpenTK; -namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks +namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { public class SliderSelectionBlueprint : SelectionBlueprint { diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/Components/SpinnerPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs similarity index 96% rename from osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/Components/SpinnerPiece.cs rename to osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs index 0d9609facf..bd63a3e607 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/Components/SpinnerPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs @@ -10,7 +10,7 @@ using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; using OpenTK; -namespace osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks.Components +namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components { public class SpinnerPiece : CompositeDrawable { diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerPlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs similarity index 90% rename from osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerPlacementBlueprint.cs rename to osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs index ca7a2f7b01..c97adde427 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs @@ -4,11 +4,11 @@ using osu.Framework.Graphics; using osu.Framework.Input.Events; using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks.Components; +using osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.UI; -namespace osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks +namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners { public class SpinnerPlacementBlueprint : PlacementBlueprint { diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerSelectionBlueprint.cs similarity index 85% rename from osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerSelectionBlueprint.cs rename to osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerSelectionBlueprint.cs index b3c550b1c1..869c4c2c79 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerSelectionBlueprint.cs @@ -2,12 +2,12 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks.Components; +using osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using OpenTK; -namespace osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks +namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners { public class SpinnerSelectionBlueprint : SelectionBlueprint { diff --git a/osu.Game.Rulesets.Osu/Edit/HitCircleCompositionTool.cs b/osu.Game.Rulesets.Osu/Edit/HitCircleCompositionTool.cs index 1a48a0b6a9..ddab70d53a 100644 --- a/osu.Game.Rulesets.Osu/Edit/HitCircleCompositionTool.cs +++ b/osu.Game.Rulesets.Osu/Edit/HitCircleCompositionTool.cs @@ -3,7 +3,7 @@ using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Tools; -using osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks; +using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles; using osu.Game.Rulesets.Osu.Objects; namespace osu.Game.Rulesets.Osu.Edit diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index 1d806aba90..a706e1d4be 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -8,9 +8,9 @@ using osu.Game.Beatmaps; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Tools; using osu.Game.Rulesets.Objects.Drawables; -using osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks; -using osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks; -using osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks; +using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles; +using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders; +using osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.UI; diff --git a/osu.Game.Rulesets.Osu/Edit/SliderCompositionTool.cs b/osu.Game.Rulesets.Osu/Edit/SliderCompositionTool.cs index 0cf98ea9d7..6d4f67c597 100644 --- a/osu.Game.Rulesets.Osu/Edit/SliderCompositionTool.cs +++ b/osu.Game.Rulesets.Osu/Edit/SliderCompositionTool.cs @@ -3,7 +3,7 @@ using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Tools; -using osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks; +using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders; using osu.Game.Rulesets.Osu.Objects; namespace osu.Game.Rulesets.Osu.Edit diff --git a/osu.Game.Rulesets.Osu/Edit/SpinnerCompositionTool.cs b/osu.Game.Rulesets.Osu/Edit/SpinnerCompositionTool.cs index b3677c7612..5c19a1bac0 100644 --- a/osu.Game.Rulesets.Osu/Edit/SpinnerCompositionTool.cs +++ b/osu.Game.Rulesets.Osu/Edit/SpinnerCompositionTool.cs @@ -3,7 +3,7 @@ using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Tools; -using osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks; +using osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners; using osu.Game.Rulesets.Osu.Objects; namespace osu.Game.Rulesets.Osu.Edit diff --git a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs index ae9a28fcaf..2629b29c6c 100644 --- a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs +++ b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs @@ -13,8 +13,8 @@ using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Edit; -using osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks; -using osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks.Components; +using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles; +using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Screens.Edit.Compose; using osu.Game.Screens.Edit.Compose.Components; From 5d51719572815210626eb87357eda6d82c2ccd80 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 7 Nov 2018 16:21:32 +0900 Subject: [PATCH 100/155] Make selection blueprints handle position adjustments --- .../Blueprints/HoldNoteSelectionBlueprint.cs | 3 +-- .../Blueprints/ManiaSelectionBlueprint.cs | 21 ++++++++++++++++++ .../Edit/Blueprints/NoteSelectionBlueprint.cs | 3 +-- .../HitCircles/HitCircleSelectionBlueprint.cs | 3 +-- .../Edit/Blueprints/OsuSelectionBlueprint.cs | 22 +++++++++++++++++++ .../Sliders/SliderCircleSelectionBlueprint.cs | 10 +++++++-- .../Sliders/SliderSelectionBlueprint.cs | 3 +-- .../Spinners/SpinnerSelectionBlueprint.cs | 9 ++++++-- osu.Game/Rulesets/Edit/SelectionBlueprint.cs | 10 +++++---- .../Compose/Components/BlueprintContainer.cs | 3 +-- .../Edit/Compose/Components/SelectionBox.cs | 12 ++-------- 11 files changed, 71 insertions(+), 28 deletions(-) create mode 100644 osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs create mode 100644 osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs index 0ede2a7b9d..3da2538497 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs @@ -5,7 +5,6 @@ using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Game.Graphics; -using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; using osu.Game.Rulesets.Mania.UI; @@ -15,7 +14,7 @@ using OpenTK.Graphics; namespace osu.Game.Rulesets.Mania.Edit.Blueprints { - public class HoldNoteSelectionBlueprint : SelectionBlueprint + public class HoldNoteSelectionBlueprint : ManiaSelectionBlueprint { public new DrawableHoldNote HitObject => (DrawableHoldNote)base.HitObject; diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs new file mode 100644 index 0000000000..474b8c662e --- /dev/null +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs @@ -0,0 +1,21 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Input.Events; +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Objects.Drawables; + +namespace osu.Game.Rulesets.Mania.Edit.Blueprints +{ + public class ManiaSelectionBlueprint : SelectionBlueprint + { + public ManiaSelectionBlueprint(DrawableHitObject hitObject) + : base(hitObject) + { + } + + public override void AdjustPosition(DragEvent dragEvent) + { + } + } +} diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/NoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/NoteSelectionBlueprint.cs index 19726a368d..7c0337dc4e 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/NoteSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/NoteSelectionBlueprint.cs @@ -3,13 +3,12 @@ using osu.Framework.Allocation; using osu.Game.Graphics; -using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; namespace osu.Game.Rulesets.Mania.Edit.Blueprints { - public class NoteSelectionBlueprint : SelectionBlueprint + public class NoteSelectionBlueprint : ManiaSelectionBlueprint { public NoteSelectionBlueprint(DrawableNote note) : base(note) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCircleSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCircleSelectionBlueprint.cs index 9c4b804d77..a59dac1834 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCircleSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCircleSelectionBlueprint.cs @@ -1,14 +1,13 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles { - public class HitCircleSelectionBlueprint : SelectionBlueprint + public class HitCircleSelectionBlueprint : OsuSelectionBlueprint { public HitCircleSelectionBlueprint(DrawableHitCircle hitCircle) : base(hitCircle) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs new file mode 100644 index 0000000000..8431d5d5d0 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs @@ -0,0 +1,22 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Input.Events; +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Osu.Objects; + +namespace osu.Game.Rulesets.Osu.Edit.Blueprints +{ + public class OsuSelectionBlueprint : SelectionBlueprint + { + protected OsuHitObject OsuObject => (OsuHitObject)HitObject.HitObject; + + public OsuSelectionBlueprint(DrawableHitObject hitObject) + : base(hitObject) + { + } + + public override void AdjustPosition(DragEvent dragEvent) => OsuObject.Position += dragEvent.Delta; + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleSelectionBlueprint.cs index 99ebfecd93..4bac9d3556 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleSelectionBlueprint.cs @@ -1,18 +1,22 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Game.Rulesets.Edit; +using osu.Framework.Input.Events; using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { - public class SliderCircleSelectionBlueprint : SelectionBlueprint + public class SliderCircleSelectionBlueprint : OsuSelectionBlueprint { + private readonly Slider slider; + public SliderCircleSelectionBlueprint(DrawableOsuHitObject hitObject, Slider slider, SliderPosition position) : base(hitObject) { + this.slider = slider; + InternalChild = new SliderCirclePiece(slider, position); Select(); @@ -20,5 +24,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders // 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 HandlePositionalInput => false; + + public override void AdjustPosition(DragEvent dragEvent) => slider.Position += dragEvent.Delta; } } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index 430ddbdc38..4810d76bf8 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -2,7 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Graphics; -using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; @@ -10,7 +9,7 @@ using OpenTK; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { - public class SliderSelectionBlueprint : SelectionBlueprint + public class SliderSelectionBlueprint : OsuSelectionBlueprint { private readonly SliderCircleSelectionBlueprint headBlueprint; diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerSelectionBlueprint.cs index 869c4c2c79..9e9cc87c5e 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerSelectionBlueprint.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.Game.Rulesets.Edit; +using osu.Framework.Input.Events; using osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; @@ -9,7 +9,7 @@ using OpenTK; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners { - public class SpinnerSelectionBlueprint : SelectionBlueprint + public class SpinnerSelectionBlueprint : OsuSelectionBlueprint { private readonly SpinnerPiece piece; @@ -20,5 +20,10 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners } public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => piece.ReceivePositionalInputAt(screenSpacePos); + + public override void AdjustPosition(DragEvent dragEvent) + { + // Spinners don't support position adjustments + } } } diff --git a/osu.Game/Rulesets/Edit/SelectionBlueprint.cs b/osu.Game/Rulesets/Edit/SelectionBlueprint.cs index 6e0d136e1f..db35d47b2b 100644 --- a/osu.Game/Rulesets/Edit/SelectionBlueprint.cs +++ b/osu.Game/Rulesets/Edit/SelectionBlueprint.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Edit /// /// A blueprint placed above a adding editing functionality. /// - public class SelectionBlueprint : CompositeDrawable, IStateful + public abstract class SelectionBlueprint : CompositeDrawable, IStateful { /// /// Invoked when this has been selected. @@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Edit /// /// Invoked when this has requested drag. /// - public event Action DragRequested; + public event Action DragRequested; /// /// The which this applies to. @@ -49,7 +49,7 @@ namespace osu.Game.Rulesets.Edit public override bool HandlePositionalInput => ShouldBeAlive; public override bool RemoveWhenNotAlive => false; - public SelectionBlueprint(DrawableHitObject hitObject) + protected SelectionBlueprint(DrawableHitObject hitObject) { HitObject = hitObject; @@ -130,10 +130,12 @@ namespace osu.Game.Rulesets.Edit protected override bool OnDrag(DragEvent e) { - DragRequested?.Invoke(this, e.Delta, e.CurrentState); + DragRequested?.Invoke(e); return true; } + public abstract void AdjustPosition(DragEvent dragEvent); + /// /// The screen-space point that causes this to be selected. /// diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index 45003545a3..acbfd1f1d6 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -12,7 +12,6 @@ using osu.Framework.Input.States; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Tools; using osu.Game.Rulesets.Objects.Drawables; -using OpenTK; namespace osu.Game.Screens.Edit.Compose.Components { @@ -165,7 +164,7 @@ namespace osu.Game.Screens.Edit.Compose.Components private void onSelectionRequested(SelectionBlueprint blueprint, InputState state) => selectionBox.HandleSelectionRequested(blueprint, state); - private void onDragRequested(SelectionBlueprint blueprint, Vector2 delta, InputState state) => selectionBox.HandleDrag(blueprint, delta, state); + private void onDragRequested(DragEvent dragEvent) => selectionBox.HandleDrag(dragEvent); private class SelectionBlueprintContainer : Container { diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs index e2a70a9ee7..8732672723 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs @@ -12,7 +12,6 @@ using osu.Framework.Input.Events; using osu.Framework.Input.States; using osu.Game.Graphics; using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Edit.Types; using OpenTK; using OpenTK.Input; @@ -60,19 +59,12 @@ namespace osu.Game.Screens.Edit.Compose.Components #region User Input Handling - public void HandleDrag(SelectionBlueprint m, Vector2 delta, InputState state) + public void HandleDrag(DragEvent dragEvent) { // Todo: Various forms of snapping foreach (var blueprint in selectedBlueprints) - { - switch (blueprint.HitObject.HitObject) - { - case IHasEditablePosition editablePosition: - editablePosition.OffsetPosition(delta); - break; - } - } + blueprint.AdjustPosition(dragEvent); } protected override bool OnKeyDown(KeyDownEvent e) From c6350c6efd20334056406fa2c5c5facb245a7c6b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 7 Nov 2018 16:21:52 +0900 Subject: [PATCH 101/155] Remove IHasEditablePosition --- osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs | 5 +---- osu.Game.Rulesets.Osu/Objects/Slider.cs | 4 ++-- osu.Game.Rulesets.Osu/Objects/SliderCircle.cs | 10 ---------- osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs | 5 ----- osu.Game.Rulesets.Osu/Objects/Spinner.cs | 6 ------ .../Rulesets/Edit/Types/IHasEditablePosition.cs | 13 ------------- 6 files changed, 3 insertions(+), 40 deletions(-) delete mode 100644 osu.Game/Rulesets/Edit/Types/IHasEditablePosition.cs diff --git a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs index 67396c7ae4..61d199a7dc 100644 --- a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs @@ -7,11 +7,10 @@ using osu.Game.Rulesets.Objects; using OpenTK; using osu.Game.Rulesets.Objects.Types; using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Rulesets.Edit.Types; namespace osu.Game.Rulesets.Osu.Objects { - public abstract class OsuHitObject : HitObject, IHasComboInformation, IHasEditablePosition + public abstract class OsuHitObject : HitObject, IHasComboInformation, IHasPosition { public const double OBJECT_RADIUS = 64; @@ -100,8 +99,6 @@ namespace osu.Game.Rulesets.Osu.Objects Scale = (1.0f - 0.7f * (difficulty.CircleSize - 5) / 5) / 2; } - public virtual void OffsetPosition(Vector2 offset) => Position += offset; - protected override HitWindows CreateHitWindows() => new OsuHitWindows(); } } diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 3680c38945..cff742ca29 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -166,7 +166,7 @@ namespace osu.Game.Rulesets.Osu.Objects private void createSliderEnds() { - HeadCircle = new SliderCircle(this) + HeadCircle = new SliderCircle { StartTime = StartTime, Position = Position, @@ -176,7 +176,7 @@ namespace osu.Game.Rulesets.Osu.Objects ComboIndex = ComboIndex, }; - TailCircle = new SliderTailCircle(this) + TailCircle = new SliderTailCircle { StartTime = EndTime, Position = EndPosition, diff --git a/osu.Game.Rulesets.Osu/Objects/SliderCircle.cs b/osu.Game.Rulesets.Osu/Objects/SliderCircle.cs index 1bdd16c9df..deda951378 100644 --- a/osu.Game.Rulesets.Osu/Objects/SliderCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/SliderCircle.cs @@ -1,19 +1,9 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using OpenTK; - namespace osu.Game.Rulesets.Osu.Objects { public class SliderCircle : HitCircle { - private readonly Slider slider; - - public SliderCircle(Slider slider) - { - this.slider = slider; - } - - public override void OffsetPosition(Vector2 offset) => slider.OffsetPosition(offset); } } diff --git a/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs b/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs index 23616ea005..b567bd8423 100644 --- a/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs @@ -8,11 +8,6 @@ namespace osu.Game.Rulesets.Osu.Objects { public class SliderTailCircle : SliderCircle { - public SliderTailCircle(Slider slider) - : base(slider) - { - } - public override Judgement CreateJudgement() => new OsuSliderTailJudgement(); } } diff --git a/osu.Game.Rulesets.Osu/Objects/Spinner.cs b/osu.Game.Rulesets.Osu/Objects/Spinner.cs index 1270685ab5..1c60fd4831 100644 --- a/osu.Game.Rulesets.Osu/Objects/Spinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Spinner.cs @@ -7,7 +7,6 @@ using osu.Game.Rulesets.Objects.Types; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Osu.Judgements; -using OpenTK; namespace osu.Game.Rulesets.Osu.Objects { @@ -32,10 +31,5 @@ namespace osu.Game.Rulesets.Osu.Objects } public override Judgement CreateJudgement() => new OsuJudgement(); - - public override void OffsetPosition(Vector2 offset) - { - // for now we don't want to allow spinners to be moved around. - } } } diff --git a/osu.Game/Rulesets/Edit/Types/IHasEditablePosition.cs b/osu.Game/Rulesets/Edit/Types/IHasEditablePosition.cs deleted file mode 100644 index 7107b6c763..0000000000 --- a/osu.Game/Rulesets/Edit/Types/IHasEditablePosition.cs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using osu.Game.Rulesets.Objects.Types; -using OpenTK; - -namespace osu.Game.Rulesets.Edit.Types -{ - public interface IHasEditablePosition : IHasPosition - { - void OffsetPosition(Vector2 offset); - } -} From 4b1b49489368e6f37334ca485f96268a7cd104d4 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 6 Nov 2018 16:16:52 +0900 Subject: [PATCH 102/155] Fix selection masks not having the correct size --- .../Blueprints/HoldNoteSelectionBlueprint.cs | 5 +++-- .../Edit/Blueprints/NoteSelectionBlueprint.cs | 6 ++++-- .../Edit/Masks/ManiaSelectionBlueprint.cs | 18 ++++++++++++++++++ 3 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 osu.Game.Rulesets.Mania/Edit/Masks/ManiaSelectionBlueprint.cs diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs index 0ede2a7b9d..573c905a51 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs @@ -5,7 +5,6 @@ using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Game.Graphics; -using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; using osu.Game.Rulesets.Mania.UI; @@ -15,7 +14,7 @@ using OpenTK.Graphics; namespace osu.Game.Rulesets.Mania.Edit.Blueprints { - public class HoldNoteSelectionBlueprint : SelectionBlueprint + public class HoldNoteSelectionBlueprint : ManiaSelectionBlueprint { public new DrawableHoldNote HitObject => (DrawableHoldNote)base.HitObject; @@ -26,6 +25,8 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints public HoldNoteSelectionBlueprint(DrawableHoldNote hold) : base(hold) { + RelativeSizeAxes = Axes.None; + InternalChildren = new Drawable[] { new HoldNoteNoteSelectionBlueprint(hold.Head), diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/NoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/NoteSelectionBlueprint.cs index 19726a368d..0ad99f9709 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/NoteSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/NoteSelectionBlueprint.cs @@ -2,18 +2,20 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Allocation; +using osu.Framework.Graphics; using osu.Game.Graphics; -using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; namespace osu.Game.Rulesets.Mania.Edit.Blueprints { - public class NoteSelectionBlueprint : SelectionBlueprint + public class NoteSelectionBlueprint : ManiaSelectionBlueprint { public NoteSelectionBlueprint(DrawableNote note) : base(note) { + RelativeSizeAxes = Axes.None; + Scale = note.Scale; CornerRadius = 5; diff --git a/osu.Game.Rulesets.Mania/Edit/Masks/ManiaSelectionBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Masks/ManiaSelectionBlueprint.cs new file mode 100644 index 0000000000..81a2728ad4 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Edit/Masks/ManiaSelectionBlueprint.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 osu.Framework.Graphics; +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Objects.Drawables; + +namespace osu.Game.Rulesets.Mania.Edit.Masks +{ + public abstract class ManiaSelectionBlueprint : SelectionBlueprint + { + protected ManiaSelectionBlueprint(DrawableHitObject hitObject) + : base(hitObject) + { + RelativeSizeAxes = Axes.None; + } + } +} From 21f8a0a56f86c219c1fdb5eb84fc463b076210a5 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 6 Nov 2018 16:19:40 +0900 Subject: [PATCH 103/155] Fix selection box using an incorrect size --- .../Edit/Blueprints/HoldNoteSelectionBlueprint.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs index 573c905a51..2cb0597a40 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs @@ -4,6 +4,7 @@ using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Graphics; +using osu.Framework.Graphics.Primitives; using osu.Game.Graphics; using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; @@ -60,6 +61,8 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints Y -= HitObject.Tail.DrawHeight; } + public override Quad SelectionQuad => ScreenSpaceDrawQuad; + private class HoldNoteNoteSelectionBlueprint : NoteSelectionBlueprint { public HoldNoteNoteSelectionBlueprint(DrawableNote note) From 8583fd1380639944316773b602446a5402eaa626 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 30 Oct 2018 17:24:10 +0900 Subject: [PATCH 104/155] Fix testcase never working --- osu.Game.Tests/Visual/TestCaseScrollingHitObjects.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseScrollingHitObjects.cs b/osu.Game.Tests/Visual/TestCaseScrollingHitObjects.cs index b254325472..eb322df185 100644 --- a/osu.Game.Tests/Visual/TestCaseScrollingHitObjects.cs +++ b/osu.Game.Tests/Visual/TestCaseScrollingHitObjects.cs @@ -114,11 +114,11 @@ namespace osu.Game.Tests.Visual private class TestPlayfield : ScrollingPlayfield { - public new readonly ScrollingDirection Direction; + public new ScrollingDirection Direction => base.Direction; public TestPlayfield(ScrollingDirection direction) { - Direction = direction; + base.Direction.Value = direction; Padding = new MarginPadding(2); From 0bdeebbce2ad84685ca32f4c265e5a55de682db1 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 30 Oct 2018 17:31:43 +0900 Subject: [PATCH 105/155] Expose basic values from ISpeedChangeVisualiser --- .../Scrolling/ScrollingHitObjectContainer.cs | 17 ++++- .../ConstantSpeedChangeVisualiser.cs | 42 +++++++----- .../Visualisers/ISpeedChangeVisualiser.cs | 19 ++++-- .../OverlappingSpeedChangeVisualiser.cs | 66 +++++++++--------- .../SequentialSpeedChangeVisualiser.cs | 67 ++++++++++++------- 5 files changed, 125 insertions(+), 86 deletions(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index 7307fc0ead..52b4072523 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -95,9 +95,22 @@ namespace osu.Game.Rulesets.UI.Scrolling { base.Update(); + speedChangeVisualiser.TimeRange = TimeRange.Value; + + switch (Direction.Value) + { + case ScrollingDirection.Up: + case ScrollingDirection.Down: + speedChangeVisualiser.ScrollLength = DrawSize.Y; + break; + default: + speedChangeVisualiser.ScrollLength = DrawSize.X; + break; + } + if (!initialStateCache.IsValid) { - speedChangeVisualiser.ComputeInitialStates(Objects, Direction, TimeRange, DrawSize); + speedChangeVisualiser.ComputeInitialStates(Objects, Direction); initialStateCache.Validate(); } } @@ -107,7 +120,7 @@ namespace osu.Game.Rulesets.UI.Scrolling base.UpdateAfterChildrenLife(); // We need to calculate this as soon as possible after lifetimes so that hitobjects get the final say in their positions - speedChangeVisualiser.UpdatePositions(AliveObjects, Direction, Time.Current, TimeRange, DrawSize); + speedChangeVisualiser.UpdatePositions(AliveObjects, Direction, Time.Current); } } } diff --git a/osu.Game/Rulesets/UI/Scrolling/Visualisers/ConstantSpeedChangeVisualiser.cs b/osu.Game/Rulesets/UI/Scrolling/Visualisers/ConstantSpeedChangeVisualiser.cs index 9e910d6b11..f4417e393a 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Visualisers/ConstantSpeedChangeVisualiser.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Visualisers/ConstantSpeedChangeVisualiser.cs @@ -4,64 +4,74 @@ using System.Collections.Generic; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Types; -using OpenTK; namespace osu.Game.Rulesets.UI.Scrolling.Visualisers { public class ConstantSpeedChangeVisualiser : ISpeedChangeVisualiser { - public void ComputeInitialStates(IEnumerable hitObjects, ScrollingDirection direction, double timeRange, Vector2 length) + public double TimeRange { get; set; } + + public float ScrollLength { get; set; } + + public void ComputeInitialStates(IEnumerable hitObjects, ScrollingDirection direction) { foreach (var obj in hitObjects) { - obj.LifetimeStart = obj.HitObject.StartTime - timeRange; + obj.LifetimeStart = GetDisplayStartTime(obj.HitObject.StartTime); if (obj.HitObject is IHasEndTime endTime) { - var hitObjectLength = (endTime.EndTime - obj.HitObject.StartTime) / timeRange; - switch (direction) { case ScrollingDirection.Up: case ScrollingDirection.Down: - obj.Height = (float)(hitObjectLength * length.Y); + obj.Height = GetLength(obj.HitObject.StartTime, endTime.EndTime); break; case ScrollingDirection.Left: case ScrollingDirection.Right: - obj.Width = (float)(hitObjectLength * length.X); + obj.Height = GetLength(obj.HitObject.StartTime, endTime.EndTime); break; } } - ComputeInitialStates(obj.NestedHitObjects, direction, timeRange, length); + ComputeInitialStates(obj.NestedHitObjects, direction); // Nested hitobjects don't need to scroll, but they do need accurate positions - UpdatePositions(obj.NestedHitObjects, direction, obj.HitObject.StartTime, timeRange, length); + UpdatePositions(obj.NestedHitObjects, direction, obj.HitObject.StartTime); } } - public void UpdatePositions(IEnumerable hitObjects, ScrollingDirection direction, double currentTime, double timeRange, Vector2 length) + public void UpdatePositions(IEnumerable hitObjects, ScrollingDirection direction, double currentTime) { foreach (var obj in hitObjects) { - var position = (obj.HitObject.StartTime - currentTime) / timeRange; - switch (direction) { case ScrollingDirection.Up: - obj.Y = (float)(position * length.Y); + obj.Y = PositionAt(currentTime, obj.HitObject.StartTime); break; case ScrollingDirection.Down: - obj.Y = (float)(-position * length.Y); + obj.Y = -PositionAt(currentTime, obj.HitObject.StartTime); break; case ScrollingDirection.Left: - obj.X = (float)(position * length.X); + obj.X = PositionAt(currentTime, obj.HitObject.StartTime); break; case ScrollingDirection.Right: - obj.X = (float)(-position * length.X); + obj.X = -PositionAt(currentTime, obj.HitObject.StartTime); break; } } } + + public double GetDisplayStartTime(double startTime) => startTime - TimeRange; + + public float GetLength(double startTime, double endTime) + { + // At the hitobject's end time, the hitobject will be positioned such that its end rests at the origin. + // This results in a negative-position value, and the absolute of it indicates the length of the hitobject. + return -PositionAt(endTime, startTime); + } + + public float PositionAt(double currentTime, double startTime) => (float)((startTime - currentTime) / TimeRange * ScrollLength); } } diff --git a/osu.Game/Rulesets/UI/Scrolling/Visualisers/ISpeedChangeVisualiser.cs b/osu.Game/Rulesets/UI/Scrolling/Visualisers/ISpeedChangeVisualiser.cs index 097e28b2dc..b7d611df50 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Visualisers/ISpeedChangeVisualiser.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Visualisers/ISpeedChangeVisualiser.cs @@ -3,21 +3,22 @@ using System.Collections.Generic; using osu.Game.Rulesets.Objects.Drawables; -using OpenTK; namespace osu.Game.Rulesets.UI.Scrolling.Visualisers { public interface ISpeedChangeVisualiser { + double TimeRange { get; set; } + + float ScrollLength { get; set; } + /// /// Computes the states of s that remain constant while scrolling, such as lifetime and spatial length. /// This is invoked once whenever or changes. /// /// The s whose states should be computed. /// The scrolling direction. - /// The duration required to scroll through one length of the screen before any speed adjustments. - /// The length of the screen that is scrolled through. - void ComputeInitialStates(IEnumerable hitObjects, ScrollingDirection direction, double timeRange, Vector2 length); + void ComputeInitialStates(IEnumerable hitObjects, ScrollingDirection direction); /// /// Updates the positions of s, depending on the current time. This is invoked once per frame. @@ -25,8 +26,12 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers /// The s whose positions should be computed. /// The scrolling direction. /// The current time. - /// The duration required to scroll through one length of the screen before any speed adjustments. - /// The length of the screen that is scrolled through. - void UpdatePositions(IEnumerable hitObjects, ScrollingDirection direction, double currentTime, double timeRange, Vector2 length); + void UpdatePositions(IEnumerable hitObjects, ScrollingDirection direction, double currentTime); + + double GetDisplayStartTime(double startTime); + + float GetLength(double startTime, double endTime); + + float PositionAt(double currentTime, double startTime); } } diff --git a/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs b/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs index d2b79e2fa7..f6fbe9063f 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs @@ -6,12 +6,15 @@ using osu.Framework.Lists; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Timing; -using OpenTK; namespace osu.Game.Rulesets.UI.Scrolling.Visualisers { public class OverlappingSpeedChangeVisualiser : ISpeedChangeVisualiser { + public double TimeRange { get; set; } + + public float ScrollLength { get; set; } + private readonly SortedList controlPoints; public OverlappingSpeedChangeVisualiser(SortedList controlPoints) @@ -19,79 +22,72 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers this.controlPoints = controlPoints; } - public void ComputeInitialStates(IEnumerable hitObjects, ScrollingDirection direction, double timeRange, Vector2 length) + public void ComputeInitialStates(IEnumerable hitObjects, ScrollingDirection direction) { foreach (var obj in hitObjects) { - // The total amount of time that the hitobject will remain visible within the timeRange, which decreases as the speed multiplier increases - double visibleDuration = timeRange / controlPointAt(obj.HitObject.StartTime).Multiplier; - - obj.LifetimeStart = obj.HitObject.StartTime - visibleDuration; + obj.LifetimeStart = GetDisplayStartTime(obj.HitObject.StartTime); if (obj.HitObject is IHasEndTime endTime) { - // At the hitobject's end time, the hitobject will be positioned such that its end rests at the origin. - // This results in a negative-position value, and the absolute of it indicates the length of the hitobject. - var hitObjectLength = -hitObjectPositionAt(obj, endTime.EndTime, timeRange); - switch (direction) { case ScrollingDirection.Up: case ScrollingDirection.Down: - obj.Height = (float)(hitObjectLength * length.Y); + obj.Height = GetLength(obj.HitObject.StartTime, endTime.EndTime); break; case ScrollingDirection.Left: case ScrollingDirection.Right: - obj.Width = (float)(hitObjectLength * length.X); + obj.Width = GetLength(obj.HitObject.StartTime, endTime.EndTime); break; } } - ComputeInitialStates(obj.NestedHitObjects, direction, timeRange, length); + ComputeInitialStates(obj.NestedHitObjects, direction); // Nested hitobjects don't need to scroll, but they do need accurate positions - UpdatePositions(obj.NestedHitObjects, direction, obj.HitObject.StartTime, timeRange, length); + UpdatePositions(obj.NestedHitObjects, direction, obj.HitObject.StartTime); } } - public void UpdatePositions(IEnumerable hitObjects, ScrollingDirection direction, double currentTime, double timeRange, Vector2 length) + public void UpdatePositions(IEnumerable hitObjects, ScrollingDirection direction, double currentTime) { foreach (var obj in hitObjects) { - var position = hitObjectPositionAt(obj, currentTime, timeRange); - switch (direction) { case ScrollingDirection.Up: - obj.Y = (float)(position * length.Y); + obj.Y = PositionAt(currentTime, obj.HitObject.StartTime); break; case ScrollingDirection.Down: - obj.Y = (float)(-position * length.Y); + obj.Y = -PositionAt(currentTime, obj.HitObject.StartTime); break; case ScrollingDirection.Left: - obj.X = (float)(position * length.X); + obj.X = PositionAt(currentTime, obj.HitObject.StartTime); break; case ScrollingDirection.Right: - obj.X = (float)(-position * length.X); + obj.X = -PositionAt(currentTime, obj.HitObject.StartTime); break; } } } - /// - /// Computes the position of a at a point in time. - /// - /// At t < startTime, position > 0.
- /// At t = startTime, position = 0.
- /// At t > startTime, position < 0. - ///
- ///
- /// The . - /// The time to find the position of at. - /// The amount of time visualised by the scrolling area. - /// The position of in the scrolling area at time = . - private double hitObjectPositionAt(DrawableHitObject obj, double time, double timeRange) - => (obj.HitObject.StartTime - time) / timeRange * controlPointAt(obj.HitObject.StartTime).Multiplier; + public double GetDisplayStartTime(double startTime) + { + // The total amount of time that the hitobject will remain visible within the timeRange, which decreases as the speed multiplier increases + double visibleDuration = TimeRange / controlPointAt(startTime).Multiplier; + return startTime - visibleDuration; + } + + public float GetLength(double startTime, double endTime) + { + // At the hitobject's end time, the hitobject will be positioned such that its end rests at the origin. + // This results in a negative-position value, and the absolute of it indicates the length of the hitobject. + return -PositionAt(endTime, startTime); + } + + public float PositionAt(double currentTime, double startTime) + => (float)((startTime - currentTime) / TimeRange * controlPointAt(startTime).Multiplier * ScrollLength); private readonly MultiplierControlPoint searchPoint = new MultiplierControlPoint(); diff --git a/osu.Game/Rulesets/UI/Scrolling/Visualisers/SequentialSpeedChangeVisualiser.cs b/osu.Game/Rulesets/UI/Scrolling/Visualisers/SequentialSpeedChangeVisualiser.cs index 25dea8dfbf..7b2471e674 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Visualisers/SequentialSpeedChangeVisualiser.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Visualisers/SequentialSpeedChangeVisualiser.cs @@ -6,13 +6,16 @@ using System.Collections.Generic; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Timing; -using OpenTK; namespace osu.Game.Rulesets.UI.Scrolling.Visualisers { public class SequentialSpeedChangeVisualiser : ISpeedChangeVisualiser { - private readonly Dictionary hitObjectPositions = new Dictionary(); + public double TimeRange { get; set; } + + public float ScrollLength { get; set; } + + private readonly Dictionary positionCache = new Dictionary(); private readonly IReadOnlyList controlPoints; @@ -21,66 +24,78 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers this.controlPoints = controlPoints; } - public void ComputeInitialStates(IEnumerable hitObjects, ScrollingDirection direction, double timeRange, Vector2 length) + public void ComputeInitialStates(IEnumerable hitObjects, ScrollingDirection direction) { foreach (var obj in hitObjects) { - // To reduce iterations when updating hitobject positions later on, their initial positions are cached - var startPosition = hitObjectPositions[obj] = positionAt(obj.HitObject.StartTime, timeRange); - - // Todo: This is approximate and will be incorrect in the case of extreme speed changes - obj.LifetimeStart = obj.HitObject.StartTime - timeRange - 1000; + obj.LifetimeStart = GetDisplayStartTime(obj.HitObject.StartTime); if (obj.HitObject is IHasEndTime endTime) { - var hitObjectLength = positionAt(endTime.EndTime, timeRange) - startPosition; - switch (direction) { case ScrollingDirection.Up: case ScrollingDirection.Down: - obj.Height = (float)(hitObjectLength * length.Y); + obj.Height = GetLength(obj.HitObject.StartTime, endTime.EndTime); break; case ScrollingDirection.Left: case ScrollingDirection.Right: - obj.Width = (float)(hitObjectLength * length.X); + obj.Width = GetLength(obj.HitObject.StartTime, endTime.EndTime); break; } } - ComputeInitialStates(obj.NestedHitObjects, direction, timeRange, length); + ComputeInitialStates(obj.NestedHitObjects, direction); // Nested hitobjects don't need to scroll, but they do need accurate positions - UpdatePositions(obj.NestedHitObjects, direction, obj.HitObject.StartTime, timeRange, length); + UpdatePositions(obj.NestedHitObjects, direction, obj.HitObject.StartTime); } } - public void UpdatePositions(IEnumerable hitObjects, ScrollingDirection direction, double currentTime, double timeRange, Vector2 length) + public void UpdatePositions(IEnumerable hitObjects, ScrollingDirection direction, double currentTime) { - var timelinePosition = positionAt(currentTime, timeRange); - foreach (var obj in hitObjects) { - var finalPosition = hitObjectPositions[obj] - timelinePosition; - switch (direction) { case ScrollingDirection.Up: - obj.Y = (float)(finalPosition * length.Y); + obj.Y = PositionAt(currentTime, obj.HitObject.StartTime); break; case ScrollingDirection.Down: - obj.Y = (float)(-finalPosition * length.Y); + obj.Y = -PositionAt(currentTime, obj.HitObject.StartTime); break; case ScrollingDirection.Left: - obj.X = (float)(finalPosition * length.X); + obj.X = PositionAt(currentTime, obj.HitObject.StartTime); break; case ScrollingDirection.Right: - obj.X = (float)(-finalPosition * length.X); + obj.X = -PositionAt(currentTime, obj.HitObject.StartTime); break; } } } + public double GetDisplayStartTime(double startTime) => startTime - TimeRange - 1000; + + public float GetLength(double startTime, double endTime) + { + var objectLength = relativePositionAtCached(endTime) - relativePositionAtCached(startTime); + return (float)(objectLength * ScrollLength); + } + + public float PositionAt(double currentTime, double startTime) + { + // Caching is not used here as currentTime is unlikely to have been previously cached + double timelinePosition = relativePositionAt(currentTime); + return (float)((relativePositionAtCached(startTime) - timelinePosition) * ScrollLength); + } + + private double relativePositionAtCached(double time) + { + if (!positionCache.TryGetValue(time, out double existing)) + positionCache[time] = existing = relativePositionAt(time); + return existing; + } + /// /// Finds the position which corresponds to a point in time. /// This is a non-linear operation that depends on all the control points up to and including the one active at the time value. @@ -88,10 +103,10 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers /// The time to find the position at. /// The amount of time visualised by the scrolling area. /// A positive value indicating the position at . - private double positionAt(double time, double timeRange) + private double relativePositionAt(double time) { if (controlPoints.Count == 0) - return time / timeRange; + return time / TimeRange; double length = 0; @@ -115,7 +130,7 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers var durationInCurrent = Math.Min(currentDuration, time - current.StartTime); // Figure out how much of the time range the duration represents, and adjust it by the speed multiplier - length += durationInCurrent / timeRange * current.Multiplier; + length += durationInCurrent / TimeRange * current.Multiplier; } return length; From 589c3a47e2e4cd7432f1dbd5c50725dc0c493ecf Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 30 Oct 2018 18:00:55 +0900 Subject: [PATCH 106/155] Remove state computation + updates from ISpeedChangeVisualiser --- .../Scrolling/ScrollingHitObjectContainer.cs | 101 ++++++++++++++---- .../ConstantSpeedChangeVisualiser.cs | 65 ++--------- .../Visualisers/ISpeedChangeVisualiser.cs | 23 ---- .../OverlappingSpeedChangeVisualiser.cs | 71 ++---------- .../SequentialSpeedChangeVisualiser.cs | 78 +++----------- 5 files changed, 110 insertions(+), 228 deletions(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index 52b4072523..31b9c22a2e 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics; using osu.Framework.Lists; using osu.Game.Configuration; using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Timing; using osu.Game.Rulesets.UI.Scrolling.Visualisers; @@ -29,30 +30,19 @@ namespace osu.Game.Rulesets.UI.Scrolling protected readonly SortedList ControlPoints = new SortedList(); public readonly Bindable Direction = new Bindable(); + private readonly SpeedChangeVisualisationMethod visualisationMethod; private Cached initialStateCache = new Cached(); - - private readonly ISpeedChangeVisualiser speedChangeVisualiser; + private ISpeedChangeVisualiser visualiser; public ScrollingHitObjectContainer(SpeedChangeVisualisationMethod visualisationMethod) { + this.visualisationMethod = visualisationMethod; + RelativeSizeAxes = Axes.Both; TimeRange.ValueChanged += _ => initialStateCache.Invalidate(); Direction.ValueChanged += _ => initialStateCache.Invalidate(); - - switch (visualisationMethod) - { - case SpeedChangeVisualisationMethod.Sequential: - speedChangeVisualiser = new SequentialSpeedChangeVisualiser(ControlPoints); - break; - case SpeedChangeVisualisationMethod.Overlapping: - speedChangeVisualiser = new OverlappingSpeedChangeVisualiser(ControlPoints); - break; - case SpeedChangeVisualisationMethod.Constant: - speedChangeVisualiser = new ConstantSpeedChangeVisualiser(); - break; - } } public override void Add(DrawableHitObject hitObject) @@ -95,23 +85,68 @@ namespace osu.Game.Rulesets.UI.Scrolling { base.Update(); - speedChangeVisualiser.TimeRange = TimeRange.Value; + if (!initialStateCache.IsValid) + { + visualiser = createVisualiser(); + + foreach (var obj in Objects) + computeInitialStateRecursive(obj); + initialStateCache.Validate(); + } + } + + private ISpeedChangeVisualiser createVisualiser() + { + float scrollLength; switch (Direction.Value) { case ScrollingDirection.Up: case ScrollingDirection.Down: - speedChangeVisualiser.ScrollLength = DrawSize.Y; + scrollLength = DrawSize.Y; break; default: - speedChangeVisualiser.ScrollLength = DrawSize.X; + scrollLength = DrawSize.X; break; } - if (!initialStateCache.IsValid) + switch (visualisationMethod) { - speedChangeVisualiser.ComputeInitialStates(Objects, Direction); - initialStateCache.Validate(); + default: + case SpeedChangeVisualisationMethod.Constant: + return new ConstantSpeedChangeVisualiser(TimeRange, scrollLength); + case SpeedChangeVisualisationMethod.Overlapping: + return new OverlappingSpeedChangeVisualiser(ControlPoints, TimeRange, scrollLength); + case SpeedChangeVisualisationMethod.Sequential: + return new SequentialSpeedChangeVisualiser(ControlPoints, TimeRange, scrollLength); + } + } + + private void computeInitialStateRecursive(DrawableHitObject hitObject) + { + hitObject.LifetimeStart = visualiser.GetDisplayStartTime(hitObject.HitObject.StartTime); + + if (hitObject.HitObject is IHasEndTime endTime) + { + switch (Direction.Value) + { + case ScrollingDirection.Up: + case ScrollingDirection.Down: + hitObject.Height = visualiser.GetLength(hitObject.HitObject.StartTime, endTime.EndTime); + break; + case ScrollingDirection.Left: + case ScrollingDirection.Right: + hitObject.Height = visualiser.GetLength(hitObject.HitObject.StartTime, endTime.EndTime); + break; + } + } + + foreach (var obj in hitObject.NestedHitObjects) + { + computeInitialStateRecursive(obj); + + // Nested hitobjects don't need to scroll, but they do need accurate positions + updatePosition(obj, hitObject.HitObject.StartTime); } } @@ -119,8 +154,28 @@ namespace osu.Game.Rulesets.UI.Scrolling { base.UpdateAfterChildrenLife(); - // We need to calculate this as soon as possible after lifetimes so that hitobjects get the final say in their positions - speedChangeVisualiser.UpdatePositions(AliveObjects, Direction, Time.Current); + // We need to calculate hitobject positions as soon as possible after lifetimes so that hitobjects get the final say in their positions + foreach (var obj in AliveObjects) + updatePosition(obj, Time.Current); + } + + private void updatePosition(DrawableHitObject hitObject, double currentTime) + { + switch (Direction.Value) + { + case ScrollingDirection.Up: + hitObject.Y = visualiser.PositionAt(currentTime, hitObject.HitObject.StartTime); + break; + case ScrollingDirection.Down: + hitObject.Y = -visualiser.PositionAt(currentTime, hitObject.HitObject.StartTime); + break; + case ScrollingDirection.Left: + hitObject.X = visualiser.PositionAt(currentTime, hitObject.HitObject.StartTime); + break; + case ScrollingDirection.Right: + hitObject.X = -visualiser.PositionAt(currentTime, hitObject.HitObject.StartTime); + break; + } } } } diff --git a/osu.Game/Rulesets/UI/Scrolling/Visualisers/ConstantSpeedChangeVisualiser.cs b/osu.Game/Rulesets/UI/Scrolling/Visualisers/ConstantSpeedChangeVisualiser.cs index f4417e393a..1d3020ec8b 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Visualisers/ConstantSpeedChangeVisualiser.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Visualisers/ConstantSpeedChangeVisualiser.cs @@ -1,69 +1,20 @@ // 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 osu.Game.Rulesets.Objects.Drawables; -using osu.Game.Rulesets.Objects.Types; - namespace osu.Game.Rulesets.UI.Scrolling.Visualisers { - public class ConstantSpeedChangeVisualiser : ISpeedChangeVisualiser + public readonly struct ConstantSpeedChangeVisualiser : ISpeedChangeVisualiser { - public double TimeRange { get; set; } + private readonly double timeRange; + private readonly float scrollLength; - public float ScrollLength { get; set; } - - public void ComputeInitialStates(IEnumerable hitObjects, ScrollingDirection direction) + public ConstantSpeedChangeVisualiser(double timeRange, float scrollLength) { - foreach (var obj in hitObjects) - { - obj.LifetimeStart = GetDisplayStartTime(obj.HitObject.StartTime); - - if (obj.HitObject is IHasEndTime endTime) - { - switch (direction) - { - case ScrollingDirection.Up: - case ScrollingDirection.Down: - obj.Height = GetLength(obj.HitObject.StartTime, endTime.EndTime); - break; - case ScrollingDirection.Left: - case ScrollingDirection.Right: - obj.Height = GetLength(obj.HitObject.StartTime, endTime.EndTime); - break; - } - } - - ComputeInitialStates(obj.NestedHitObjects, direction); - - // Nested hitobjects don't need to scroll, but they do need accurate positions - UpdatePositions(obj.NestedHitObjects, direction, obj.HitObject.StartTime); - } + this.timeRange = timeRange; + this.scrollLength = scrollLength; } - public void UpdatePositions(IEnumerable hitObjects, ScrollingDirection direction, double currentTime) - { - foreach (var obj in hitObjects) - { - switch (direction) - { - case ScrollingDirection.Up: - obj.Y = PositionAt(currentTime, obj.HitObject.StartTime); - break; - case ScrollingDirection.Down: - obj.Y = -PositionAt(currentTime, obj.HitObject.StartTime); - break; - case ScrollingDirection.Left: - obj.X = PositionAt(currentTime, obj.HitObject.StartTime); - break; - case ScrollingDirection.Right: - obj.X = -PositionAt(currentTime, obj.HitObject.StartTime); - break; - } - } - } - - public double GetDisplayStartTime(double startTime) => startTime - TimeRange; + public double GetDisplayStartTime(double startTime) => startTime - timeRange; public float GetLength(double startTime, double endTime) { @@ -72,6 +23,6 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers return -PositionAt(endTime, startTime); } - public float PositionAt(double currentTime, double startTime) => (float)((startTime - currentTime) / TimeRange * ScrollLength); + public float PositionAt(double currentTime, double startTime) => (float)((startTime - currentTime) / timeRange * scrollLength); } } diff --git a/osu.Game/Rulesets/UI/Scrolling/Visualisers/ISpeedChangeVisualiser.cs b/osu.Game/Rulesets/UI/Scrolling/Visualisers/ISpeedChangeVisualiser.cs index b7d611df50..478c10c6ce 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Visualisers/ISpeedChangeVisualiser.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Visualisers/ISpeedChangeVisualiser.cs @@ -1,33 +1,10 @@ // 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 osu.Game.Rulesets.Objects.Drawables; - namespace osu.Game.Rulesets.UI.Scrolling.Visualisers { public interface ISpeedChangeVisualiser { - double TimeRange { get; set; } - - float ScrollLength { get; set; } - - /// - /// Computes the states of s that remain constant while scrolling, such as lifetime and spatial length. - /// This is invoked once whenever or changes. - /// - /// The s whose states should be computed. - /// The scrolling direction. - void ComputeInitialStates(IEnumerable hitObjects, ScrollingDirection direction); - - /// - /// Updates the positions of s, depending on the current time. This is invoked once per frame. - /// - /// The s whose positions should be computed. - /// The scrolling direction. - /// The current time. - void UpdatePositions(IEnumerable hitObjects, ScrollingDirection direction, double currentTime); - double GetDisplayStartTime(double startTime); float GetLength(double startTime, double endTime); diff --git a/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs b/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs index f6fbe9063f..646ea0c280 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs @@ -1,81 +1,32 @@ // 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 osu.Framework.Lists; -using osu.Game.Rulesets.Objects.Drawables; -using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Timing; namespace osu.Game.Rulesets.UI.Scrolling.Visualisers { - public class OverlappingSpeedChangeVisualiser : ISpeedChangeVisualiser + public readonly struct OverlappingSpeedChangeVisualiser : ISpeedChangeVisualiser { - public double TimeRange { get; set; } - - public float ScrollLength { get; set; } + private readonly MultiplierControlPoint searchPoint; private readonly SortedList controlPoints; + private readonly double timeRange; + private readonly float scrollLength; - public OverlappingSpeedChangeVisualiser(SortedList controlPoints) + public OverlappingSpeedChangeVisualiser(SortedList controlPoints, double timeRange, float scrollLength) { this.controlPoints = controlPoints; - } + this.timeRange = timeRange; + this.scrollLength = scrollLength; - public void ComputeInitialStates(IEnumerable hitObjects, ScrollingDirection direction) - { - foreach (var obj in hitObjects) - { - obj.LifetimeStart = GetDisplayStartTime(obj.HitObject.StartTime); - - if (obj.HitObject is IHasEndTime endTime) - { - switch (direction) - { - case ScrollingDirection.Up: - case ScrollingDirection.Down: - obj.Height = GetLength(obj.HitObject.StartTime, endTime.EndTime); - break; - case ScrollingDirection.Left: - case ScrollingDirection.Right: - obj.Width = GetLength(obj.HitObject.StartTime, endTime.EndTime); - break; - } - } - - ComputeInitialStates(obj.NestedHitObjects, direction); - - // Nested hitobjects don't need to scroll, but they do need accurate positions - UpdatePositions(obj.NestedHitObjects, direction, obj.HitObject.StartTime); - } - } - - public void UpdatePositions(IEnumerable hitObjects, ScrollingDirection direction, double currentTime) - { - foreach (var obj in hitObjects) - { - switch (direction) - { - case ScrollingDirection.Up: - obj.Y = PositionAt(currentTime, obj.HitObject.StartTime); - break; - case ScrollingDirection.Down: - obj.Y = -PositionAt(currentTime, obj.HitObject.StartTime); - break; - case ScrollingDirection.Left: - obj.X = PositionAt(currentTime, obj.HitObject.StartTime); - break; - case ScrollingDirection.Right: - obj.X = -PositionAt(currentTime, obj.HitObject.StartTime); - break; - } - } + searchPoint = new MultiplierControlPoint(); } public double GetDisplayStartTime(double startTime) { // The total amount of time that the hitobject will remain visible within the timeRange, which decreases as the speed multiplier increases - double visibleDuration = TimeRange / controlPointAt(startTime).Multiplier; + double visibleDuration = timeRange / controlPointAt(startTime).Multiplier; return startTime - visibleDuration; } @@ -87,9 +38,7 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers } public float PositionAt(double currentTime, double startTime) - => (float)((startTime - currentTime) / TimeRange * controlPointAt(startTime).Multiplier * ScrollLength); - - private readonly MultiplierControlPoint searchPoint = new MultiplierControlPoint(); + => (float)((startTime - currentTime) / timeRange * controlPointAt(startTime).Multiplier * scrollLength); /// /// Finds the which affects the speed of hitobjects at a specific time. diff --git a/osu.Game/Rulesets/UI/Scrolling/Visualisers/SequentialSpeedChangeVisualiser.cs b/osu.Game/Rulesets/UI/Scrolling/Visualisers/SequentialSpeedChangeVisualiser.cs index 7b2471e674..9e8099fdb5 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Visualisers/SequentialSpeedChangeVisualiser.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Visualisers/SequentialSpeedChangeVisualiser.cs @@ -3,90 +3,40 @@ using System; using System.Collections.Generic; -using osu.Game.Rulesets.Objects.Drawables; -using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Timing; namespace osu.Game.Rulesets.UI.Scrolling.Visualisers { - public class SequentialSpeedChangeVisualiser : ISpeedChangeVisualiser + public readonly struct SequentialSpeedChangeVisualiser : ISpeedChangeVisualiser { - public double TimeRange { get; set; } - - public float ScrollLength { get; set; } - - private readonly Dictionary positionCache = new Dictionary(); + private readonly Dictionary positionCache; private readonly IReadOnlyList controlPoints; + private readonly double timeRange; + private readonly float scrollLength; - public SequentialSpeedChangeVisualiser(IReadOnlyList controlPoints) + public SequentialSpeedChangeVisualiser(IReadOnlyList controlPoints, double timeRange, float scrollLength) { this.controlPoints = controlPoints; + this.timeRange = timeRange; + this.scrollLength = scrollLength; + + positionCache = new Dictionary(); } - public void ComputeInitialStates(IEnumerable hitObjects, ScrollingDirection direction) - { - foreach (var obj in hitObjects) - { - obj.LifetimeStart = GetDisplayStartTime(obj.HitObject.StartTime); - - if (obj.HitObject is IHasEndTime endTime) - { - switch (direction) - { - case ScrollingDirection.Up: - case ScrollingDirection.Down: - obj.Height = GetLength(obj.HitObject.StartTime, endTime.EndTime); - break; - case ScrollingDirection.Left: - case ScrollingDirection.Right: - obj.Width = GetLength(obj.HitObject.StartTime, endTime.EndTime); - break; - } - } - - ComputeInitialStates(obj.NestedHitObjects, direction); - - // Nested hitobjects don't need to scroll, but they do need accurate positions - UpdatePositions(obj.NestedHitObjects, direction, obj.HitObject.StartTime); - } - } - - public void UpdatePositions(IEnumerable hitObjects, ScrollingDirection direction, double currentTime) - { - foreach (var obj in hitObjects) - { - switch (direction) - { - case ScrollingDirection.Up: - obj.Y = PositionAt(currentTime, obj.HitObject.StartTime); - break; - case ScrollingDirection.Down: - obj.Y = -PositionAt(currentTime, obj.HitObject.StartTime); - break; - case ScrollingDirection.Left: - obj.X = PositionAt(currentTime, obj.HitObject.StartTime); - break; - case ScrollingDirection.Right: - obj.X = -PositionAt(currentTime, obj.HitObject.StartTime); - break; - } - } - } - - public double GetDisplayStartTime(double startTime) => startTime - TimeRange - 1000; + public double GetDisplayStartTime(double startTime) => startTime - timeRange - 1000; public float GetLength(double startTime, double endTime) { var objectLength = relativePositionAtCached(endTime) - relativePositionAtCached(startTime); - return (float)(objectLength * ScrollLength); + return (float)(objectLength * scrollLength); } public float PositionAt(double currentTime, double startTime) { // Caching is not used here as currentTime is unlikely to have been previously cached double timelinePosition = relativePositionAt(currentTime); - return (float)((relativePositionAtCached(startTime) - timelinePosition) * ScrollLength); + return (float)((relativePositionAtCached(startTime) - timelinePosition) * scrollLength); } private double relativePositionAtCached(double time) @@ -106,7 +56,7 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers private double relativePositionAt(double time) { if (controlPoints.Count == 0) - return time / TimeRange; + return time / timeRange; double length = 0; @@ -130,7 +80,7 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers var durationInCurrent = Math.Min(currentDuration, time - current.StartTime); // Figure out how much of the time range the duration represents, and adjust it by the speed multiplier - length += durationInCurrent / TimeRange * current.Multiplier; + length += durationInCurrent / timeRange * current.Multiplier; } return length; From 76ea314c273718621020d4f5b07dcd3c83376d9a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 30 Oct 2018 18:04:13 +0900 Subject: [PATCH 107/155] Reorder params --- .../UI/Scrolling/ScrollingHitObjectContainer.cs | 8 ++++---- .../Visualisers/ConstantSpeedChangeVisualiser.cs | 6 +++--- .../Scrolling/Visualisers/ISpeedChangeVisualiser.cs | 4 ++-- .../Visualisers/OverlappingSpeedChangeVisualiser.cs | 12 ++++++------ .../Visualisers/SequentialSpeedChangeVisualiser.cs | 6 +++--- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index 31b9c22a2e..641c8066a5 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -164,16 +164,16 @@ namespace osu.Game.Rulesets.UI.Scrolling switch (Direction.Value) { case ScrollingDirection.Up: - hitObject.Y = visualiser.PositionAt(currentTime, hitObject.HitObject.StartTime); + hitObject.Y = visualiser.PositionAt(hitObject.HitObject.StartTime, currentTime); break; case ScrollingDirection.Down: - hitObject.Y = -visualiser.PositionAt(currentTime, hitObject.HitObject.StartTime); + hitObject.Y = -visualiser.PositionAt(hitObject.HitObject.StartTime, currentTime); break; case ScrollingDirection.Left: - hitObject.X = visualiser.PositionAt(currentTime, hitObject.HitObject.StartTime); + hitObject.X = visualiser.PositionAt(hitObject.HitObject.StartTime, currentTime); break; case ScrollingDirection.Right: - hitObject.X = -visualiser.PositionAt(currentTime, hitObject.HitObject.StartTime); + hitObject.X = -visualiser.PositionAt(hitObject.HitObject.StartTime, currentTime); break; } } diff --git a/osu.Game/Rulesets/UI/Scrolling/Visualisers/ConstantSpeedChangeVisualiser.cs b/osu.Game/Rulesets/UI/Scrolling/Visualisers/ConstantSpeedChangeVisualiser.cs index 1d3020ec8b..7c8f9018a9 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Visualisers/ConstantSpeedChangeVisualiser.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Visualisers/ConstantSpeedChangeVisualiser.cs @@ -14,15 +14,15 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers this.scrollLength = scrollLength; } - public double GetDisplayStartTime(double startTime) => startTime - timeRange; + public double GetDisplayStartTime(double time) => time - timeRange; public float GetLength(double startTime, double endTime) { // At the hitobject's end time, the hitobject will be positioned such that its end rests at the origin. // This results in a negative-position value, and the absolute of it indicates the length of the hitobject. - return -PositionAt(endTime, startTime); + return -PositionAt(startTime, endTime); } - public float PositionAt(double currentTime, double startTime) => (float)((startTime - currentTime) / timeRange * scrollLength); + public float PositionAt(double time, double currentTime) => (float)((time - currentTime) / timeRange * scrollLength); } } diff --git a/osu.Game/Rulesets/UI/Scrolling/Visualisers/ISpeedChangeVisualiser.cs b/osu.Game/Rulesets/UI/Scrolling/Visualisers/ISpeedChangeVisualiser.cs index 478c10c6ce..5e719b4f2a 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Visualisers/ISpeedChangeVisualiser.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Visualisers/ISpeedChangeVisualiser.cs @@ -5,10 +5,10 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers { public interface ISpeedChangeVisualiser { - double GetDisplayStartTime(double startTime); + double GetDisplayStartTime(double time); float GetLength(double startTime, double endTime); - float PositionAt(double currentTime, double startTime); + float PositionAt(double time, double currentTime); } } diff --git a/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs b/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs index 646ea0c280..1fbada4f4d 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs @@ -23,22 +23,22 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers searchPoint = new MultiplierControlPoint(); } - public double GetDisplayStartTime(double startTime) + public double GetDisplayStartTime(double time) { // The total amount of time that the hitobject will remain visible within the timeRange, which decreases as the speed multiplier increases - double visibleDuration = timeRange / controlPointAt(startTime).Multiplier; - return startTime - visibleDuration; + double visibleDuration = timeRange / controlPointAt(time).Multiplier; + return time - visibleDuration; } public float GetLength(double startTime, double endTime) { // At the hitobject's end time, the hitobject will be positioned such that its end rests at the origin. // This results in a negative-position value, and the absolute of it indicates the length of the hitobject. - return -PositionAt(endTime, startTime); + return -PositionAt(startTime, endTime); } - public float PositionAt(double currentTime, double startTime) - => (float)((startTime - currentTime) / timeRange * controlPointAt(startTime).Multiplier * scrollLength); + public float PositionAt(double time, double currentTime) + => (float)((time - currentTime) / timeRange * controlPointAt(time).Multiplier * scrollLength); /// /// Finds the which affects the speed of hitobjects at a specific time. diff --git a/osu.Game/Rulesets/UI/Scrolling/Visualisers/SequentialSpeedChangeVisualiser.cs b/osu.Game/Rulesets/UI/Scrolling/Visualisers/SequentialSpeedChangeVisualiser.cs index 9e8099fdb5..1fa87a2f6b 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Visualisers/SequentialSpeedChangeVisualiser.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Visualisers/SequentialSpeedChangeVisualiser.cs @@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers positionCache = new Dictionary(); } - public double GetDisplayStartTime(double startTime) => startTime - timeRange - 1000; + public double GetDisplayStartTime(double time) => time - timeRange - 1000; public float GetLength(double startTime, double endTime) { @@ -32,11 +32,11 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers return (float)(objectLength * scrollLength); } - public float PositionAt(double currentTime, double startTime) + public float PositionAt(double time, double currentTime) { // Caching is not used here as currentTime is unlikely to have been previously cached double timelinePosition = relativePositionAt(currentTime); - return (float)((relativePositionAtCached(startTime) - timelinePosition) * scrollLength); + return (float)((relativePositionAtCached(time) - timelinePosition) * scrollLength); } private double relativePositionAtCached(double time) From f41bfd14ca890730c71b646ccda47222213c85b3 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 30 Oct 2018 18:14:11 +0900 Subject: [PATCH 108/155] Add some xmldocs --- .../Visualisers/ISpeedChangeVisualiser.cs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/osu.Game/Rulesets/UI/Scrolling/Visualisers/ISpeedChangeVisualiser.cs b/osu.Game/Rulesets/UI/Scrolling/Visualisers/ISpeedChangeVisualiser.cs index 5e719b4f2a..b4435f558d 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Visualisers/ISpeedChangeVisualiser.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Visualisers/ISpeedChangeVisualiser.cs @@ -5,10 +5,30 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers { public interface ISpeedChangeVisualiser { + /// + /// Given a point in time, computes the time at which the point enters the visible time range of this . + /// + /// + /// E.g. For a constant visible time range of 5000ms, the time at which t=7000ms enters the visible time range is 2000ms. + /// + /// The time value. + /// The time at which enters the visible time range of this . double GetDisplayStartTime(double time); + /// + /// Computes the spatial length within a start and end time. + /// + /// The start time. + /// The end time. + /// The absolute spatial length. float GetLength(double startTime, double endTime); + /// + /// Given the current time, computes the spatial position of a point in time. + /// + /// The time to compute the spatial position of. + /// The current time. + /// The absolute spatial position. float PositionAt(double time, double currentTime); } } From 195f82fa966a0c07ff781dd8725faf8802b0f97b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 30 Oct 2018 18:33:24 +0900 Subject: [PATCH 109/155] Give visualiser methods range+length params again --- .../Scrolling/ScrollingHitObjectContainer.cs | 75 +++++++++---------- .../ConstantSpeedChangeVisualiser.cs | 24 +++--- .../Visualisers/ISpeedChangeVisualiser.cs | 24 ++++-- .../OverlappingSpeedChangeVisualiser.cs | 20 ++--- .../SequentialSpeedChangeVisualiser.cs | 28 ++++--- 5 files changed, 86 insertions(+), 85 deletions(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index 641c8066a5..3844a5903c 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -30,19 +30,30 @@ namespace osu.Game.Rulesets.UI.Scrolling protected readonly SortedList ControlPoints = new SortedList(); public readonly Bindable Direction = new Bindable(); - private readonly SpeedChangeVisualisationMethod visualisationMethod; + + private readonly ISpeedChangeVisualiser visualiser; private Cached initialStateCache = new Cached(); - private ISpeedChangeVisualiser visualiser; public ScrollingHitObjectContainer(SpeedChangeVisualisationMethod visualisationMethod) { - this.visualisationMethod = visualisationMethod; - RelativeSizeAxes = Axes.Both; TimeRange.ValueChanged += _ => initialStateCache.Invalidate(); Direction.ValueChanged += _ => initialStateCache.Invalidate(); + + switch (visualisationMethod) + { + case SpeedChangeVisualisationMethod.Sequential: + visualiser = new SequentialSpeedChangeVisualiser(ControlPoints); + break; + case SpeedChangeVisualisationMethod.Overlapping: + visualiser = new OverlappingSpeedChangeVisualiser(ControlPoints); + break; + case SpeedChangeVisualisationMethod.Constant: + visualiser = new ConstantSpeedChangeVisualiser(); + break; + } } public override void Add(DrawableHitObject hitObject) @@ -81,13 +92,26 @@ namespace osu.Game.Rulesets.UI.Scrolling return base.Invalidate(invalidation, source, shallPropagate); } + private float scrollLength; + protected override void Update() { base.Update(); if (!initialStateCache.IsValid) { - visualiser = createVisualiser(); + switch (Direction.Value) + { + case ScrollingDirection.Up: + case ScrollingDirection.Down: + scrollLength = DrawSize.Y; + break; + default: + scrollLength = DrawSize.X; + break; + } + + visualiser.Reset(); foreach (var obj in Objects) computeInitialStateRecursive(obj); @@ -95,36 +119,9 @@ namespace osu.Game.Rulesets.UI.Scrolling } } - private ISpeedChangeVisualiser createVisualiser() - { - float scrollLength; - - switch (Direction.Value) - { - case ScrollingDirection.Up: - case ScrollingDirection.Down: - scrollLength = DrawSize.Y; - break; - default: - scrollLength = DrawSize.X; - break; - } - - switch (visualisationMethod) - { - default: - case SpeedChangeVisualisationMethod.Constant: - return new ConstantSpeedChangeVisualiser(TimeRange, scrollLength); - case SpeedChangeVisualisationMethod.Overlapping: - return new OverlappingSpeedChangeVisualiser(ControlPoints, TimeRange, scrollLength); - case SpeedChangeVisualisationMethod.Sequential: - return new SequentialSpeedChangeVisualiser(ControlPoints, TimeRange, scrollLength); - } - } - private void computeInitialStateRecursive(DrawableHitObject hitObject) { - hitObject.LifetimeStart = visualiser.GetDisplayStartTime(hitObject.HitObject.StartTime); + hitObject.LifetimeStart = visualiser.GetDisplayStartTime(hitObject.HitObject.StartTime, TimeRange); if (hitObject.HitObject is IHasEndTime endTime) { @@ -132,11 +129,11 @@ namespace osu.Game.Rulesets.UI.Scrolling { case ScrollingDirection.Up: case ScrollingDirection.Down: - hitObject.Height = visualiser.GetLength(hitObject.HitObject.StartTime, endTime.EndTime); + hitObject.Height = visualiser.GetLength(hitObject.HitObject.StartTime, endTime.EndTime, TimeRange, scrollLength); break; case ScrollingDirection.Left: case ScrollingDirection.Right: - hitObject.Height = visualiser.GetLength(hitObject.HitObject.StartTime, endTime.EndTime); + hitObject.Height = visualiser.GetLength(hitObject.HitObject.StartTime, endTime.EndTime, TimeRange, scrollLength); break; } } @@ -164,16 +161,16 @@ namespace osu.Game.Rulesets.UI.Scrolling switch (Direction.Value) { case ScrollingDirection.Up: - hitObject.Y = visualiser.PositionAt(hitObject.HitObject.StartTime, currentTime); + hitObject.Y = visualiser.PositionAt(hitObject.HitObject.StartTime, currentTime, TimeRange, scrollLength); break; case ScrollingDirection.Down: - hitObject.Y = -visualiser.PositionAt(hitObject.HitObject.StartTime, currentTime); + hitObject.Y = -visualiser.PositionAt(hitObject.HitObject.StartTime, currentTime, TimeRange, scrollLength); break; case ScrollingDirection.Left: - hitObject.X = visualiser.PositionAt(hitObject.HitObject.StartTime, currentTime); + hitObject.X = visualiser.PositionAt(hitObject.HitObject.StartTime, currentTime, TimeRange, scrollLength); break; case ScrollingDirection.Right: - hitObject.X = -visualiser.PositionAt(hitObject.HitObject.StartTime, currentTime); + hitObject.X = -visualiser.PositionAt(hitObject.HitObject.StartTime, currentTime, TimeRange, scrollLength); break; } } diff --git a/osu.Game/Rulesets/UI/Scrolling/Visualisers/ConstantSpeedChangeVisualiser.cs b/osu.Game/Rulesets/UI/Scrolling/Visualisers/ConstantSpeedChangeVisualiser.cs index 7c8f9018a9..09710392c9 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Visualisers/ConstantSpeedChangeVisualiser.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Visualisers/ConstantSpeedChangeVisualiser.cs @@ -3,26 +3,22 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers { - public readonly struct ConstantSpeedChangeVisualiser : ISpeedChangeVisualiser + public class ConstantSpeedChangeVisualiser : ISpeedChangeVisualiser { - private readonly double timeRange; - private readonly float scrollLength; + public double GetDisplayStartTime(double time, double timeRange) => time - timeRange; - public ConstantSpeedChangeVisualiser(double timeRange, float scrollLength) - { - this.timeRange = timeRange; - this.scrollLength = scrollLength; - } - - public double GetDisplayStartTime(double time) => time - timeRange; - - public float GetLength(double startTime, double endTime) + public float GetLength(double startTime, double endTime, double timeRange, float scrollLength) { // At the hitobject's end time, the hitobject will be positioned such that its end rests at the origin. // This results in a negative-position value, and the absolute of it indicates the length of the hitobject. - return -PositionAt(startTime, endTime); + return -PositionAt(startTime, endTime, timeRange, scrollLength); } - public float PositionAt(double time, double currentTime) => (float)((time - currentTime) / timeRange * scrollLength); + public float PositionAt(double time, double currentTime, double timeRange, float scrollLength) + => (float)((time - currentTime) / timeRange * scrollLength); + + public void Reset() + { + } } } diff --git a/osu.Game/Rulesets/UI/Scrolling/Visualisers/ISpeedChangeVisualiser.cs b/osu.Game/Rulesets/UI/Scrolling/Visualisers/ISpeedChangeVisualiser.cs index b4435f558d..f950e7f375 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Visualisers/ISpeedChangeVisualiser.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Visualisers/ISpeedChangeVisualiser.cs @@ -6,29 +6,39 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers public interface ISpeedChangeVisualiser { /// - /// Given a point in time, computes the time at which the point enters the visible time range of this . + /// Given a point in time, computes the time at which it enters the time range. /// /// - /// E.g. For a constant visible time range of 5000ms, the time at which t=7000ms enters the visible time range is 2000ms. + /// E.g. For a constant time range of 5000ms, the time at which t=7000ms enters the time range is 2000ms. /// - /// The time value. - /// The time at which enters the visible time range of this . - double GetDisplayStartTime(double time); + /// The point in time. + /// The amount of visible time. + /// The time at which enters . + double GetDisplayStartTime(double time, double timeRange); /// /// Computes the spatial length within a start and end time. /// /// The start time. /// The end time. + /// The amount of visible time. + /// The absolute spatial length through . /// The absolute spatial length. - float GetLength(double startTime, double endTime); + float GetLength(double startTime, double endTime, double timeRange, float scrollLength); /// /// Given the current time, computes the spatial position of a point in time. /// /// The time to compute the spatial position of. /// The current time. + /// The amount of visible time. + /// The absolute spatial length through . /// The absolute spatial position. - float PositionAt(double time, double currentTime); + float PositionAt(double time, double currentTime, double timeRange, float scrollLength); + + /// + /// Resets this to a default state. + /// + void Reset(); } } diff --git a/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs b/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs index 1fbada4f4d..8b0eacc26b 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs @@ -6,40 +6,40 @@ using osu.Game.Rulesets.Timing; namespace osu.Game.Rulesets.UI.Scrolling.Visualisers { - public readonly struct OverlappingSpeedChangeVisualiser : ISpeedChangeVisualiser + public class OverlappingSpeedChangeVisualiser : ISpeedChangeVisualiser { private readonly MultiplierControlPoint searchPoint; private readonly SortedList controlPoints; - private readonly double timeRange; - private readonly float scrollLength; - public OverlappingSpeedChangeVisualiser(SortedList controlPoints, double timeRange, float scrollLength) + public OverlappingSpeedChangeVisualiser(SortedList controlPoints) { this.controlPoints = controlPoints; - this.timeRange = timeRange; - this.scrollLength = scrollLength; searchPoint = new MultiplierControlPoint(); } - public double GetDisplayStartTime(double time) + public double GetDisplayStartTime(double time, double timeRange) { // The total amount of time that the hitobject will remain visible within the timeRange, which decreases as the speed multiplier increases double visibleDuration = timeRange / controlPointAt(time).Multiplier; return time - visibleDuration; } - public float GetLength(double startTime, double endTime) + public float GetLength(double startTime, double endTime, double timeRange, float scrollLength) { // At the hitobject's end time, the hitobject will be positioned such that its end rests at the origin. // This results in a negative-position value, and the absolute of it indicates the length of the hitobject. - return -PositionAt(startTime, endTime); + return -PositionAt(startTime, endTime, timeRange, scrollLength); } - public float PositionAt(double time, double currentTime) + public float PositionAt(double time, double currentTime, double timeRange, float scrollLength) => (float)((time - currentTime) / timeRange * controlPointAt(time).Multiplier * scrollLength); + public void Reset() + { + } + /// /// Finds the which affects the speed of hitobjects at a specific time. /// diff --git a/osu.Game/Rulesets/UI/Scrolling/Visualisers/SequentialSpeedChangeVisualiser.cs b/osu.Game/Rulesets/UI/Scrolling/Visualisers/SequentialSpeedChangeVisualiser.cs index 1fa87a2f6b..bc63299bc8 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Visualisers/SequentialSpeedChangeVisualiser.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Visualisers/SequentialSpeedChangeVisualiser.cs @@ -7,45 +7,43 @@ using osu.Game.Rulesets.Timing; namespace osu.Game.Rulesets.UI.Scrolling.Visualisers { - public readonly struct SequentialSpeedChangeVisualiser : ISpeedChangeVisualiser + public class SequentialSpeedChangeVisualiser : ISpeedChangeVisualiser { private readonly Dictionary positionCache; private readonly IReadOnlyList controlPoints; - private readonly double timeRange; - private readonly float scrollLength; - public SequentialSpeedChangeVisualiser(IReadOnlyList controlPoints, double timeRange, float scrollLength) + public SequentialSpeedChangeVisualiser(IReadOnlyList controlPoints) { this.controlPoints = controlPoints; - this.timeRange = timeRange; - this.scrollLength = scrollLength; positionCache = new Dictionary(); } - public double GetDisplayStartTime(double time) => time - timeRange - 1000; + public double GetDisplayStartTime(double time, double timeRange) => time - timeRange - 1000; - public float GetLength(double startTime, double endTime) + public float GetLength(double startTime, double endTime, double timeRange, float scrollLength) { - var objectLength = relativePositionAtCached(endTime) - relativePositionAtCached(startTime); + var objectLength = relativePositionAtCached(endTime, timeRange) - relativePositionAtCached(startTime, timeRange); return (float)(objectLength * scrollLength); } - public float PositionAt(double time, double currentTime) + public float PositionAt(double time, double currentTime, double timeRange, float scrollLength) { // Caching is not used here as currentTime is unlikely to have been previously cached - double timelinePosition = relativePositionAt(currentTime); - return (float)((relativePositionAtCached(time) - timelinePosition) * scrollLength); + double timelinePosition = relativePositionAt(currentTime, timeRange); + return (float)((relativePositionAtCached(time, timeRange) - timelinePosition) * scrollLength); } - private double relativePositionAtCached(double time) + private double relativePositionAtCached(double time, double timeRange) { if (!positionCache.TryGetValue(time, out double existing)) - positionCache[time] = existing = relativePositionAt(time); + positionCache[time] = existing = relativePositionAt(time, timeRange); return existing; } + public void Reset() => positionCache.Clear(); + /// /// Finds the position which corresponds to a point in time. /// This is a non-linear operation that depends on all the control points up to and including the one active at the time value. @@ -53,7 +51,7 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers /// The time to find the position at. /// The amount of time visualised by the scrolling area. /// A positive value indicating the position at . - private double relativePositionAt(double time) + private double relativePositionAt(double time, double timeRange) { if (controlPoints.Count == 0) return time / timeRange; From 2f87f267a3b6be261aaf143305135911d224158e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 2 Nov 2018 19:45:32 +0900 Subject: [PATCH 110/155] Fix height being set instead of width --- osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index 3844a5903c..cc5d7e7751 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -133,7 +133,7 @@ namespace osu.Game.Rulesets.UI.Scrolling break; case ScrollingDirection.Left: case ScrollingDirection.Right: - hitObject.Height = visualiser.GetLength(hitObject.HitObject.StartTime, endTime.EndTime, TimeRange, scrollLength); + hitObject.Width = visualiser.GetLength(hitObject.HitObject.StartTime, endTime.EndTime, TimeRange, scrollLength); break; } } From f66a9f4f1e384c96879e2ef764f62daec8ab3325 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 2 Nov 2018 19:51:34 +0900 Subject: [PATCH 111/155] Rename IScrollChangeVisualiser -> IScrollAlgorithm --- osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs | 2 +- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 2 +- ...ualisationMethod.cs => ScrollAlgorithm.cs} | 2 +- .../Scrolling/ScrollingHitObjectContainer.cs | 34 +++++++++---------- .../UI/Scrolling/ScrollingPlayfield.cs | 4 +-- ...sualiser.cs => ConstantScrollAlgorithm.cs} | 2 +- ...hangeVisualiser.cs => IScrollAlgorithm.cs} | 4 +-- ...liser.cs => OverlappingScrollAlgorithm.cs} | 4 +-- ...aliser.cs => SequentialScrollAlgorithm.cs} | 4 +-- 9 files changed, 29 insertions(+), 29 deletions(-) rename osu.Game/Configuration/{SpeedChangeVisualisationMethod.cs => ScrollAlgorithm.cs} (89%) rename osu.Game/Rulesets/UI/Scrolling/Visualisers/{ConstantSpeedChangeVisualiser.cs => ConstantScrollAlgorithm.cs} (93%) rename osu.Game/Rulesets/UI/Scrolling/Visualisers/{ISpeedChangeVisualiser.cs => IScrollAlgorithm.cs} (94%) rename osu.Game/Rulesets/UI/Scrolling/Visualisers/{OverlappingSpeedChangeVisualiser.cs => OverlappingScrollAlgorithm.cs} (93%) rename osu.Game/Rulesets/UI/Scrolling/Visualisers/{SequentialSpeedChangeVisualiser.cs => SequentialScrollAlgorithm.cs} (95%) diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs index 925e7aaac9..160d784f5f 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Catch.UI protected override bool UserScrollSpeedAdjustment => false; - protected override SpeedChangeVisualisationMethod VisualisationMethod => SpeedChangeVisualisationMethod.Constant; + protected override ScrollAlgorithm ScrollAlgorithm => ScrollAlgorithm.Constant; public CatchPlayfield(BeatmapDifficulty difficulty, Func> getVisualRepresentation) { diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 40ed659bd6..eab2965160 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Taiko.UI protected override bool UserScrollSpeedAdjustment => false; - protected override SpeedChangeVisualisationMethod VisualisationMethod => SpeedChangeVisualisationMethod.Overlapping; + protected override ScrollAlgorithm ScrollAlgorithm => ScrollAlgorithm.Overlapping; private readonly Container hitExplosionContainer; private readonly Container kiaiExplosionContainer; diff --git a/osu.Game/Configuration/SpeedChangeVisualisationMethod.cs b/osu.Game/Configuration/ScrollAlgorithm.cs similarity index 89% rename from osu.Game/Configuration/SpeedChangeVisualisationMethod.cs rename to osu.Game/Configuration/ScrollAlgorithm.cs index 39c6e5649c..be302d38f6 100644 --- a/osu.Game/Configuration/SpeedChangeVisualisationMethod.cs +++ b/osu.Game/Configuration/ScrollAlgorithm.cs @@ -5,7 +5,7 @@ using System.ComponentModel; namespace osu.Game.Configuration { - public enum SpeedChangeVisualisationMethod + public enum ScrollAlgorithm { [Description("Sequential")] Sequential, diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index cc5d7e7751..78032ddba9 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -31,27 +31,27 @@ namespace osu.Game.Rulesets.UI.Scrolling public readonly Bindable Direction = new Bindable(); - private readonly ISpeedChangeVisualiser visualiser; + private readonly IScrollAlgorithm algorithm; private Cached initialStateCache = new Cached(); - public ScrollingHitObjectContainer(SpeedChangeVisualisationMethod visualisationMethod) + public ScrollingHitObjectContainer(ScrollAlgorithm scrollAlgorithm) { RelativeSizeAxes = Axes.Both; TimeRange.ValueChanged += _ => initialStateCache.Invalidate(); Direction.ValueChanged += _ => initialStateCache.Invalidate(); - switch (visualisationMethod) + switch (scrollAlgorithm) { - case SpeedChangeVisualisationMethod.Sequential: - visualiser = new SequentialSpeedChangeVisualiser(ControlPoints); + case ScrollAlgorithm.Sequential: + algorithm = new SequentialScrollAlgorithm(ControlPoints); break; - case SpeedChangeVisualisationMethod.Overlapping: - visualiser = new OverlappingSpeedChangeVisualiser(ControlPoints); + case ScrollAlgorithm.Overlapping: + algorithm = new OverlappingScrollAlgorithm(ControlPoints); break; - case SpeedChangeVisualisationMethod.Constant: - visualiser = new ConstantSpeedChangeVisualiser(); + case ScrollAlgorithm.Constant: + algorithm = new ConstantScrollAlgorithm(); break; } } @@ -111,7 +111,7 @@ namespace osu.Game.Rulesets.UI.Scrolling break; } - visualiser.Reset(); + algorithm.Reset(); foreach (var obj in Objects) computeInitialStateRecursive(obj); @@ -121,7 +121,7 @@ namespace osu.Game.Rulesets.UI.Scrolling private void computeInitialStateRecursive(DrawableHitObject hitObject) { - hitObject.LifetimeStart = visualiser.GetDisplayStartTime(hitObject.HitObject.StartTime, TimeRange); + hitObject.LifetimeStart = algorithm.GetDisplayStartTime(hitObject.HitObject.StartTime, TimeRange); if (hitObject.HitObject is IHasEndTime endTime) { @@ -129,11 +129,11 @@ namespace osu.Game.Rulesets.UI.Scrolling { case ScrollingDirection.Up: case ScrollingDirection.Down: - hitObject.Height = visualiser.GetLength(hitObject.HitObject.StartTime, endTime.EndTime, TimeRange, scrollLength); + hitObject.Height = algorithm.GetLength(hitObject.HitObject.StartTime, endTime.EndTime, TimeRange, scrollLength); break; case ScrollingDirection.Left: case ScrollingDirection.Right: - hitObject.Width = visualiser.GetLength(hitObject.HitObject.StartTime, endTime.EndTime, TimeRange, scrollLength); + hitObject.Width = algorithm.GetLength(hitObject.HitObject.StartTime, endTime.EndTime, TimeRange, scrollLength); break; } } @@ -161,16 +161,16 @@ namespace osu.Game.Rulesets.UI.Scrolling switch (Direction.Value) { case ScrollingDirection.Up: - hitObject.Y = visualiser.PositionAt(hitObject.HitObject.StartTime, currentTime, TimeRange, scrollLength); + hitObject.Y = algorithm.PositionAt(hitObject.HitObject.StartTime, currentTime, TimeRange, scrollLength); break; case ScrollingDirection.Down: - hitObject.Y = -visualiser.PositionAt(hitObject.HitObject.StartTime, currentTime, TimeRange, scrollLength); + hitObject.Y = -algorithm.PositionAt(hitObject.HitObject.StartTime, currentTime, TimeRange, scrollLength); break; case ScrollingDirection.Left: - hitObject.X = visualiser.PositionAt(hitObject.HitObject.StartTime, currentTime, TimeRange, scrollLength); + hitObject.X = algorithm.PositionAt(hitObject.HitObject.StartTime, currentTime, TimeRange, scrollLength); break; case ScrollingDirection.Right: - hitObject.X = -visualiser.PositionAt(hitObject.HitObject.StartTime, currentTime, TimeRange, scrollLength); + hitObject.X = -algorithm.PositionAt(hitObject.HitObject.StartTime, currentTime, TimeRange, scrollLength); break; } } diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs index a1fc13ce4d..b0367444bb 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs @@ -63,7 +63,7 @@ namespace osu.Game.Rulesets.UI.Scrolling /// protected readonly Bindable Direction = new Bindable(); - protected virtual SpeedChangeVisualisationMethod VisualisationMethod => SpeedChangeVisualisationMethod.Sequential; + protected virtual ScrollAlgorithm ScrollAlgorithm => ScrollAlgorithm.Sequential; [BackgroundDependencyLoader] private void load() @@ -93,7 +93,7 @@ namespace osu.Game.Rulesets.UI.Scrolling protected sealed override HitObjectContainer CreateHitObjectContainer() { - var container = new ScrollingHitObjectContainer(VisualisationMethod); + var container = new ScrollingHitObjectContainer(ScrollAlgorithm); container.Direction.BindTo(Direction); return container; } diff --git a/osu.Game/Rulesets/UI/Scrolling/Visualisers/ConstantSpeedChangeVisualiser.cs b/osu.Game/Rulesets/UI/Scrolling/Visualisers/ConstantScrollAlgorithm.cs similarity index 93% rename from osu.Game/Rulesets/UI/Scrolling/Visualisers/ConstantSpeedChangeVisualiser.cs rename to osu.Game/Rulesets/UI/Scrolling/Visualisers/ConstantScrollAlgorithm.cs index 09710392c9..cab8ec45a5 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Visualisers/ConstantSpeedChangeVisualiser.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Visualisers/ConstantScrollAlgorithm.cs @@ -3,7 +3,7 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers { - public class ConstantSpeedChangeVisualiser : ISpeedChangeVisualiser + public class ConstantScrollAlgorithm : IScrollAlgorithm { public double GetDisplayStartTime(double time, double timeRange) => time - timeRange; diff --git a/osu.Game/Rulesets/UI/Scrolling/Visualisers/ISpeedChangeVisualiser.cs b/osu.Game/Rulesets/UI/Scrolling/Visualisers/IScrollAlgorithm.cs similarity index 94% rename from osu.Game/Rulesets/UI/Scrolling/Visualisers/ISpeedChangeVisualiser.cs rename to osu.Game/Rulesets/UI/Scrolling/Visualisers/IScrollAlgorithm.cs index f950e7f375..7d72f93962 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Visualisers/ISpeedChangeVisualiser.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Visualisers/IScrollAlgorithm.cs @@ -3,7 +3,7 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers { - public interface ISpeedChangeVisualiser + public interface IScrollAlgorithm { /// /// Given a point in time, computes the time at which it enters the time range. @@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers float PositionAt(double time, double currentTime, double timeRange, float scrollLength); /// - /// Resets this to a default state. + /// Resets this to a default state. /// void Reset(); } diff --git a/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs b/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingScrollAlgorithm.cs similarity index 93% rename from osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs rename to osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingScrollAlgorithm.cs index 8b0eacc26b..392d7a1c51 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingScrollAlgorithm.cs @@ -6,13 +6,13 @@ using osu.Game.Rulesets.Timing; namespace osu.Game.Rulesets.UI.Scrolling.Visualisers { - public class OverlappingSpeedChangeVisualiser : ISpeedChangeVisualiser + public class OverlappingScrollAlgorithm : IScrollAlgorithm { private readonly MultiplierControlPoint searchPoint; private readonly SortedList controlPoints; - public OverlappingSpeedChangeVisualiser(SortedList controlPoints) + public OverlappingScrollAlgorithm(SortedList controlPoints) { this.controlPoints = controlPoints; diff --git a/osu.Game/Rulesets/UI/Scrolling/Visualisers/SequentialSpeedChangeVisualiser.cs b/osu.Game/Rulesets/UI/Scrolling/Visualisers/SequentialScrollAlgorithm.cs similarity index 95% rename from osu.Game/Rulesets/UI/Scrolling/Visualisers/SequentialSpeedChangeVisualiser.cs rename to osu.Game/Rulesets/UI/Scrolling/Visualisers/SequentialScrollAlgorithm.cs index bc63299bc8..ff058cfdcf 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Visualisers/SequentialSpeedChangeVisualiser.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Visualisers/SequentialScrollAlgorithm.cs @@ -7,13 +7,13 @@ using osu.Game.Rulesets.Timing; namespace osu.Game.Rulesets.UI.Scrolling.Visualisers { - public class SequentialSpeedChangeVisualiser : ISpeedChangeVisualiser + public class SequentialScrollAlgorithm : IScrollAlgorithm { private readonly Dictionary positionCache; private readonly IReadOnlyList controlPoints; - public SequentialSpeedChangeVisualiser(IReadOnlyList controlPoints) + public SequentialScrollAlgorithm(IReadOnlyList controlPoints) { this.controlPoints = controlPoints; From 33056b80987f48c8ba6eccb4cce85e3e675956b7 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 2 Nov 2018 19:52:40 +0900 Subject: [PATCH 112/155] Adjust namespaces --- .../{Visualisers => Algorithms}/ConstantScrollAlgorithm.cs | 2 +- .../Scrolling/{Visualisers => Algorithms}/IScrollAlgorithm.cs | 2 +- .../{Visualisers => Algorithms}/OverlappingScrollAlgorithm.cs | 2 +- .../{Visualisers => Algorithms}/SequentialScrollAlgorithm.cs | 2 +- osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) rename osu.Game/Rulesets/UI/Scrolling/{Visualisers => Algorithms}/ConstantScrollAlgorithm.cs (94%) rename osu.Game/Rulesets/UI/Scrolling/{Visualisers => Algorithms}/IScrollAlgorithm.cs (97%) rename osu.Game/Rulesets/UI/Scrolling/{Visualisers => Algorithms}/OverlappingScrollAlgorithm.cs (97%) rename osu.Game/Rulesets/UI/Scrolling/{Visualisers => Algorithms}/SequentialScrollAlgorithm.cs (98%) diff --git a/osu.Game/Rulesets/UI/Scrolling/Visualisers/ConstantScrollAlgorithm.cs b/osu.Game/Rulesets/UI/Scrolling/Algorithms/ConstantScrollAlgorithm.cs similarity index 94% rename from osu.Game/Rulesets/UI/Scrolling/Visualisers/ConstantScrollAlgorithm.cs rename to osu.Game/Rulesets/UI/Scrolling/Algorithms/ConstantScrollAlgorithm.cs index cab8ec45a5..ed61ed7022 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Visualisers/ConstantScrollAlgorithm.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Algorithms/ConstantScrollAlgorithm.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 -namespace osu.Game.Rulesets.UI.Scrolling.Visualisers +namespace osu.Game.Rulesets.UI.Scrolling.Algorithms { public class ConstantScrollAlgorithm : IScrollAlgorithm { diff --git a/osu.Game/Rulesets/UI/Scrolling/Visualisers/IScrollAlgorithm.cs b/osu.Game/Rulesets/UI/Scrolling/Algorithms/IScrollAlgorithm.cs similarity index 97% rename from osu.Game/Rulesets/UI/Scrolling/Visualisers/IScrollAlgorithm.cs rename to osu.Game/Rulesets/UI/Scrolling/Algorithms/IScrollAlgorithm.cs index 7d72f93962..43bc1b2a2a 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Visualisers/IScrollAlgorithm.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Algorithms/IScrollAlgorithm.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 -namespace osu.Game.Rulesets.UI.Scrolling.Visualisers +namespace osu.Game.Rulesets.UI.Scrolling.Algorithms { public interface IScrollAlgorithm { diff --git a/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingScrollAlgorithm.cs b/osu.Game/Rulesets/UI/Scrolling/Algorithms/OverlappingScrollAlgorithm.cs similarity index 97% rename from osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingScrollAlgorithm.cs rename to osu.Game/Rulesets/UI/Scrolling/Algorithms/OverlappingScrollAlgorithm.cs index 392d7a1c51..f7c097e81d 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingScrollAlgorithm.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Algorithms/OverlappingScrollAlgorithm.cs @@ -4,7 +4,7 @@ using osu.Framework.Lists; using osu.Game.Rulesets.Timing; -namespace osu.Game.Rulesets.UI.Scrolling.Visualisers +namespace osu.Game.Rulesets.UI.Scrolling.Algorithms { public class OverlappingScrollAlgorithm : IScrollAlgorithm { diff --git a/osu.Game/Rulesets/UI/Scrolling/Visualisers/SequentialScrollAlgorithm.cs b/osu.Game/Rulesets/UI/Scrolling/Algorithms/SequentialScrollAlgorithm.cs similarity index 98% rename from osu.Game/Rulesets/UI/Scrolling/Visualisers/SequentialScrollAlgorithm.cs rename to osu.Game/Rulesets/UI/Scrolling/Algorithms/SequentialScrollAlgorithm.cs index ff058cfdcf..54494cfe63 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Visualisers/SequentialScrollAlgorithm.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Algorithms/SequentialScrollAlgorithm.cs @@ -5,7 +5,7 @@ using System; using System.Collections.Generic; using osu.Game.Rulesets.Timing; -namespace osu.Game.Rulesets.UI.Scrolling.Visualisers +namespace osu.Game.Rulesets.UI.Scrolling.Algorithms { public class SequentialScrollAlgorithm : IScrollAlgorithm { diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index 78032ddba9..45bc95a71c 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -9,7 +9,7 @@ using osu.Game.Configuration; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Timing; -using osu.Game.Rulesets.UI.Scrolling.Visualisers; +using osu.Game.Rulesets.UI.Scrolling.Algorithms; namespace osu.Game.Rulesets.UI.Scrolling { From d0b63e8f8d67463f277c465e805ee379592f7138 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 8 Nov 2018 14:13:57 +0900 Subject: [PATCH 113/155] Fix missing references --- .../Edit/Blueprints/HoldNoteSelectionBlueprint.cs | 1 + .../Edit/Blueprints/NoteSelectionBlueprint.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs index 2cb0597a40..b707f88852 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs @@ -6,6 +6,7 @@ using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Primitives; using osu.Game.Graphics; +using osu.Game.Rulesets.Mania.Edit.Masks; using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; using osu.Game.Rulesets.Mania.UI; diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/NoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/NoteSelectionBlueprint.cs index 0ad99f9709..dd6adfc230 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/NoteSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/NoteSelectionBlueprint.cs @@ -4,6 +4,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Graphics; +using osu.Game.Rulesets.Mania.Edit.Masks; using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; From 4783df1d4ba8ea8335f1f65934d685a71fe464d5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 9 Nov 2018 11:36:06 +0900 Subject: [PATCH 114/155] Fix compose mode not working --- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 485c1921cf..932cfe5789 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -64,7 +64,7 @@ namespace osu.Game.Rulesets.Edit layerBelowRuleset.Child = new EditorPlayfieldBorder { RelativeSizeAxes = Axes.Both }; var layerAboveRuleset = CreateLayerContainer(); - layerAboveRuleset.Child = new BlueprintContainer(); + layerAboveRuleset.Child = blueprintContainer = new BlueprintContainer(); layerContainers.Add(layerBelowRuleset); layerContainers.Add(layerAboveRuleset); From 54ab256c8e01e369ae664408e29e25f5161e12e5 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 1 Nov 2018 15:38:19 +0900 Subject: [PATCH 115/155] Instantiate a new path rather than setting properties on it # Conflicts: # osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs # osu.Game.Rulesets.Catch/Objects/JuiceStream.cs # osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs # osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs # osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs # osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs # osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs # osu.Game/Rulesets/Objects/SliderPath.cs --- .../TestCaseAutoJuiceStream.cs | 7 +- .../Beatmaps/CatchBeatmapConverter.cs | 4 +- .../Objects/JuiceStream.cs | 27 ++-- osu.Game.Rulesets.Osu.Tests/TestCaseSlider.cs | 40 +++--- .../TestCaseSliderSelectionBlueprint.cs | 7 +- .../Beatmaps/OsuBeatmapConverter.cs | 4 +- .../Components/PathControlPointPiece.cs | 16 +-- .../Components/PathControlPointVisualiser.cs | 6 +- .../Sliders/Components/SliderCirclePiece.cs | 2 +- osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs | 9 +- .../Objects/Drawables/DrawableSlider.cs | 2 +- .../Objects/Drawables/DrawableSliderHead.cs | 2 +- .../Objects/Drawables/DrawableSliderTail.cs | 2 +- osu.Game.Rulesets.Osu/Objects/Slider.cs | 30 ++--- .../Visual/TestCaseHitObjectComposer.cs | 6 +- .../Legacy/Catch/ConvertHitObjectParser.cs | 4 +- .../Rulesets/Objects/Legacy/ConvertSlider.cs | 7 +- .../Legacy/Mania/ConvertHitObjectParser.cs | 4 +- .../Legacy/Osu/ConvertHitObjectParser.cs | 4 +- .../Legacy/Taiko/ConvertHitObjectParser.cs | 4 +- osu.Game/Rulesets/Objects/SliderPath.cs | 122 +++++++----------- osu.Game/Rulesets/Objects/Types/IHasCurve.cs | 10 -- 22 files changed, 117 insertions(+), 202 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestCaseAutoJuiceStream.cs b/osu.Game.Rulesets.Catch.Tests/TestCaseAutoJuiceStream.cs index cac1356c81..bea64302c3 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestCaseAutoJuiceStream.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestCaseAutoJuiceStream.cs @@ -5,6 +5,7 @@ using System.Linq; using osu.Game.Beatmaps; using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.UI; +using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; using osu.Game.Screens.Play; using osu.Game.Tests.Visual; @@ -37,13 +38,11 @@ namespace osu.Game.Rulesets.Catch.Tests beatmap.HitObjects.Add(new JuiceStream { X = 0.5f - width / 2, - ControlPoints = new[] + Path = new SliderPath(PathType.Linear, new[] { Vector2.Zero, new Vector2(width * CatchPlayfield.BASE_WIDTH, 0) - }, - PathType = PathType.Linear, - Distance = width * CatchPlayfield.BASE_WIDTH, + }), StartTime = i * 2000, NewCombo = i % 8 == 0 }); diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs index fed65c42af..c3dc9499c2 100644 --- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs +++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs @@ -34,9 +34,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps { StartTime = obj.StartTime, Samples = obj.Samples, - ControlPoints = curveData.ControlPoints, - PathType = curveData.PathType, - Distance = curveData.Distance, + Path = curveData.Path, NodeSamples = curveData.NodeSamples, RepeatCount = curveData.RepeatCount, X = (positionData?.X ?? 0) / CatchPlayfield.BASE_WIDTH, diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index f1e131932b..a4e04ae837 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -10,7 +10,6 @@ using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; -using OpenTK; namespace osu.Game.Rulesets.Catch.Objects { @@ -50,7 +49,7 @@ namespace osu.Game.Rulesets.Catch.Objects if (TickDistance == 0) return; - var length = Path.Distance; + var length = Path.GetDistance(); var tickDistance = Math.Min(TickDistance, length); var spanDuration = length / Velocity; @@ -132,34 +131,24 @@ namespace osu.Game.Rulesets.Catch.Objects } } - public double EndTime => StartTime + this.SpanCount() * Path.Distance / Velocity; + public double EndTime => StartTime + this.SpanCount() * Path.GetDistance() / Velocity; public float EndX => X + this.CurvePositionAt(1).X / CatchPlayfield.BASE_WIDTH; public double Duration => EndTime - StartTime; - public double Distance + private SliderPath path; + + public SliderPath Path { - get { return Path.Distance; } - set { Path.Distance = value; } + get => path; + set => path = value; } - public SliderPath Path { get; } = new SliderPath(); - - public Vector2[] ControlPoints - { - get { return Path.ControlPoints; } - set { Path.ControlPoints = value; } - } + public double Distance => Path.GetDistance(); public List> NodeSamples { get; set; } = new List>(); - public PathType PathType - { - get { return Path.PathType; } - set { Path.PathType = value; } - } - public double? LegacyLastTickOffset { get; set; } } } diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSlider.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSlider.cs index 0bd6bb5abc..5b638782fb 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseSlider.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSlider.cs @@ -18,6 +18,7 @@ using System.Linq; using NUnit.Framework; using osu.Game.Graphics.Sprites; using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; @@ -108,13 +109,12 @@ namespace osu.Game.Rulesets.Osu.Tests { StartTime = Time.Current + 1000, Position = new Vector2(239, 176), - ControlPoints = new[] + Path = new SliderPath(PathType.PerfectCurve, new[] { Vector2.Zero, new Vector2(154, 28), new Vector2(52, -34) - }, - Distance = 700, + }, 700), RepeatCount = repeats, NodeSamples = createEmptySamples(repeats), StackHeight = 10 @@ -141,12 +141,11 @@ namespace osu.Game.Rulesets.Osu.Tests { StartTime = Time.Current + 1000, Position = new Vector2(-(distance / 2), 0), - ControlPoints = new[] + Path = new SliderPath(PathType.PerfectCurve, new[] { Vector2.Zero, new Vector2(distance, 0), - }, - Distance = distance, + }, distance), RepeatCount = repeats, NodeSamples = createEmptySamples(repeats), StackHeight = stackHeight @@ -161,13 +160,12 @@ namespace osu.Game.Rulesets.Osu.Tests { StartTime = Time.Current + 1000, Position = new Vector2(-200, 0), - ControlPoints = new[] + Path = new SliderPath(PathType.PerfectCurve, new[] { Vector2.Zero, new Vector2(200, 200), new Vector2(400, 0) - }, - Distance = 600, + }, 600), RepeatCount = repeats, NodeSamples = createEmptySamples(repeats) }; @@ -181,10 +179,9 @@ namespace osu.Game.Rulesets.Osu.Tests { var slider = new Slider { - PathType = PathType.Linear, StartTime = Time.Current + 1000, Position = new Vector2(-200, 0), - ControlPoints = new[] + Path = new SliderPath(PathType.Linear, new[] { Vector2.Zero, new Vector2(150, 75), @@ -192,8 +189,7 @@ namespace osu.Game.Rulesets.Osu.Tests new Vector2(300, -200), new Vector2(400, 0), new Vector2(430, 0) - }, - Distance = 793.4417, + }), RepeatCount = repeats, NodeSamples = createEmptySamples(repeats) }; @@ -207,18 +203,16 @@ namespace osu.Game.Rulesets.Osu.Tests { var slider = new Slider { - PathType = PathType.Bezier, StartTime = Time.Current + 1000, Position = new Vector2(-200, 0), - ControlPoints = new[] + Path = new SliderPath(PathType.Bezier, new[] { Vector2.Zero, new Vector2(150, 75), new Vector2(200, 100), new Vector2(300, -200), new Vector2(430, 0) - }, - Distance = 480, + }), RepeatCount = repeats, NodeSamples = createEmptySamples(repeats) }; @@ -232,10 +226,9 @@ namespace osu.Game.Rulesets.Osu.Tests { var slider = new Slider { - PathType = PathType.Linear, StartTime = Time.Current + 1000, Position = new Vector2(0, 0), - ControlPoints = new[] + Path = new SliderPath(PathType.Linear, new[] { Vector2.Zero, new Vector2(-200, 0), @@ -243,8 +236,7 @@ namespace osu.Game.Rulesets.Osu.Tests new Vector2(0, -200), new Vector2(-200, -200), new Vector2(0, -200) - }, - Distance = 1000, + }), RepeatCount = repeats, NodeSamples = createEmptySamples(repeats) }; @@ -264,15 +256,13 @@ namespace osu.Game.Rulesets.Osu.Tests { StartTime = Time.Current + 1000, Position = new Vector2(-100, 0), - PathType = PathType.Catmull, - ControlPoints = new[] + Path = new SliderPath(PathType.Catmull, new[] { Vector2.Zero, new Vector2(50, -50), new Vector2(150, 50), new Vector2(200, 0) - }, - Distance = 300, + }), RepeatCount = repeats, NodeSamples = repeatSamples }; diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionBlueprint.cs index 78e3d76313..cacbcb2cd6 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionBlueprint.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders; using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components; @@ -35,14 +36,12 @@ namespace osu.Game.Rulesets.Osu.Tests var slider = new Slider { Position = new Vector2(256, 192), - ControlPoints = new[] + Path = new SliderPath(PathType.Bezier, new[] { Vector2.Zero, new Vector2(150, 150), new Vector2(300, 0) - }, - PathType = PathType.Bezier, - Distance = 350 + }) }; slider.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 2 }); diff --git a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs index 87c81cdd3b..4fc4f3edc3 100644 --- a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs +++ b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs @@ -35,9 +35,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps { StartTime = original.StartTime, Samples = original.Samples, - ControlPoints = curveData.ControlPoints, - PathType = curveData.PathType, - Distance = curveData.Distance, + Path = curveData.Path, NodeSamples = curveData.NodeSamples, RepeatCount = curveData.RepeatCount, Position = positionData?.Position ?? Vector2.Zero, diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs index 175e9d79f4..22ad911c21 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics.Lines; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; using osu.Game.Graphics; +using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Osu.Objects; using OpenTK; @@ -55,16 +56,16 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { base.Update(); - Position = slider.StackedPosition + slider.ControlPoints[index]; + Position = slider.StackedPosition + slider.Path.ControlPoints[index]; marker.Colour = isSegmentSeparator ? colours.Red : colours.Yellow; path.ClearVertices(); - if (index != slider.ControlPoints.Length - 1) + if (index != slider.Path.ControlPoints.Length - 1) { path.AddVertex(Vector2.Zero); - path.AddVertex(slider.ControlPoints[index + 1] - slider.ControlPoints[index]); + path.AddVertex(slider.Path.ControlPoints[index + 1] - slider.Path.ControlPoints[index]); } path.OriginPosition = path.PositionInBoundingBox(Vector2.Zero); @@ -76,7 +77,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components protected override bool OnDrag(DragEvent e) { - var newControlPoints = slider.ControlPoints.ToArray(); + var newControlPoints = slider.Path.ControlPoints.ToArray(); if (index == 0) { @@ -96,8 +97,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components if (isSegmentSeparatorWithPrevious) newControlPoints[index - 1] = newControlPoints[index]; - slider.ControlPoints = newControlPoints; - slider.Path.Calculate(true); + slider.Path = new SliderPath(slider.Path.Type, newControlPoints); return true; } @@ -106,8 +106,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components private bool isSegmentSeparator => isSegmentSeparatorWithNext || isSegmentSeparatorWithPrevious; - private bool isSegmentSeparatorWithNext => index < slider.ControlPoints.Length - 1 && slider.ControlPoints[index + 1] == slider.ControlPoints[index]; + private bool isSegmentSeparatorWithNext => index < slider.Path.ControlPoints.Length - 1 && slider.Path.ControlPoints[index + 1] == slider.Path.ControlPoints[index]; - private bool isSegmentSeparatorWithPrevious => index > 0 && slider.ControlPoints[index - 1] == slider.ControlPoints[index]; + private bool isSegmentSeparatorWithPrevious => index > 0 && slider.Path.ControlPoints[index - 1] == slider.Path.ControlPoints[index]; } } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs index db8e879126..ab9d81574a 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs @@ -19,15 +19,15 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components InternalChild = pieces = new Container { RelativeSizeAxes = Axes.Both }; - slider.ControlPointsChanged += _ => updatePathControlPoints(); + slider.PathChanged += _ => updatePathControlPoints(); updatePathControlPoints(); } private void updatePathControlPoints() { - while (slider.ControlPoints.Length > pieces.Count) + while (slider.Path.ControlPoints.Length > pieces.Count) pieces.Add(new PathControlPointPiece(slider, pieces.Count)); - while (slider.ControlPoints.Length < pieces.Count) + while (slider.Path.ControlPoints.Length < pieces.Count) pieces.Remove(pieces[pieces.Count - 1]); } } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderCirclePiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderCirclePiece.cs index a91739737f..1ee765f5e0 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderCirclePiece.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components this.slider = slider; this.position = position; - slider.ControlPointsChanged += _ => UpdatePosition(); + slider.PathChanged += _ => UpdatePosition(); } protected override void UpdatePosition() diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs b/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs index e01d71e1f8..223e4df844 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs @@ -32,12 +32,11 @@ namespace osu.Game.Rulesets.Osu.Mods slider.NestedHitObjects.OfType().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Position.Y)); slider.NestedHitObjects.OfType().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Position.Y)); - var newControlPoints = new Vector2[slider.ControlPoints.Length]; - for (int i = 0; i < slider.ControlPoints.Length; i++) - newControlPoints[i] = new Vector2(slider.ControlPoints[i].X, -slider.ControlPoints[i].Y); + var newControlPoints = new Vector2[slider.Path.ControlPoints.Length]; + for (int i = 0; i < slider.Path.ControlPoints.Length; i++) + newControlPoints[i] = new Vector2(slider.Path.ControlPoints[i].X, -slider.Path.ControlPoints[i].Y); - slider.ControlPoints = newControlPoints; - slider.Path?.Calculate(); // Recalculate the slider curve + slider.Path = new SliderPath(slider.Path.Type, newControlPoints, slider.Path.ExpectedDistance); } } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index 514ae09064..a90182cecb 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -91,7 +91,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Ball.Scale = new Vector2(HitObject.Scale); }; - slider.ControlPointsChanged += _ => Body.Refresh(); + slider.PathChanged += _ => Body.Refresh(); } public override Color4 AccentColour diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs index 6a836679a2..b933364887 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables this.slider = slider; h.PositionChanged += _ => updatePosition(); - slider.ControlPointsChanged += _ => updatePosition(); + slider.PathChanged += _ => updatePosition(); updatePosition(); } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs index cc88a6718b..6946a55d8e 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs @@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables AlwaysPresent = true; hitCircle.PositionChanged += _ => updatePosition(); - slider.ControlPointsChanged += _ => updatePosition(); + slider.PathChanged += _ => updatePosition(); updatePosition(); } diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index cff742ca29..07e526956a 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -22,9 +22,9 @@ namespace osu.Game.Rulesets.Osu.Objects /// private const float base_scoring_distance = 100; - public event Action ControlPointsChanged; + public event Action PathChanged; - public double EndTime => StartTime + this.SpanCount() * Path.Distance / Velocity; + public double EndTime => StartTime + this.SpanCount() * Path.GetDistance() / Velocity; public double Duration => EndTime - StartTime; public Vector2 StackedPositionAt(double t) => StackedPosition + this.CurvePositionAt(t); @@ -52,35 +52,23 @@ namespace osu.Game.Rulesets.Osu.Objects } } - public SliderPath Path { get; } = new SliderPath(); + private SliderPath path; - public Vector2[] ControlPoints + public SliderPath Path { - get => Path.ControlPoints; + get => path; set { - if (Path.ControlPoints == value) - return; - Path.ControlPoints = value; + path = value; - ControlPointsChanged?.Invoke(value); + PathChanged?.Invoke(value); if (TailCircle != null) TailCircle.Position = EndPosition; } } - public PathType PathType - { - get { return Path.PathType; } - set { Path.PathType = value; } - } - - public double Distance - { - get { return Path.Distance; } - set { Path.Distance = value; } - } + public double Distance => Path.GetDistance(); public override Vector2 Position { @@ -190,7 +178,7 @@ namespace osu.Game.Rulesets.Osu.Objects private void createTicks() { - var length = Path.Distance; + var length = Path.GetDistance(); var tickDistance = MathHelper.Clamp(TickDistance, 0, length); if (tickDistance == 0) return; diff --git a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs index 2629b29c6c..d894d2738e 100644 --- a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs +++ b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs @@ -11,6 +11,7 @@ using OpenTK; using osu.Game.Beatmaps; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Edit; using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles; @@ -53,12 +54,11 @@ namespace osu.Game.Tests.Visual new Slider { Position = new Vector2(128, 256), - ControlPoints = new[] + Path = new SliderPath(PathType.Linear, new[] { Vector2.Zero, new Vector2(216, 0), - }, - Distance = 216, + }), Scale = 0.5f, } }, diff --git a/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs index c805c55ed1..b167812c1d 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs @@ -50,9 +50,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch X = position.X, NewCombo = FirstObject || newCombo, ComboOffset = comboOffset, - ControlPoints = controlPoints, - Distance = length, - PathType = pathType, + Path = new SliderPath(pathType, controlPoints, length), NodeSamples = nodeSamples, RepeatCount = repeatCount }; diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs index b3d9f3c40c..901cc1ba9f 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs @@ -3,7 +3,6 @@ using osu.Game.Rulesets.Objects.Types; using System.Collections.Generic; -using OpenTK; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; @@ -20,11 +19,9 @@ namespace osu.Game.Rulesets.Objects.Legacy /// /// s don't need a curve since they're converted to ruleset-specific hitobjects. /// - public SliderPath Path { get; } = null; - public Vector2[] ControlPoints { get; set; } - public PathType PathType { get; set; } + public SliderPath Path { get; set; } - public double Distance { get; set; } + public double Distance => Path.GetDistance(); public List> NodeSamples { get; set; } public int RepeatCount { get; set; } diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs index 90b7f3d554..fa5e769d3c 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs @@ -31,9 +31,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania return new ConvertSlider { X = position.X, - ControlPoints = controlPoints, - Distance = length, - PathType = pathType, + Path = new SliderPath(pathType, controlPoints, length), NodeSamples = nodeSamples, RepeatCount = repeatCount }; diff --git a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs index bb41a147b0..e21903dc6d 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs @@ -51,9 +51,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu Position = position, NewCombo = FirstObject || newCombo, ComboOffset = comboOffset, - ControlPoints = controlPoints, - Distance = Math.Max(0, length), - PathType = pathType, + Path = new SliderPath(pathType, controlPoints, Math.Max(0, length)), NodeSamples = nodeSamples, RepeatCount = repeatCount }; diff --git a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs index ae913b3bef..8e1e01a9fd 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs @@ -27,9 +27,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko { return new ConvertSlider { - ControlPoints = controlPoints, - Distance = length, - PathType = pathType, + Path = new SliderPath(pathType, controlPoints, length), NodeSamples = nodeSamples, RepeatCount = repeatCount }; diff --git a/osu.Game/Rulesets/Objects/SliderPath.cs b/osu.Game/Rulesets/Objects/SliderPath.cs index 423cd3b069..195e429f2b 100644 --- a/osu.Game/Rulesets/Objects/SliderPath.cs +++ b/osu.Game/Rulesets/Objects/SliderPath.cs @@ -10,22 +10,31 @@ using OpenTK; namespace osu.Game.Rulesets.Objects { - public class SliderPath + public readonly struct SliderPath { - public double Distance; + public readonly Vector2[] ControlPoints; + public readonly PathType Type; + public readonly double? ExpectedDistance; - public Vector2[] ControlPoints = Array.Empty(); + public SliderPath(PathType type, Vector2[] controlPoints, double? expectedDistance = null) + { + ControlPoints = controlPoints; + Type = type; + ExpectedDistance = expectedDistance; - public PathType PathType = PathType.PerfectCurve; + calculatedPath = new List(); + cumulativeLength = new List(); - public Vector2 Offset; + calculatePath(); + calculateCumulativeLength(); + } - private readonly List calculatedPath = new List(); - private readonly List cumulativeLength = new List(); + private readonly List calculatedPath; + private readonly List cumulativeLength; private List calculateSubpath(ReadOnlySpan subControlPoints) { - switch (PathType) + switch (Type) { case PathType.Linear: return PathApproximator.ApproximateLinear(subControlPoints); @@ -77,49 +86,6 @@ namespace osu.Game.Rulesets.Objects } } - private void calculateCumulativeLengthAndTrimPath() - { - double l = 0; - - cumulativeLength.Clear(); - cumulativeLength.Add(l); - - for (int i = 0; i < calculatedPath.Count - 1; ++i) - { - Vector2 diff = calculatedPath[i + 1] - calculatedPath[i]; - double d = diff.Length; - - // Shorten slider paths that are too long compared to what's - // in the .osu file. - if (Distance - l < d) - { - calculatedPath[i + 1] = calculatedPath[i] + diff * (float)((Distance - l) / d); - calculatedPath.RemoveRange(i + 2, calculatedPath.Count - 2 - i); - - l = Distance; - cumulativeLength.Add(l); - break; - } - - l += d; - cumulativeLength.Add(l); - } - - // Lengthen slider paths that are too short compared to what's - // in the .osu file. - if (l < Distance && calculatedPath.Count > 1) - { - Vector2 diff = calculatedPath[calculatedPath.Count - 1] - calculatedPath[calculatedPath.Count - 2]; - double d = diff.Length; - - if (d <= 0) - return; - - calculatedPath[calculatedPath.Count - 1] += diff * (float)((Distance - l) / d); - cumulativeLength[calculatedPath.Count - 1] = Distance; - } - } - private void calculateCumulativeLength() { double l = 0; @@ -132,21 +98,33 @@ namespace osu.Game.Rulesets.Objects Vector2 diff = calculatedPath[i + 1] - calculatedPath[i]; double d = diff.Length; + // Shorted slider paths that are too long compared to the expected distance + if (ExpectedDistance.HasValue && ExpectedDistance - l < d) + { + calculatedPath[i + 1] = calculatedPath[i] + diff * (float)((ExpectedDistance - l) / d); + calculatedPath.RemoveRange(i + 2, calculatedPath.Count - 2 - i); + + l = ExpectedDistance.Value; + cumulativeLength.Add(l); + break; + } + l += d; cumulativeLength.Add(l); } - Distance = l; - } + // Lengthen slider paths that are too short compared to the expected distance + if (ExpectedDistance.HasValue && l < ExpectedDistance && calculatedPath.Count > 1) + { + Vector2 diff = calculatedPath[calculatedPath.Count - 1] - calculatedPath[calculatedPath.Count - 2]; + double d = diff.Length; - public void Calculate(bool updateDistance = false) - { - calculatePath(); + if (d <= 0) + return; - if (!updateDistance) - calculateCumulativeLengthAndTrimPath(); - else - calculateCumulativeLength(); + calculatedPath[calculatedPath.Count - 1] += diff * (float)((ExpectedDistance - l) / d); + cumulativeLength[calculatedPath.Count - 1] = ExpectedDistance.Value; + } } private int indexOfDistance(double d) @@ -159,7 +137,7 @@ namespace osu.Game.Rulesets.Objects private double progressToDistance(double progress) { - return MathHelper.Clamp(progress, 0, 1) * Distance; + return MathHelper.Clamp(progress, 0, 1) * GetDistance(); } private Vector2 interpolateVertices(int i, double d) @@ -169,7 +147,7 @@ namespace osu.Game.Rulesets.Objects if (i <= 0) return calculatedPath.First(); - else if (i >= calculatedPath.Count) + if (i >= calculatedPath.Count) return calculatedPath.Last(); Vector2 p0 = calculatedPath[i - 1]; @@ -186,6 +164,8 @@ namespace osu.Game.Rulesets.Objects return p0 + (p1 - p0) * (float)w; } + public double GetDistance() => cumulativeLength.Count == 0 ? 0 : cumulativeLength[cumulativeLength.Count - 1]; + /// /// Computes the slider path until a given progress that ranges from 0 (beginning of the slider) /// to 1 (end of the slider) and stores the generated path in the given list. @@ -195,23 +175,22 @@ namespace osu.Game.Rulesets.Objects /// End progress. Ranges from 0 (beginning of the slider) to 1 (end of the slider). public void GetPathToProgress(List path, double p0, double p1) { - if (calculatedPath.Count == 0 && ControlPoints.Length > 0) - Calculate(); - double d0 = progressToDistance(p0); double d1 = progressToDistance(p1); path.Clear(); int i = 0; - for (; i < calculatedPath.Count && cumulativeLength[i] < d0; ++i) { } + for (; i < calculatedPath.Count && cumulativeLength[i] < d0; ++i) + { + } - path.Add(interpolateVertices(i, d0) + Offset); + path.Add(interpolateVertices(i, d0)); for (; i < calculatedPath.Count && cumulativeLength[i] <= d1; ++i) - path.Add(calculatedPath[i] + Offset); + path.Add(calculatedPath[i]); - path.Add(interpolateVertices(i, d1) + Offset); + path.Add(interpolateVertices(i, d1)); } /// @@ -222,11 +201,8 @@ namespace osu.Game.Rulesets.Objects /// public Vector2 PositionAt(double progress) { - if (calculatedPath.Count == 0 && ControlPoints.Length > 0) - Calculate(); - double d = progressToDistance(progress); - return interpolateVertices(indexOfDistance(d), d) + Offset; + return interpolateVertices(indexOfDistance(d), d); } } } diff --git a/osu.Game/Rulesets/Objects/Types/IHasCurve.cs b/osu.Game/Rulesets/Objects/Types/IHasCurve.cs index 2a0d495e94..a097b62851 100644 --- a/osu.Game/Rulesets/Objects/Types/IHasCurve.cs +++ b/osu.Game/Rulesets/Objects/Types/IHasCurve.cs @@ -14,16 +14,6 @@ namespace osu.Game.Rulesets.Objects.Types /// The curve. /// SliderPath Path { get; } - - /// - /// The control points that shape the curve. - /// - Vector2[] ControlPoints { get; } - - /// - /// The type of curve. - /// - PathType PathType { get; } } public static class HasCurveExtensions From 51e4feeda768ec0765e3bbbfefd21a434e9eff9b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 12 Nov 2018 13:55:14 +0900 Subject: [PATCH 116/155] Adjust to new path structure --- .../Sliders/Components/SliderBodyPiece.cs | 2 - .../Sliders/SliderPlacementBlueprint.cs | 40 ++----------------- 2 files changed, 3 insertions(+), 39 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs index 6fc7d39e6c..06bc265258 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs @@ -45,8 +45,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { base.Update(); - slider.Path.Calculate(); - var vertices = new List(); slider.Path.GetPathToProgress(vertices, 0, 1); diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs index add9cb69f3..d59cd35f19 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs @@ -1,16 +1,15 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System; using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Input.Events; -using osu.Framework.MathUtils; using osu.Game.Graphics; using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components; using OpenTK; @@ -119,12 +118,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders private void updateSlider() { - for (int i = 0; i < segments.Count; i++) - segments[i].Calculate(i == segments.Count - 1 ? (Vector2?)cursor : null); - - HitObject.ControlPoints = segments.SelectMany(s => s.ControlPoints).Concat(cursor.Yield()).ToArray(); - HitObject.PathType = HitObject.ControlPoints.Length > 2 ? PathType.Bezier : PathType.Linear; - HitObject.Distance = segments.Sum(s => s.Distance); + var newControlPoints = segments.SelectMany(s => s.ControlPoints).Concat(cursor.Yield()).ToArray(); + HitObject.Path = new SliderPath(newControlPoints.Length > 2 ? PathType.Bezier : PathType.Linear, newControlPoints); } private void setState(PlacementState newState) @@ -140,41 +135,12 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders private class Segment { - public float Distance { get; private set; } - public readonly List ControlPoints = new List(); public Segment(Vector2 offset) { ControlPoints.Add(offset); } - - public void Calculate(Vector2? cursor = null) - { - Span allControlPoints = stackalloc Vector2[ControlPoints.Count + (cursor.HasValue ? 1 : 0)]; - - for (int i = 0; i < ControlPoints.Count; i++) - allControlPoints[i] = ControlPoints[i]; - if (cursor.HasValue) - allControlPoints[allControlPoints.Length - 1] = cursor.Value; - - List result; - - switch (allControlPoints.Length) - { - case 1: - case 2: - result = PathApproximator.ApproximateLinear(allControlPoints); - break; - default: - result = PathApproximator.ApproximateBezier(allControlPoints); - break; - } - - Distance = 0; - for (int i = 0; i < result.Count - 1; i++) - Distance += Vector2.Distance(result[i], result[i + 1]); - } } } } From 3b88d94793feafa815abf8a3e7ca9d18d6e92294 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 12 Nov 2018 14:03:54 +0900 Subject: [PATCH 117/155] Make SliderPath.ControlPoints read-only --- .../Sliders/Components/PathControlPointPiece.cs | 9 ++++----- osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs | 2 +- osu.Game/Rulesets/Objects/SliderPath.cs | 6 +++--- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs index 22ad911c21..d46fa46c22 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs @@ -1,7 +1,6 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -56,7 +55,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { base.Update(); - Position = slider.StackedPosition + slider.Path.ControlPoints[index]; + Position = slider.StackedPosition + slider.Path.ControlPoints.Span[index]; marker.Colour = isSegmentSeparator ? colours.Red : colours.Yellow; @@ -65,7 +64,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components if (index != slider.Path.ControlPoints.Length - 1) { path.AddVertex(Vector2.Zero); - path.AddVertex(slider.Path.ControlPoints[index + 1] - slider.Path.ControlPoints[index]); + path.AddVertex(slider.Path.ControlPoints.Span[index + 1] - slider.Path.ControlPoints.Span[index]); } path.OriginPosition = path.PositionInBoundingBox(Vector2.Zero); @@ -106,8 +105,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components private bool isSegmentSeparator => isSegmentSeparatorWithNext || isSegmentSeparatorWithPrevious; - private bool isSegmentSeparatorWithNext => index < slider.Path.ControlPoints.Length - 1 && slider.Path.ControlPoints[index + 1] == slider.Path.ControlPoints[index]; + private bool isSegmentSeparatorWithNext => index < slider.Path.ControlPoints.Length - 1 && slider.Path.ControlPoints.Span[index + 1] == slider.Path.ControlPoints.Span[index]; - private bool isSegmentSeparatorWithPrevious => index > 0 && slider.Path.ControlPoints[index - 1] == slider.Path.ControlPoints[index]; + private bool isSegmentSeparatorWithPrevious => index > 0 && slider.Path.ControlPoints.Span[index - 1] == slider.Path.ControlPoints.Span[index]; } } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs b/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs index 223e4df844..b66b5d3d39 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs @@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Osu.Mods var newControlPoints = new Vector2[slider.Path.ControlPoints.Length]; for (int i = 0; i < slider.Path.ControlPoints.Length; i++) - newControlPoints[i] = new Vector2(slider.Path.ControlPoints[i].X, -slider.Path.ControlPoints[i].Y); + newControlPoints[i] = new Vector2(slider.Path.ControlPoints.Span[i].X, -slider.Path.ControlPoints.Span[i].Y); slider.Path = new SliderPath(slider.Path.Type, newControlPoints, slider.Path.ExpectedDistance); } diff --git a/osu.Game/Rulesets/Objects/SliderPath.cs b/osu.Game/Rulesets/Objects/SliderPath.cs index 195e429f2b..5ad1cec6b6 100644 --- a/osu.Game/Rulesets/Objects/SliderPath.cs +++ b/osu.Game/Rulesets/Objects/SliderPath.cs @@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Objects { public readonly struct SliderPath { - public readonly Vector2[] ControlPoints; + public readonly ReadOnlyMemory ControlPoints; public readonly PathType Type; public readonly double? ExpectedDistance; @@ -73,9 +73,9 @@ namespace osu.Game.Rulesets.Objects { end++; - if (i == ControlPoints.Length - 1 || ControlPoints[i] == ControlPoints[i + 1]) + if (i == ControlPoints.Length - 1 || ControlPoints.Span[i] == ControlPoints.Span[i + 1]) { - ReadOnlySpan cpSpan = ControlPoints.AsSpan().Slice(start, end - start); + ReadOnlySpan cpSpan = ControlPoints.Span.Slice(start, end - start); foreach (Vector2 t in calculateSubpath(cpSpan)) if (calculatedPath.Count == 0 || calculatedPath.Last() != t) From 3aba462e524a4f769114f197bf7edac5f2cfb3c2 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 12 Nov 2018 14:07:48 +0900 Subject: [PATCH 118/155] Make Path.Distance a property again --- osu.Game.Rulesets.Catch/Objects/JuiceStream.cs | 6 +++--- osu.Game.Rulesets.Osu/Objects/Slider.cs | 6 +++--- osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs | 2 +- osu.Game/Rulesets/Objects/SliderPath.cs | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index a4e04ae837..d8bd3e0edc 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -49,7 +49,7 @@ namespace osu.Game.Rulesets.Catch.Objects if (TickDistance == 0) return; - var length = Path.GetDistance(); + var length = Path.Distance; var tickDistance = Math.Min(TickDistance, length); var spanDuration = length / Velocity; @@ -131,7 +131,7 @@ namespace osu.Game.Rulesets.Catch.Objects } } - public double EndTime => StartTime + this.SpanCount() * Path.GetDistance() / Velocity; + public double EndTime => StartTime + this.SpanCount() * Path.Distance / Velocity; public float EndX => X + this.CurvePositionAt(1).X / CatchPlayfield.BASE_WIDTH; @@ -145,7 +145,7 @@ namespace osu.Game.Rulesets.Catch.Objects set => path = value; } - public double Distance => Path.GetDistance(); + public double Distance => Path.Distance; public List> NodeSamples { get; set; } = new List>(); diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 07e526956a..cf57f24b83 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Osu.Objects public event Action PathChanged; - public double EndTime => StartTime + this.SpanCount() * Path.GetDistance() / Velocity; + public double EndTime => StartTime + this.SpanCount() * Path.Distance / Velocity; public double Duration => EndTime - StartTime; public Vector2 StackedPositionAt(double t) => StackedPosition + this.CurvePositionAt(t); @@ -68,7 +68,7 @@ namespace osu.Game.Rulesets.Osu.Objects } } - public double Distance => Path.GetDistance(); + public double Distance => Path.Distance; public override Vector2 Position { @@ -178,7 +178,7 @@ namespace osu.Game.Rulesets.Osu.Objects private void createTicks() { - var length = Path.GetDistance(); + var length = Path.Distance; var tickDistance = MathHelper.Clamp(TickDistance, 0, length); if (tickDistance == 0) return; diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs index 901cc1ba9f..0512a97354 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs @@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Objects.Legacy /// public SliderPath Path { get; set; } - public double Distance => Path.GetDistance(); + public double Distance => Path.Distance; public List> NodeSamples { get; set; } public int RepeatCount { get; set; } diff --git a/osu.Game/Rulesets/Objects/SliderPath.cs b/osu.Game/Rulesets/Objects/SliderPath.cs index 5ad1cec6b6..3f0f0518d6 100644 --- a/osu.Game/Rulesets/Objects/SliderPath.cs +++ b/osu.Game/Rulesets/Objects/SliderPath.cs @@ -137,7 +137,7 @@ namespace osu.Game.Rulesets.Objects private double progressToDistance(double progress) { - return MathHelper.Clamp(progress, 0, 1) * GetDistance(); + return MathHelper.Clamp(progress, 0, 1) * Distance; } private Vector2 interpolateVertices(int i, double d) @@ -164,7 +164,7 @@ namespace osu.Game.Rulesets.Objects return p0 + (p1 - p0) * (float)w; } - public double GetDistance() => cumulativeLength.Count == 0 ? 0 : cumulativeLength[cumulativeLength.Count - 1]; + public double Distance => cumulativeLength.Count == 0 ? 0 : cumulativeLength[cumulativeLength.Count - 1]; /// /// Computes the slider path until a given progress that ranges from 0 (beginning of the slider) From 4eef1134a629db002036fdde63ac37f2e476513f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 12 Nov 2018 14:08:36 +0900 Subject: [PATCH 119/155] Re-order file --- osu.Game/Rulesets/Objects/SliderPath.cs | 86 ++++++++++++------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/osu.Game/Rulesets/Objects/SliderPath.cs b/osu.Game/Rulesets/Objects/SliderPath.cs index 3f0f0518d6..b81ccbe1e1 100644 --- a/osu.Game/Rulesets/Objects/SliderPath.cs +++ b/osu.Game/Rulesets/Objects/SliderPath.cs @@ -16,6 +16,9 @@ namespace osu.Game.Rulesets.Objects public readonly PathType Type; public readonly double? ExpectedDistance; + private readonly List calculatedPath; + private readonly List cumulativeLength; + public SliderPath(PathType type, Vector2[] controlPoints, double? expectedDistance = null) { ControlPoints = controlPoints; @@ -29,8 +32,46 @@ namespace osu.Game.Rulesets.Objects calculateCumulativeLength(); } - private readonly List calculatedPath; - private readonly List cumulativeLength; + public double Distance => cumulativeLength.Count == 0 ? 0 : cumulativeLength[cumulativeLength.Count - 1]; + + /// + /// Computes the slider path until a given progress that ranges from 0 (beginning of the slider) + /// to 1 (end of the slider) and stores the generated path in the given list. + /// + /// The list to be filled with the computed path. + /// Start progress. Ranges from 0 (beginning of the slider) to 1 (end of the slider). + /// End progress. Ranges from 0 (beginning of the slider) to 1 (end of the slider). + public void GetPathToProgress(List path, double p0, double p1) + { + double d0 = progressToDistance(p0); + double d1 = progressToDistance(p1); + + path.Clear(); + + int i = 0; + for (; i < calculatedPath.Count && cumulativeLength[i] < d0; ++i) + { + } + + path.Add(interpolateVertices(i, d0)); + + for (; i < calculatedPath.Count && cumulativeLength[i] <= d1; ++i) + path.Add(calculatedPath[i]); + + path.Add(interpolateVertices(i, d1)); + } + + /// + /// Computes the position on the slider at a given progress that ranges from 0 (beginning of the path) + /// to 1 (end of the path). + /// + /// Ranges from 0 (beginning of the path) to 1 (end of the path). + /// + public Vector2 PositionAt(double progress) + { + double d = progressToDistance(progress); + return interpolateVertices(indexOfDistance(d), d); + } private List calculateSubpath(ReadOnlySpan subControlPoints) { @@ -163,46 +204,5 @@ namespace osu.Game.Rulesets.Objects double w = (d - d0) / (d1 - d0); return p0 + (p1 - p0) * (float)w; } - - public double Distance => cumulativeLength.Count == 0 ? 0 : cumulativeLength[cumulativeLength.Count - 1]; - - /// - /// Computes the slider path until a given progress that ranges from 0 (beginning of the slider) - /// to 1 (end of the slider) and stores the generated path in the given list. - /// - /// The list to be filled with the computed path. - /// Start progress. Ranges from 0 (beginning of the slider) to 1 (end of the slider). - /// End progress. Ranges from 0 (beginning of the slider) to 1 (end of the slider). - public void GetPathToProgress(List path, double p0, double p1) - { - double d0 = progressToDistance(p0); - double d1 = progressToDistance(p1); - - path.Clear(); - - int i = 0; - for (; i < calculatedPath.Count && cumulativeLength[i] < d0; ++i) - { - } - - path.Add(interpolateVertices(i, d0)); - - for (; i < calculatedPath.Count && cumulativeLength[i] <= d1; ++i) - path.Add(calculatedPath[i]); - - path.Add(interpolateVertices(i, d1)); - } - - /// - /// Computes the position on the slider at a given progress that ranges from 0 (beginning of the path) - /// to 1 (end of the path). - /// - /// Ranges from 0 (beginning of the path) to 1 (end of the path). - /// - public Vector2 PositionAt(double progress) - { - double d = progressToDistance(progress); - return interpolateVertices(indexOfDistance(d), d); - } } } From 77d16aa968d2ea6de8194cd3756c49484cfac720 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 12 Nov 2018 14:16:21 +0900 Subject: [PATCH 120/155] Add xmldocs --- osu.Game/Rulesets/Objects/SliderPath.cs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/osu.Game/Rulesets/Objects/SliderPath.cs b/osu.Game/Rulesets/Objects/SliderPath.cs index b81ccbe1e1..66acbeed68 100644 --- a/osu.Game/Rulesets/Objects/SliderPath.cs +++ b/osu.Game/Rulesets/Objects/SliderPath.cs @@ -12,13 +12,33 @@ namespace osu.Game.Rulesets.Objects { public readonly struct SliderPath { + /// + /// The control points of the path. + /// public readonly ReadOnlyMemory ControlPoints; + + /// + /// The type of path. + /// public readonly PathType Type; + + /// + /// The user-set distance of the path. If non-null, will match this value, + /// and the path will be shortened/lengthened to match this length. + /// public readonly double? ExpectedDistance; private readonly List calculatedPath; private readonly List cumulativeLength; + /// + /// Creates a new . + /// + /// The type of path. + /// The control points of the path. + /// A user-set distance of the path that may be shorter or longer than the true distance between all + /// . The path will be shortened/lengthened to match this length. + /// If null, the path will use the true distance between all . public SliderPath(PathType type, Vector2[] controlPoints, double? expectedDistance = null) { ControlPoints = controlPoints; @@ -32,6 +52,9 @@ namespace osu.Game.Rulesets.Objects calculateCumulativeLength(); } + /// + /// The distance of the path after lengthening/shortening to account for . + /// public double Distance => cumulativeLength.Count == 0 ? 0 : cumulativeLength[cumulativeLength.Count - 1]; /// From d594ce35304218ac8eb613159737a66e1955bc34 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 12 Nov 2018 16:20:38 +0900 Subject: [PATCH 121/155] Revert "Make SliderPath.ControlPoints read-only" This reverts commit 3b88d94793feafa815abf8a3e7ca9d18d6e92294. # Conflicts: # osu.Game/Rulesets/Objects/SliderPath.cs --- .../Sliders/Components/PathControlPointPiece.cs | 9 +++++---- osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs | 2 +- osu.Game/Rulesets/Objects/SliderPath.cs | 6 +++--- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs index d46fa46c22..22ad911c21 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.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.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -55,7 +56,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { base.Update(); - Position = slider.StackedPosition + slider.Path.ControlPoints.Span[index]; + Position = slider.StackedPosition + slider.Path.ControlPoints[index]; marker.Colour = isSegmentSeparator ? colours.Red : colours.Yellow; @@ -64,7 +65,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components if (index != slider.Path.ControlPoints.Length - 1) { path.AddVertex(Vector2.Zero); - path.AddVertex(slider.Path.ControlPoints.Span[index + 1] - slider.Path.ControlPoints.Span[index]); + path.AddVertex(slider.Path.ControlPoints[index + 1] - slider.Path.ControlPoints[index]); } path.OriginPosition = path.PositionInBoundingBox(Vector2.Zero); @@ -105,8 +106,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components private bool isSegmentSeparator => isSegmentSeparatorWithNext || isSegmentSeparatorWithPrevious; - private bool isSegmentSeparatorWithNext => index < slider.Path.ControlPoints.Length - 1 && slider.Path.ControlPoints.Span[index + 1] == slider.Path.ControlPoints.Span[index]; + private bool isSegmentSeparatorWithNext => index < slider.Path.ControlPoints.Length - 1 && slider.Path.ControlPoints[index + 1] == slider.Path.ControlPoints[index]; - private bool isSegmentSeparatorWithPrevious => index > 0 && slider.Path.ControlPoints.Span[index - 1] == slider.Path.ControlPoints.Span[index]; + private bool isSegmentSeparatorWithPrevious => index > 0 && slider.Path.ControlPoints[index - 1] == slider.Path.ControlPoints[index]; } } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs b/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs index b66b5d3d39..223e4df844 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs @@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Osu.Mods var newControlPoints = new Vector2[slider.Path.ControlPoints.Length]; for (int i = 0; i < slider.Path.ControlPoints.Length; i++) - newControlPoints[i] = new Vector2(slider.Path.ControlPoints.Span[i].X, -slider.Path.ControlPoints.Span[i].Y); + newControlPoints[i] = new Vector2(slider.Path.ControlPoints[i].X, -slider.Path.ControlPoints[i].Y); slider.Path = new SliderPath(slider.Path.Type, newControlPoints, slider.Path.ExpectedDistance); } diff --git a/osu.Game/Rulesets/Objects/SliderPath.cs b/osu.Game/Rulesets/Objects/SliderPath.cs index 66acbeed68..a174280456 100644 --- a/osu.Game/Rulesets/Objects/SliderPath.cs +++ b/osu.Game/Rulesets/Objects/SliderPath.cs @@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Objects /// /// The control points of the path. /// - public readonly ReadOnlyMemory ControlPoints; + public readonly Vector2[] ControlPoints; /// /// The type of path. @@ -137,9 +137,9 @@ namespace osu.Game.Rulesets.Objects { end++; - if (i == ControlPoints.Length - 1 || ControlPoints.Span[i] == ControlPoints.Span[i + 1]) + if (i == ControlPoints.Length - 1 || ControlPoints[i] == ControlPoints[i + 1]) { - ReadOnlySpan cpSpan = ControlPoints.Span.Slice(start, end - start); + ReadOnlySpan cpSpan = ControlPoints.AsSpan().Slice(start, end - start); foreach (Vector2 t in calculateSubpath(cpSpan)) if (calculatedPath.Count == 0 || calculatedPath.Last() != t) From 8ad9b6a02a268f72940259e1f271670d28516876 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 12 Nov 2018 16:38:14 +0900 Subject: [PATCH 122/155] Safety for default(SliderPath) --- osu.Game/Rulesets/Objects/SliderPath.cs | 52 ++++++++++++++++++------- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/osu.Game/Rulesets/Objects/SliderPath.cs b/osu.Game/Rulesets/Objects/SliderPath.cs index a174280456..27f864e2aa 100644 --- a/osu.Game/Rulesets/Objects/SliderPath.cs +++ b/osu.Game/Rulesets/Objects/SliderPath.cs @@ -10,26 +10,28 @@ using OpenTK; namespace osu.Game.Rulesets.Objects { - public readonly struct SliderPath + public struct SliderPath { /// /// The control points of the path. /// public readonly Vector2[] ControlPoints; - /// - /// The type of path. - /// - public readonly PathType Type; - /// /// The user-set distance of the path. If non-null, will match this value, /// and the path will be shortened/lengthened to match this length. /// public readonly double? ExpectedDistance; - private readonly List calculatedPath; - private readonly List cumulativeLength; + /// + /// The type of path. + /// + public readonly PathType Type; + + private List calculatedPath; + private List cumulativeLength; + + private bool isInitialised; /// /// Creates a new . @@ -41,21 +43,26 @@ namespace osu.Game.Rulesets.Objects /// If null, the path will use the true distance between all . public SliderPath(PathType type, Vector2[] controlPoints, double? expectedDistance = null) { + this = default; + ControlPoints = controlPoints; Type = type; ExpectedDistance = expectedDistance; - calculatedPath = new List(); - cumulativeLength = new List(); - - calculatePath(); - calculateCumulativeLength(); + ensureInitialised(); } /// /// The distance of the path after lengthening/shortening to account for . /// - public double Distance => cumulativeLength.Count == 0 ? 0 : cumulativeLength[cumulativeLength.Count - 1]; + public double Distance + { + get + { + ensureInitialised(); + return cumulativeLength.Count == 0 ? 0 : cumulativeLength[cumulativeLength.Count - 1]; + } + } /// /// Computes the slider path until a given progress that ranges from 0 (beginning of the slider) @@ -66,6 +73,8 @@ namespace osu.Game.Rulesets.Objects /// End progress. Ranges from 0 (beginning of the slider) to 1 (end of the slider). public void GetPathToProgress(List path, double p0, double p1) { + ensureInitialised(); + double d0 = progressToDistance(p0); double d1 = progressToDistance(p1); @@ -92,10 +101,25 @@ namespace osu.Game.Rulesets.Objects /// public Vector2 PositionAt(double progress) { + ensureInitialised(); + double d = progressToDistance(progress); return interpolateVertices(indexOfDistance(d), d); } + private void ensureInitialised() + { + if (isInitialised) + return; + isInitialised = true; + + calculatedPath = new List(); + cumulativeLength = new List(); + + calculatePath(); + calculateCumulativeLength(); + } + private List calculateSubpath(ReadOnlySpan subControlPoints) { switch (Type) From 0e92b385f01500c85fb6b94ec60793bbb40bab1f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 12 Nov 2018 16:38:33 +0900 Subject: [PATCH 123/155] Define default json deserialisation constructor --- osu.Game/Rulesets/Objects/SliderPath.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Rulesets/Objects/SliderPath.cs b/osu.Game/Rulesets/Objects/SliderPath.cs index 27f864e2aa..c5d3a39ab1 100644 --- a/osu.Game/Rulesets/Objects/SliderPath.cs +++ b/osu.Game/Rulesets/Objects/SliderPath.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Newtonsoft.Json; using osu.Framework.MathUtils; using osu.Game.Rulesets.Objects.Types; using OpenTK; @@ -41,6 +42,7 @@ namespace osu.Game.Rulesets.Objects /// A user-set distance of the path that may be shorter or longer than the true distance between all /// . The path will be shortened/lengthened to match this length. /// If null, the path will use the true distance between all . + [JsonConstructor] public SliderPath(PathType type, Vector2[] controlPoints, double? expectedDistance = null) { this = default; From 0220ed21b03530088525ce15cd0e56c6d6abb819 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 12 Nov 2018 16:38:39 +0900 Subject: [PATCH 124/155] Ignore distance for json serialisation --- osu.Game/Rulesets/Objects/SliderPath.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Rulesets/Objects/SliderPath.cs b/osu.Game/Rulesets/Objects/SliderPath.cs index c5d3a39ab1..2bb903155e 100644 --- a/osu.Game/Rulesets/Objects/SliderPath.cs +++ b/osu.Game/Rulesets/Objects/SliderPath.cs @@ -57,6 +57,7 @@ namespace osu.Game.Rulesets.Objects /// /// The distance of the path after lengthening/shortening to account for . /// + [JsonIgnore] public double Distance { get From f4fd6189f892bd25cc37af571dd7183fc2e667de Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 12 Nov 2018 16:53:30 +0900 Subject: [PATCH 125/155] Implement IEquatable --- osu.Game/Rulesets/Objects/SliderPath.cs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Objects/SliderPath.cs b/osu.Game/Rulesets/Objects/SliderPath.cs index 2bb903155e..548e1680f7 100644 --- a/osu.Game/Rulesets/Objects/SliderPath.cs +++ b/osu.Game/Rulesets/Objects/SliderPath.cs @@ -11,7 +11,7 @@ using OpenTK; namespace osu.Game.Rulesets.Objects { - public struct SliderPath + public struct SliderPath : IEquatable { /// /// The control points of the path. @@ -254,5 +254,21 @@ namespace osu.Game.Rulesets.Objects double w = (d - d0) / (d1 - d0); return p0 + (p1 - p0) * (float)w; } + + public bool Equals(SliderPath other) + { + if (ControlPoints == null && other.ControlPoints != null) + return false; + if (other.ControlPoints == null && ControlPoints != null) + return false; + + return ControlPoints.SequenceEqual(other.ControlPoints) && ExpectedDistance.Equals(other.ExpectedDistance) && Type == other.Type; + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + return obj is SliderPath other && Equals(other); + } } } From 1101e161d9155a5e51da153bf9c15fb9e325be4c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Nov 2018 17:01:50 +0900 Subject: [PATCH 126/155] Update framework and resources --- osu-resources | 2 +- osu.Game/osu.Game.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu-resources b/osu-resources index 9ee64e369f..651e598b01 160000 --- a/osu-resources +++ b/osu-resources @@ -1 +1 @@ -Subproject commit 9ee64e369fe6fdafc6aed40f5a35b5f01eb82c53 +Subproject commit 651e598b016b43e31ab1c1b29d5b30c92361b8d9 diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index c9461ea504..9f7996a5fd 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -18,7 +18,7 @@ - + From f3ba4297018b97fb4eacd1b4d118a6aeb364e6a2 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 12 Nov 2018 17:10:37 +0900 Subject: [PATCH 127/155] Make sure control points is internally initialised --- .../Components/PathControlPointPiece.cs | 1 - osu.Game/Rulesets/Objects/SliderPath.cs | 26 ++++++++++++++----- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs index 22ad911c21..7100d9443e 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs @@ -1,7 +1,6 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; diff --git a/osu.Game/Rulesets/Objects/SliderPath.cs b/osu.Game/Rulesets/Objects/SliderPath.cs index 548e1680f7..74a312698c 100644 --- a/osu.Game/Rulesets/Objects/SliderPath.cs +++ b/osu.Game/Rulesets/Objects/SliderPath.cs @@ -13,11 +13,6 @@ namespace osu.Game.Rulesets.Objects { public struct SliderPath : IEquatable { - /// - /// The control points of the path. - /// - public readonly Vector2[] ControlPoints; - /// /// The user-set distance of the path. If non-null, will match this value, /// and the path will be shortened/lengthened to match this length. @@ -29,6 +24,9 @@ namespace osu.Game.Rulesets.Objects /// public readonly PathType Type; + [JsonProperty] + private Vector2[] controlPoints; + private List calculatedPath; private List cumulativeLength; @@ -46,14 +44,27 @@ namespace osu.Game.Rulesets.Objects public SliderPath(PathType type, Vector2[] controlPoints, double? expectedDistance = null) { this = default; + this.controlPoints = controlPoints; - ControlPoints = controlPoints; Type = type; ExpectedDistance = expectedDistance; ensureInitialised(); } + /// + /// The control points of the path. + /// + [JsonIgnore] + public ReadOnlySpan ControlPoints + { + get + { + ensureInitialised(); + return controlPoints.AsSpan(); + } + } + /// /// The distance of the path after lengthening/shortening to account for . /// @@ -116,6 +127,7 @@ namespace osu.Game.Rulesets.Objects return; isInitialised = true; + controlPoints = controlPoints ?? Array.Empty(); calculatedPath = new List(); cumulativeLength = new List(); @@ -166,7 +178,7 @@ namespace osu.Game.Rulesets.Objects if (i == ControlPoints.Length - 1 || ControlPoints[i] == ControlPoints[i + 1]) { - ReadOnlySpan cpSpan = ControlPoints.AsSpan().Slice(start, end - start); + ReadOnlySpan cpSpan = ControlPoints.Slice(start, end - start); foreach (Vector2 t in calculateSubpath(cpSpan)) if (calculatedPath.Count == 0 || calculatedPath.Last() != t) From e3c60c2f965d2d5288ab0df4c49382451fb9c757 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 12 Nov 2018 17:18:58 +0900 Subject: [PATCH 128/155] Cleanups --- .../Edit/Blueprints/HoldNoteSelectionBlueprint.cs | 2 -- .../Edit/Blueprints/ManiaSelectionBlueprint.cs | 2 ++ .../Edit/Blueprints/NoteSelectionBlueprint.cs | 3 --- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs index 2cb0597a40..c41c7addd0 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs @@ -26,8 +26,6 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints public HoldNoteSelectionBlueprint(DrawableHoldNote hold) : base(hold) { - RelativeSizeAxes = Axes.None; - InternalChildren = new Drawable[] { new HoldNoteNoteSelectionBlueprint(hold.Head), diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs index 474b8c662e..53f9dd8752 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.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 osu.Framework.Graphics; using osu.Framework.Input.Events; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects.Drawables; @@ -12,6 +13,7 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints public ManiaSelectionBlueprint(DrawableHitObject hitObject) : base(hitObject) { + RelativeSizeAxes = Axes.None; } public override void AdjustPosition(DragEvent dragEvent) diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/NoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/NoteSelectionBlueprint.cs index 0ad99f9709..7c0337dc4e 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/NoteSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/NoteSelectionBlueprint.cs @@ -2,7 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Allocation; -using osu.Framework.Graphics; using osu.Game.Graphics; using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; @@ -14,8 +13,6 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints public NoteSelectionBlueprint(DrawableNote note) : base(note) { - RelativeSizeAxes = Axes.None; - Scale = note.Scale; CornerRadius = 5; From aee7a80e71683b1377e87bab67ecd3689c9bc810 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 12 Nov 2018 17:26:37 +0900 Subject: [PATCH 129/155] ScrollAlgorithm -> ScrollVisualisationMethod --- osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs | 2 +- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 2 +- ...ScrollAlgorithm.cs => ScrollVisualisationMethod.cs} | 2 +- .../UI/Scrolling/ScrollingHitObjectContainer.cs | 10 +++++----- osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) rename osu.Game/Configuration/{ScrollAlgorithm.cs => ScrollVisualisationMethod.cs} (90%) diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs index 160d784f5f..08b7684677 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Catch.UI protected override bool UserScrollSpeedAdjustment => false; - protected override ScrollAlgorithm ScrollAlgorithm => ScrollAlgorithm.Constant; + protected override ScrollVisualisationMethod VisualisationMethod => ScrollVisualisationMethod.Constant; public CatchPlayfield(BeatmapDifficulty difficulty, Func> getVisualRepresentation) { diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index eab2965160..824c1f817a 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Taiko.UI protected override bool UserScrollSpeedAdjustment => false; - protected override ScrollAlgorithm ScrollAlgorithm => ScrollAlgorithm.Overlapping; + protected override ScrollVisualisationMethod VisualisationMethod => ScrollVisualisationMethod.Overlapping; private readonly Container hitExplosionContainer; private readonly Container kiaiExplosionContainer; diff --git a/osu.Game/Configuration/ScrollAlgorithm.cs b/osu.Game/Configuration/ScrollVisualisationMethod.cs similarity index 90% rename from osu.Game/Configuration/ScrollAlgorithm.cs rename to osu.Game/Configuration/ScrollVisualisationMethod.cs index be302d38f6..cc7dcdbc0e 100644 --- a/osu.Game/Configuration/ScrollAlgorithm.cs +++ b/osu.Game/Configuration/ScrollVisualisationMethod.cs @@ -5,7 +5,7 @@ using System.ComponentModel; namespace osu.Game.Configuration { - public enum ScrollAlgorithm + public enum ScrollVisualisationMethod { [Description("Sequential")] Sequential, diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index 45bc95a71c..489604afc9 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -35,22 +35,22 @@ namespace osu.Game.Rulesets.UI.Scrolling private Cached initialStateCache = new Cached(); - public ScrollingHitObjectContainer(ScrollAlgorithm scrollAlgorithm) + public ScrollingHitObjectContainer(ScrollVisualisationMethod visualisationMethod) { RelativeSizeAxes = Axes.Both; TimeRange.ValueChanged += _ => initialStateCache.Invalidate(); Direction.ValueChanged += _ => initialStateCache.Invalidate(); - switch (scrollAlgorithm) + switch (visualisationMethod) { - case ScrollAlgorithm.Sequential: + case ScrollVisualisationMethod.Sequential: algorithm = new SequentialScrollAlgorithm(ControlPoints); break; - case ScrollAlgorithm.Overlapping: + case ScrollVisualisationMethod.Overlapping: algorithm = new OverlappingScrollAlgorithm(ControlPoints); break; - case ScrollAlgorithm.Constant: + case ScrollVisualisationMethod.Constant: algorithm = new ConstantScrollAlgorithm(); break; } diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs index b0367444bb..5e2704c9ee 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs @@ -63,7 +63,7 @@ namespace osu.Game.Rulesets.UI.Scrolling /// protected readonly Bindable Direction = new Bindable(); - protected virtual ScrollAlgorithm ScrollAlgorithm => ScrollAlgorithm.Sequential; + protected virtual ScrollVisualisationMethod VisualisationMethod => ScrollVisualisationMethod.Sequential; [BackgroundDependencyLoader] private void load() @@ -93,7 +93,7 @@ namespace osu.Game.Rulesets.UI.Scrolling protected sealed override HitObjectContainer CreateHitObjectContainer() { - var container = new ScrollingHitObjectContainer(ScrollAlgorithm); + var container = new ScrollingHitObjectContainer(VisualisationMethod); container.Direction.BindTo(Direction); return container; } From 7f0f143a1bb3bec08df923313a882b299065ae84 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 6 Nov 2018 12:01:54 +0900 Subject: [PATCH 130/155] Move IScrollAlgorithm to ScrollingRulesetContainer + use DI --- osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs | 2 - .../UI/CatchRulesetContainer.cs | 3 + osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 3 - .../UI/TaikoRulesetContainer.cs | 3 + .../Visual/TestCaseScrollingHitObjects.cs | 67 +++++++++++++++++-- .../Scrolling/ScrollingHitObjectContainer.cs | 34 ++-------- .../UI/Scrolling/ScrollingPlayfield.cs | 5 +- .../UI/Scrolling/ScrollingRulesetContainer.cs | 36 ++++++---- 8 files changed, 97 insertions(+), 56 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs index 08b7684677..167e7b4976 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs @@ -5,7 +5,6 @@ using System; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; -using osu.Game.Configuration; using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects.Drawable; using osu.Game.Rulesets.Judgements; @@ -23,7 +22,6 @@ namespace osu.Game.Rulesets.Catch.UI protected override bool UserScrollSpeedAdjustment => false; - protected override ScrollVisualisationMethod VisualisationMethod => ScrollVisualisationMethod.Constant; public CatchPlayfield(BeatmapDifficulty difficulty, Func> getVisualRepresentation) { diff --git a/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs b/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs index 94233bc9f0..60b2707df6 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs @@ -3,6 +3,7 @@ using osu.Framework.Input; using osu.Game.Beatmaps; +using osu.Game.Configuration; using osu.Game.Input.Handlers; using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects.Drawable; @@ -18,6 +19,8 @@ namespace osu.Game.Rulesets.Catch.UI { public class CatchRulesetContainer : ScrollingRulesetContainer { + protected override ScrollAlgorithm ScrollAlgorithm => ScrollAlgorithm.Constant; + public CatchRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) : base(ruleset, beatmap) { diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 824c1f817a..4c69576089 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -8,7 +8,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Judgements; @@ -41,8 +40,6 @@ namespace osu.Game.Rulesets.Taiko.UI protected override bool UserScrollSpeedAdjustment => false; - protected override ScrollVisualisationMethod VisualisationMethod => ScrollVisualisationMethod.Overlapping; - private readonly Container hitExplosionContainer; private readonly Container kiaiExplosionContainer; private readonly JudgementContainer judgementContainer; diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs b/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs index c94ced3390..bd31d49a67 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs @@ -14,6 +14,7 @@ using osu.Game.Rulesets.UI; using osu.Game.Rulesets.Taiko.Replays; using System.Linq; using osu.Framework.Input; +using osu.Game.Configuration; using osu.Game.Input.Handlers; using osu.Game.Rulesets.UI.Scrolling; @@ -21,6 +22,8 @@ namespace osu.Game.Rulesets.Taiko.UI { public class TaikoRulesetContainer : ScrollingRulesetContainer { + protected override ScrollAlgorithm ScrollAlgorithm => ScrollAlgorithm.Overlapping; + public TaikoRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) : base(ruleset, beatmap) { diff --git a/osu.Game.Tests/Visual/TestCaseScrollingHitObjects.cs b/osu.Game.Tests/Visual/TestCaseScrollingHitObjects.cs index eb322df185..ecee153163 100644 --- a/osu.Game.Tests/Visual/TestCaseScrollingHitObjects.cs +++ b/osu.Game.Tests/Visual/TestCaseScrollingHitObjects.cs @@ -4,16 +4,20 @@ using System; using System.Collections.Generic; using NUnit.Framework; +using osu.Framework.Allocation; using osu.Framework.Extensions.IEnumerableExtensions; using OpenTK; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Lists; +using osu.Game.Configuration; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Timing; using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI.Scrolling; +using osu.Game.Rulesets.UI.Scrolling.Algorithms; namespace osu.Game.Tests.Visual { @@ -44,6 +48,10 @@ namespace osu.Game.Tests.Visual } }); + AddStep("Constant scroll", () => setScrollAlgorithm(ScrollAlgorithm.Constant)); + AddStep("Overlapping scroll", () => setScrollAlgorithm(ScrollAlgorithm.Overlapping)); + AddStep("Sequential scroll", () => setScrollAlgorithm(ScrollAlgorithm.Sequential)); + AddSliderStep("Time range", 100, 10000, 5000, v => playfields.ForEach(p => p.VisibleTimeRange.Value = v)); AddStep("Add control point", () => addControlPoint(Time.Current + 5000)); } @@ -52,7 +60,7 @@ namespace osu.Game.Tests.Visual { base.LoadComplete(); - playfields.ForEach(p => p.HitObjects.AddControlPoint(new MultiplierControlPoint(0))); + playfields.ForEach(p => p.ControlPoints.Add(new MultiplierControlPoint(0))); for (int i = 0; i <= 5000; i += 1000) addHitObject(Time.Current + i); @@ -75,9 +83,9 @@ namespace osu.Game.Tests.Visual { playfields.ForEach(p => { - p.HitObjects.AddControlPoint(new MultiplierControlPoint(time) { DifficultyPoint = { SpeedMultiplier = 3 } }); - p.HitObjects.AddControlPoint(new MultiplierControlPoint(time + 2000) { DifficultyPoint = { SpeedMultiplier = 2 } }); - p.HitObjects.AddControlPoint(new MultiplierControlPoint(time + 3000) { DifficultyPoint = { SpeedMultiplier = 1 } }); + p.ControlPoints.Add(new MultiplierControlPoint(time) { DifficultyPoint = { SpeedMultiplier = 3 } }); + p.ControlPoints.Add(new MultiplierControlPoint(time + 2000) { DifficultyPoint = { SpeedMultiplier = 2 } }); + p.ControlPoints.Add(new MultiplierControlPoint(time + 3000) { DifficultyPoint = { SpeedMultiplier = 1 } }); TestDrawableControlPoint createDrawablePoint(double t) { @@ -111,11 +119,19 @@ namespace osu.Game.Tests.Visual } } + private void setScrollAlgorithm(ScrollAlgorithm algorithm) => playfields.ForEach(p => p.ScrollAlgorithm = algorithm); private class TestPlayfield : ScrollingPlayfield { public new ScrollingDirection Direction => base.Direction; + public SortedList ControlPoints => algorithm.ControlPoints; + + public ScrollAlgorithm ScrollAlgorithm { set => algorithm.Algorithm = value; } + + [Cached(Type = typeof(IScrollAlgorithm))] + private readonly TestScrollAlgorithm algorithm = new TestScrollAlgorithm(); + public TestPlayfield(ScrollingDirection direction) { base.Direction.Value = direction; @@ -139,6 +155,49 @@ namespace osu.Game.Tests.Visual } } + private class TestScrollAlgorithm : IScrollAlgorithm + { + public readonly SortedList ControlPoints = new SortedList(); + + private IScrollAlgorithm implementation; + + public TestScrollAlgorithm() + { + Algorithm = ScrollAlgorithm.Constant; + } + + public ScrollAlgorithm Algorithm + { + set + { + switch (value) + { + case ScrollAlgorithm.Constant: + implementation = new ConstantScrollAlgorithm(); + break; + case ScrollAlgorithm.Overlapping: + implementation = new OverlappingScrollAlgorithm(ControlPoints); + break; + case ScrollAlgorithm.Sequential: + implementation = new SequentialScrollAlgorithm(ControlPoints); + break; + } + } + } + + public double GetDisplayStartTime(double time, double timeRange) + => implementation.GetDisplayStartTime(time, timeRange); + + public float GetLength(double startTime, double endTime, double timeRange, float scrollLength) + => implementation.GetLength(startTime, endTime, timeRange, scrollLength); + + public float PositionAt(double time, double currentTime, double timeRange, float scrollLength) + => implementation.PositionAt(time, currentTime, timeRange, scrollLength); + + public void Reset() + => implementation.Reset(); + } + private class TestDrawableControlPoint : DrawableHitObject { public TestDrawableControlPoint(ScrollingDirection direction, double time) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index 489604afc9..6bcba211da 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -1,11 +1,11 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using osu.Framework.Allocation; using osu.Framework.Caching; using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Lists; -using osu.Game.Configuration; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Timing; @@ -31,29 +31,17 @@ namespace osu.Game.Rulesets.UI.Scrolling public readonly Bindable Direction = new Bindable(); - private readonly IScrollAlgorithm algorithm; + [Resolved] + private IScrollAlgorithm algorithm { get; set; } private Cached initialStateCache = new Cached(); - public ScrollingHitObjectContainer(ScrollVisualisationMethod visualisationMethod) + public ScrollingHitObjectContainer() { RelativeSizeAxes = Axes.Both; TimeRange.ValueChanged += _ => initialStateCache.Invalidate(); Direction.ValueChanged += _ => initialStateCache.Invalidate(); - - switch (visualisationMethod) - { - case ScrollVisualisationMethod.Sequential: - algorithm = new SequentialScrollAlgorithm(ControlPoints); - break; - case ScrollVisualisationMethod.Overlapping: - algorithm = new OverlappingScrollAlgorithm(ControlPoints); - break; - case ScrollVisualisationMethod.Constant: - algorithm = new ConstantScrollAlgorithm(); - break; - } } public override void Add(DrawableHitObject hitObject) @@ -70,20 +58,6 @@ namespace osu.Game.Rulesets.UI.Scrolling return result; } - public void AddControlPoint(MultiplierControlPoint controlPoint) - { - ControlPoints.Add(controlPoint); - initialStateCache.Invalidate(); - } - - public bool RemoveControlPoint(MultiplierControlPoint controlPoint) - { - var result = ControlPoints.Remove(controlPoint); - if (result) - initialStateCache.Invalidate(); - return result; - } - public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true) { if ((invalidation & (Invalidation.RequiredParentSizeToFit | Invalidation.DrawInfo)) > 0) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs index 5e2704c9ee..b555b6616a 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs @@ -5,7 +5,6 @@ using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Input.Bindings; -using osu.Game.Configuration; using osu.Game.Input.Bindings; using osu.Game.Rulesets.Objects.Drawables; @@ -63,8 +62,6 @@ namespace osu.Game.Rulesets.UI.Scrolling /// protected readonly Bindable Direction = new Bindable(); - protected virtual ScrollVisualisationMethod VisualisationMethod => ScrollVisualisationMethod.Sequential; - [BackgroundDependencyLoader] private void load() { @@ -93,7 +90,7 @@ namespace osu.Game.Rulesets.UI.Scrolling protected sealed override HitObjectContainer CreateHitObjectContainer() { - var container = new ScrollingHitObjectContainer(VisualisationMethod); + var container = new ScrollingHitObjectContainer(); container.Direction.BindTo(Direction); return container; } diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingRulesetContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingRulesetContainer.cs index 41cdd6c06f..2f6ef730b3 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingRulesetContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingRulesetContainer.cs @@ -4,13 +4,14 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; -using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Lists; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Configuration; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Timing; +using osu.Game.Rulesets.UI.Scrolling.Algorithms; namespace osu.Game.Rulesets.UI.Scrolling { @@ -27,11 +28,28 @@ namespace osu.Game.Rulesets.UI.Scrolling /// inside this . /// /// - protected readonly SortedList DefaultControlPoints = new SortedList(Comparer.Default); + private readonly SortedList controlPoints = new SortedList(Comparer.Default); + + protected virtual ScrollAlgorithm ScrollAlgorithm => ScrollAlgorithm.Sequential; + + [Cached(Type = typeof(IScrollAlgorithm))] + private readonly IScrollAlgorithm algorithm; protected ScrollingRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) : base(ruleset, beatmap) { + switch (ScrollAlgorithm) + { + case ScrollAlgorithm.Sequential: + algorithm = new SequentialScrollAlgorithm(controlPoints); + break; + case ScrollAlgorithm.Overlapping: + algorithm = new OverlappingScrollAlgorithm(controlPoints); + break; + case ScrollAlgorithm.Constant: + algorithm = new ConstantScrollAlgorithm(); + break; + } } [BackgroundDependencyLoader] @@ -75,19 +93,11 @@ namespace osu.Game.Rulesets.UI.Scrolling // Collapse sections with the same start time .GroupBy(s => s.StartTime).Select(g => g.Last()).OrderBy(s => s.StartTime); - DefaultControlPoints.AddRange(timingChanges); + controlPoints.AddRange(timingChanges); // If we have no control points, add a default one - if (DefaultControlPoints.Count == 0) - DefaultControlPoints.Add(new MultiplierControlPoint { Velocity = Beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier }); - - DefaultControlPoints.ForEach(c => applySpeedAdjustment(c, Playfield)); - } - - private void applySpeedAdjustment(MultiplierControlPoint controlPoint, ScrollingPlayfield playfield) - { - playfield.HitObjects.AddControlPoint(controlPoint); - playfield.NestedPlayfields?.OfType().ForEach(p => applySpeedAdjustment(controlPoint, p)); + if (controlPoints.Count == 0) + controlPoints.Add(new MultiplierControlPoint { Velocity = Beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier }); } } } From 9fde7f7f4482829a92f369453dc494bcadd0733a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 6 Nov 2018 13:58:38 +0900 Subject: [PATCH 131/155] Move scrolling info to osu.Game --- osu.Game.Rulesets.Mania.Tests/ScrollingTestContainer.cs | 1 - .../Edit/Blueprints/HoldNoteSelectionBlueprint.cs | 1 - osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs | 1 + .../Objects/Drawables/DrawableManiaHitObject.cs | 1 - osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/NotePiece.cs | 1 - .../UI => osu.Game/Rulesets/UI/Scrolling}/IScrollingInfo.cs | 3 +-- 6 files changed, 2 insertions(+), 6 deletions(-) rename {osu.Game.Rulesets.Mania/UI => osu.Game/Rulesets/UI/Scrolling}/IScrollingInfo.cs (85%) diff --git a/osu.Game.Rulesets.Mania.Tests/ScrollingTestContainer.cs b/osu.Game.Rulesets.Mania.Tests/ScrollingTestContainer.cs index 29663c2093..ea5659e690 100644 --- a/osu.Game.Rulesets.Mania.Tests/ScrollingTestContainer.cs +++ b/osu.Game.Rulesets.Mania.Tests/ScrollingTestContainer.cs @@ -4,7 +4,6 @@ using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Graphics.Containers; -using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.UI.Scrolling; namespace osu.Game.Rulesets.Mania.Tests diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs index 0ede2a7b9d..f6f33624e5 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs @@ -8,7 +8,6 @@ using osu.Game.Graphics; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; -using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.UI.Scrolling; using OpenTK; using OpenTK.Graphics; diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs index 06d67821a9..0cc4d30163 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs @@ -14,6 +14,7 @@ using osu.Game.Rulesets.Mania.Configuration; using osu.Game.Rulesets.Mania.Edit.Blueprints; using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.UI; +using osu.Game.Rulesets.UI.Scrolling; namespace osu.Game.Rulesets.Mania.Edit { diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs index cb6196a890..8c96c6dfe7 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs @@ -5,7 +5,6 @@ using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Graphics; -using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.UI.Scrolling; diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/NotePiece.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/NotePiece.cs index 2c74f5b168..b7c90e5144 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/NotePiece.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/NotePiece.cs @@ -9,7 +9,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; -using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.UI.Scrolling; namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces diff --git a/osu.Game.Rulesets.Mania/UI/IScrollingInfo.cs b/osu.Game/Rulesets/UI/Scrolling/IScrollingInfo.cs similarity index 85% rename from osu.Game.Rulesets.Mania/UI/IScrollingInfo.cs rename to osu.Game/Rulesets/UI/Scrolling/IScrollingInfo.cs index ee65e9f1a5..151c6f01e2 100644 --- a/osu.Game.Rulesets.Mania/UI/IScrollingInfo.cs +++ b/osu.Game/Rulesets/UI/Scrolling/IScrollingInfo.cs @@ -3,9 +3,8 @@ using osu.Framework.Configuration; using osu.Game.Rulesets.Objects; -using osu.Game.Rulesets.UI.Scrolling; -namespace osu.Game.Rulesets.Mania.UI +namespace osu.Game.Rulesets.UI.Scrolling { public interface IScrollingInfo { From 48486895ba3a43c4f7a6520929bd91cc73644690 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 6 Nov 2018 14:23:54 +0900 Subject: [PATCH 132/155] Remove unused code --- .../Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index 6bcba211da..a8188fcb87 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -5,10 +5,8 @@ using osu.Framework.Allocation; using osu.Framework.Caching; using osu.Framework.Configuration; using osu.Framework.Graphics; -using osu.Framework.Lists; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Types; -using osu.Game.Rulesets.Timing; using osu.Game.Rulesets.UI.Scrolling.Algorithms; namespace osu.Game.Rulesets.UI.Scrolling @@ -24,11 +22,6 @@ namespace osu.Game.Rulesets.UI.Scrolling MaxValue = double.MaxValue }; - /// - /// The control points that adjust the scrolling speed. - /// - protected readonly SortedList ControlPoints = new SortedList(); - public readonly Bindable Direction = new Bindable(); [Resolved] From ad45bc766609a697e1fe780b13d43e18c81a2c70 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 6 Nov 2018 15:46:36 +0900 Subject: [PATCH 133/155] Move scroll direction to scrollinginfo --- osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs | 3 - .../UI/CatchRulesetContainer.cs | 1 + .../ScrollingTestContainer.cs | 32 ------ .../TestCaseColumn.cs | 1 + .../TestCaseStage.cs | 1 + .../Edit/ManiaHitObjectComposer.cs | 12 ++- osu.Game.Rulesets.Mania/UI/Column.cs | 4 +- osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs | 3 +- .../UI/ManiaRulesetContainer.cs | 16 +-- .../UI/ManiaScrollingInfo.cs | 23 ----- .../UI/ManiaScrollingPlayfield.cs | 21 ---- osu.Game.Rulesets.Mania/UI/ManiaStage.cs | 2 +- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 2 - .../UI/TaikoRulesetContainer.cs | 1 + .../Visual/TestCaseScrollingHitObjects.cs | 99 ++++++------------- .../Scrolling/ScrollingHitObjectContainer.cs | 19 +++- .../UI/Scrolling/ScrollingPlayfield.cs | 16 ++- .../UI/Scrolling/ScrollingRulesetContainer.cs | 26 ++++- .../Tests/Visual/ScrollingTestContainer.cs | 87 ++++++++++++++++ 19 files changed, 185 insertions(+), 184 deletions(-) delete mode 100644 osu.Game.Rulesets.Mania.Tests/ScrollingTestContainer.cs delete mode 100644 osu.Game.Rulesets.Mania/UI/ManiaScrollingInfo.cs delete mode 100644 osu.Game.Rulesets.Mania/UI/ManiaScrollingPlayfield.cs create mode 100644 osu.Game/Tests/Visual/ScrollingTestContainer.cs diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs index 167e7b4976..0782930f63 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs @@ -22,11 +22,8 @@ namespace osu.Game.Rulesets.Catch.UI protected override bool UserScrollSpeedAdjustment => false; - public CatchPlayfield(BeatmapDifficulty difficulty, Func> getVisualRepresentation) { - Direction.Value = ScrollingDirection.Down; - Container explodingFruitContainer; Anchor = Anchor.TopCentre; diff --git a/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs b/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs index 60b2707df6..31a6c74959 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs @@ -24,6 +24,7 @@ namespace osu.Game.Rulesets.Catch.UI public CatchRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) : base(ruleset, beatmap) { + Direction.Value = ScrollingDirection.Down; } public override ScoreProcessor CreateScoreProcessor() => new CatchScoreProcessor(this); diff --git a/osu.Game.Rulesets.Mania.Tests/ScrollingTestContainer.cs b/osu.Game.Rulesets.Mania.Tests/ScrollingTestContainer.cs deleted file mode 100644 index ea5659e690..0000000000 --- a/osu.Game.Rulesets.Mania.Tests/ScrollingTestContainer.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using osu.Framework.Allocation; -using osu.Framework.Configuration; -using osu.Framework.Graphics.Containers; -using osu.Game.Rulesets.UI.Scrolling; - -namespace osu.Game.Rulesets.Mania.Tests -{ - /// - /// A container which provides a to children. - /// - public class ScrollingTestContainer : Container - { - [Cached(Type = typeof(IScrollingInfo))] - private readonly TestScrollingInfo scrollingInfo = new TestScrollingInfo(); - - public ScrollingTestContainer(ScrollingDirection direction) - { - scrollingInfo.Direction.Value = direction; - } - - public void Flip() => scrollingInfo.Direction.Value = scrollingInfo.Direction.Value == ScrollingDirection.Up ? ScrollingDirection.Down : ScrollingDirection.Up; - } - - public class TestScrollingInfo : IScrollingInfo - { - public readonly Bindable Direction = new Bindable(); - IBindable IScrollingInfo.Direction => Direction; - } -} diff --git a/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs b/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs index cceee718ca..048ebe39e8 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs @@ -14,6 +14,7 @@ using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Mania.UI.Components; using osu.Game.Rulesets.UI.Scrolling; +using osu.Game.Tests.Visual; using OpenTK; using OpenTK.Graphics; diff --git a/osu.Game.Rulesets.Mania.Tests/TestCaseStage.cs b/osu.Game.Rulesets.Mania.Tests/TestCaseStage.cs index 5c5d955168..a7e3c7da41 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestCaseStage.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestCaseStage.cs @@ -14,6 +14,7 @@ using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.UI.Scrolling; +using osu.Game.Tests.Visual; using OpenTK; namespace osu.Game.Rulesets.Mania.Tests diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs index 0cc4d30163..7cbf6495f5 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs @@ -10,9 +10,8 @@ using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables; using System.Collections.Generic; using osu.Framework.Allocation; -using osu.Game.Rulesets.Mania.Configuration; +using osu.Framework.Configuration; using osu.Game.Rulesets.Mania.Edit.Blueprints; -using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI.Scrolling; @@ -20,8 +19,6 @@ namespace osu.Game.Rulesets.Mania.Edit { public class ManiaHitObjectComposer : HitObjectComposer { - protected new ManiaConfigManager Config => (ManiaConfigManager)base.Config; - public ManiaHitObjectComposer(Ruleset ruleset) : base(ruleset) { @@ -30,7 +27,7 @@ namespace osu.Game.Rulesets.Mania.Edit protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) { var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); - dependencies.CacheAs(new ManiaScrollingInfo(Config)); + dependencies.CacheAs(new ScrollingInfo()); return dependencies; } @@ -51,5 +48,10 @@ namespace osu.Game.Rulesets.Mania.Edit return base.CreateBlueprintFor(hitObject); } + + private class ScrollingInfo : IScrollingInfo + { + public IBindable Direction { get; } = new Bindable(); + } } } diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs index 09976e5994..547e0abae8 100644 --- a/osu.Game.Rulesets.Mania/UI/Column.cs +++ b/osu.Game.Rulesets.Mania/UI/Column.cs @@ -16,7 +16,7 @@ using osu.Game.Rulesets.UI.Scrolling; namespace osu.Game.Rulesets.Mania.UI { - public class Column : ManiaScrollingPlayfield, IKeyBindingHandler, IHasAccentColour + public class Column : ScrollingPlayfield, IKeyBindingHandler, IHasAccentColour { private const float column_width = 45; private const float special_column_width = 70; @@ -144,7 +144,7 @@ namespace osu.Game.Rulesets.Mania.UI explosionContainer.Add(new HitExplosion(judgedObject) { - Anchor = Direction == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre + Anchor = Direction.Value == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre }); } diff --git a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs index 5c3a618a19..dc965ea7f4 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs @@ -10,11 +10,12 @@ using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Configuration; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.UI.Scrolling; using OpenTK; namespace osu.Game.Rulesets.Mania.UI { - public class ManiaPlayfield : ManiaScrollingPlayfield + public class ManiaPlayfield : ScrollingPlayfield { private readonly List stages = new List(); diff --git a/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs b/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs index 500fb5a631..34182b7219 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Configuration; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Input; @@ -35,6 +36,8 @@ namespace osu.Game.Rulesets.Mania.UI protected new ManiaConfigManager Config => (ManiaConfigManager)base.Config; + private readonly Bindable configDirection = new Bindable(); + public ManiaRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) : base(ruleset, beatmap) { @@ -70,18 +73,9 @@ namespace osu.Game.Rulesets.Mania.UI private void load() { BarLines.ForEach(Playfield.Add); - } - private DependencyContainer dependencies; - - protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) - { - dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); - - if (dependencies.Get() == null) - dependencies.CacheAs(new ManiaScrollingInfo(Config)); - - return dependencies; + Config.BindWith(ManiaSetting.ScrollDirection, configDirection); + configDirection.BindValueChanged(v => Direction.Value = (ScrollingDirection)v, true); } protected override Playfield CreatePlayfield() => new ManiaPlayfield(Beatmap.Stages) diff --git a/osu.Game.Rulesets.Mania/UI/ManiaScrollingInfo.cs b/osu.Game.Rulesets.Mania/UI/ManiaScrollingInfo.cs deleted file mode 100644 index 624ea13e1b..0000000000 --- a/osu.Game.Rulesets.Mania/UI/ManiaScrollingInfo.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using osu.Framework.Configuration; -using osu.Game.Rulesets.Mania.Configuration; -using osu.Game.Rulesets.UI.Scrolling; - -namespace osu.Game.Rulesets.Mania.UI -{ - public class ManiaScrollingInfo : IScrollingInfo - { - private readonly Bindable configDirection = new Bindable(); - - public readonly Bindable Direction = new Bindable(); - IBindable IScrollingInfo.Direction => Direction; - - public ManiaScrollingInfo(ManiaConfigManager config) - { - config.BindWith(ManiaSetting.ScrollDirection, configDirection); - configDirection.BindValueChanged(v => Direction.Value = (ScrollingDirection)v, true); - } - } -} diff --git a/osu.Game.Rulesets.Mania/UI/ManiaScrollingPlayfield.cs b/osu.Game.Rulesets.Mania/UI/ManiaScrollingPlayfield.cs deleted file mode 100644 index 8ee0fbf7fe..0000000000 --- a/osu.Game.Rulesets.Mania/UI/ManiaScrollingPlayfield.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using osu.Framework.Allocation; -using osu.Framework.Configuration; -using osu.Game.Rulesets.UI.Scrolling; - -namespace osu.Game.Rulesets.Mania.UI -{ - public abstract class ManiaScrollingPlayfield : ScrollingPlayfield - { - private readonly IBindable direction = new Bindable(); - - [BackgroundDependencyLoader] - private void load(IScrollingInfo scrollingInfo) - { - direction.BindTo(scrollingInfo.Direction); - direction.BindValueChanged(direction => Direction.Value = direction, true); - } - } -} diff --git a/osu.Game.Rulesets.Mania/UI/ManiaStage.cs b/osu.Game.Rulesets.Mania/UI/ManiaStage.cs index 8cf49686b9..48caf91d7b 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaStage.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaStage.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Mania.UI /// /// A collection of s. /// - public class ManiaStage : ManiaScrollingPlayfield + public class ManiaStage : ScrollingPlayfield { public const float HIT_TARGET_POSITION = 50; diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 4c69576089..97fdbc5b7a 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -56,8 +56,6 @@ namespace osu.Game.Rulesets.Taiko.UI public TaikoPlayfield(ControlPointInfo controlPoints) { - Direction.Value = ScrollingDirection.Left; - InternalChild = new PlayfieldAdjustmentContainer { Anchor = Anchor.CentreLeft, diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs b/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs index bd31d49a67..afec8094ad 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs @@ -27,6 +27,7 @@ namespace osu.Game.Rulesets.Taiko.UI public TaikoRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) : base(ruleset, beatmap) { + Direction.Value = ScrollingDirection.Left; } [BackgroundDependencyLoader] diff --git a/osu.Game.Tests/Visual/TestCaseScrollingHitObjects.cs b/osu.Game.Tests/Visual/TestCaseScrollingHitObjects.cs index ecee153163..ecc7b3ed7a 100644 --- a/osu.Game.Tests/Visual/TestCaseScrollingHitObjects.cs +++ b/osu.Game.Tests/Visual/TestCaseScrollingHitObjects.cs @@ -4,20 +4,17 @@ using System; using System.Collections.Generic; using NUnit.Framework; -using osu.Framework.Allocation; using osu.Framework.Extensions.IEnumerableExtensions; using OpenTK; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Framework.Lists; using osu.Game.Configuration; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Timing; using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI.Scrolling; -using osu.Game.Rulesets.UI.Scrolling.Algorithms; namespace osu.Game.Tests.Visual { @@ -26,6 +23,7 @@ namespace osu.Game.Tests.Visual { public override IReadOnlyList RequiredTypes => new[] { typeof(Playfield) }; + private readonly ScrollingTestContainer[] scrollContainers = new ScrollingTestContainer[4]; private readonly TestPlayfield[] playfields = new TestPlayfield[4]; public TestCaseScrollingHitObjects() @@ -37,13 +35,29 @@ namespace osu.Game.Tests.Visual { new Drawable[] { - playfields[0] = new TestPlayfield(ScrollingDirection.Up), - playfields[1] = new TestPlayfield(ScrollingDirection.Down) + scrollContainers[0] = new ScrollingTestContainer(ScrollingDirection.Up) + { + RelativeSizeAxes = Axes.Both, + Child = playfields[0] = new TestPlayfield() + }, + scrollContainers[1] = new ScrollingTestContainer(ScrollingDirection.Up) + { + RelativeSizeAxes = Axes.Both, + Child = playfields[1] = new TestPlayfield() + }, }, new Drawable[] { - playfields[2] = new TestPlayfield(ScrollingDirection.Left), - playfields[3] = new TestPlayfield(ScrollingDirection.Right) + scrollContainers[2] = new ScrollingTestContainer(ScrollingDirection.Up) + { + RelativeSizeAxes = Axes.Both, + Child = playfields[2] = new TestPlayfield() + }, + scrollContainers[3] = new ScrollingTestContainer(ScrollingDirection.Up) + { + RelativeSizeAxes = Axes.Both, + Child = playfields[3] = new TestPlayfield() + } } } }); @@ -60,7 +74,7 @@ namespace osu.Game.Tests.Visual { base.LoadComplete(); - playfields.ForEach(p => p.ControlPoints.Add(new MultiplierControlPoint(0))); + scrollContainers.ForEach(c => c.ControlPoints.Add(new MultiplierControlPoint(0))); for (int i = 0; i <= 5000; i += 1000) addHitObject(Time.Current + i); @@ -81,12 +95,15 @@ namespace osu.Game.Tests.Visual private void addControlPoint(double time) { + scrollContainers.ForEach(c => + { + c.ControlPoints.Add(new MultiplierControlPoint(time) { DifficultyPoint = { SpeedMultiplier = 3 } }); + c.ControlPoints.Add(new MultiplierControlPoint(time + 2000) { DifficultyPoint = { SpeedMultiplier = 2 } }); + c.ControlPoints.Add(new MultiplierControlPoint(time + 3000) { DifficultyPoint = { SpeedMultiplier = 1 } }); + }); + playfields.ForEach(p => { - p.ControlPoints.Add(new MultiplierControlPoint(time) { DifficultyPoint = { SpeedMultiplier = 3 } }); - p.ControlPoints.Add(new MultiplierControlPoint(time + 2000) { DifficultyPoint = { SpeedMultiplier = 2 } }); - p.ControlPoints.Add(new MultiplierControlPoint(time + 3000) { DifficultyPoint = { SpeedMultiplier = 1 } }); - TestDrawableControlPoint createDrawablePoint(double t) { var obj = new TestDrawableControlPoint(p.Direction, t); @@ -119,23 +136,14 @@ namespace osu.Game.Tests.Visual } } - private void setScrollAlgorithm(ScrollAlgorithm algorithm) => playfields.ForEach(p => p.ScrollAlgorithm = algorithm); + private void setScrollAlgorithm(ScrollAlgorithm algorithm) => scrollContainers.ForEach(c => c.ScrollAlgorithm = algorithm); private class TestPlayfield : ScrollingPlayfield { - public new ScrollingDirection Direction => base.Direction; + public new ScrollingDirection Direction => base.Direction.Value; - public SortedList ControlPoints => algorithm.ControlPoints; - - public ScrollAlgorithm ScrollAlgorithm { set => algorithm.Algorithm = value; } - - [Cached(Type = typeof(IScrollAlgorithm))] - private readonly TestScrollAlgorithm algorithm = new TestScrollAlgorithm(); - - public TestPlayfield(ScrollingDirection direction) + public TestPlayfield() { - base.Direction.Value = direction; - Padding = new MarginPadding(2); InternalChildren = new Drawable[] @@ -155,49 +163,6 @@ namespace osu.Game.Tests.Visual } } - private class TestScrollAlgorithm : IScrollAlgorithm - { - public readonly SortedList ControlPoints = new SortedList(); - - private IScrollAlgorithm implementation; - - public TestScrollAlgorithm() - { - Algorithm = ScrollAlgorithm.Constant; - } - - public ScrollAlgorithm Algorithm - { - set - { - switch (value) - { - case ScrollAlgorithm.Constant: - implementation = new ConstantScrollAlgorithm(); - break; - case ScrollAlgorithm.Overlapping: - implementation = new OverlappingScrollAlgorithm(ControlPoints); - break; - case ScrollAlgorithm.Sequential: - implementation = new SequentialScrollAlgorithm(ControlPoints); - break; - } - } - } - - public double GetDisplayStartTime(double time, double timeRange) - => implementation.GetDisplayStartTime(time, timeRange); - - public float GetLength(double startTime, double endTime, double timeRange, float scrollLength) - => implementation.GetLength(startTime, endTime, timeRange, scrollLength); - - public float PositionAt(double time, double currentTime, double timeRange, float scrollLength) - => implementation.PositionAt(time, currentTime, timeRange, scrollLength); - - public void Reset() - => implementation.Reset(); - } - private class TestDrawableControlPoint : DrawableHitObject { public TestDrawableControlPoint(ScrollingDirection direction, double time) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index a8188fcb87..fda3a4cdc5 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -22,11 +22,14 @@ namespace osu.Game.Rulesets.UI.Scrolling MaxValue = double.MaxValue }; - public readonly Bindable Direction = new Bindable(); + private readonly IBindable direction = new Bindable(); [Resolved] private IScrollAlgorithm algorithm { get; set; } + [Resolved] + private IScrollingInfo scrollingInfo { get; set; } + private Cached initialStateCache = new Cached(); public ScrollingHitObjectContainer() @@ -34,7 +37,13 @@ namespace osu.Game.Rulesets.UI.Scrolling RelativeSizeAxes = Axes.Both; TimeRange.ValueChanged += _ => initialStateCache.Invalidate(); - Direction.ValueChanged += _ => initialStateCache.Invalidate(); + direction.ValueChanged += _ => initialStateCache.Invalidate(); + } + + [BackgroundDependencyLoader] + private void load() + { + direction.BindTo(scrollingInfo.Direction); } public override void Add(DrawableHitObject hitObject) @@ -67,7 +76,7 @@ namespace osu.Game.Rulesets.UI.Scrolling if (!initialStateCache.IsValid) { - switch (Direction.Value) + switch (direction.Value) { case ScrollingDirection.Up: case ScrollingDirection.Down: @@ -92,7 +101,7 @@ namespace osu.Game.Rulesets.UI.Scrolling if (hitObject.HitObject is IHasEndTime endTime) { - switch (Direction.Value) + switch (direction.Value) { case ScrollingDirection.Up: case ScrollingDirection.Down: @@ -125,7 +134,7 @@ namespace osu.Game.Rulesets.UI.Scrolling private void updatePosition(DrawableHitObject hitObject, double currentTime) { - switch (Direction.Value) + switch (direction.Value) { case ScrollingDirection.Up: hitObject.Y = algorithm.PositionAt(hitObject.HitObject.StartTime, currentTime, TimeRange, scrollLength); diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs index b555b6616a..c3b358825c 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs @@ -52,19 +52,20 @@ namespace osu.Game.Rulesets.UI.Scrolling /// protected virtual bool UserScrollSpeedAdjustment => true; + protected readonly IBindable Direction = new Bindable(); + /// /// The container that contains the s. /// public new ScrollingHitObjectContainer HitObjects => (ScrollingHitObjectContainer)HitObjectContainer; - /// - /// The direction in which s in this should scroll. - /// - protected readonly Bindable Direction = new Bindable(); + [Resolved] + private IScrollingInfo scrollingInfo { get; set; } [BackgroundDependencyLoader] private void load() { + Direction.BindTo(scrollingInfo.Direction); HitObjects.TimeRange.BindTo(VisibleTimeRange); } @@ -88,11 +89,6 @@ namespace osu.Game.Rulesets.UI.Scrolling public bool OnReleased(GlobalAction action) => false; - protected sealed override HitObjectContainer CreateHitObjectContainer() - { - var container = new ScrollingHitObjectContainer(); - container.Direction.BindTo(Direction); - return container; - } + protected sealed override HitObjectContainer CreateHitObjectContainer() => new ScrollingHitObjectContainer(); } } diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingRulesetContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingRulesetContainer.cs index 2f6ef730b3..73fb9591da 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingRulesetContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingRulesetContainer.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Configuration; using osu.Framework.Lists; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; @@ -23,6 +24,10 @@ namespace osu.Game.Rulesets.UI.Scrolling where TObject : HitObject where TPlayfield : ScrollingPlayfield { + protected readonly Bindable Direction = new Bindable(); + + protected virtual ScrollAlgorithm ScrollAlgorithm => ScrollAlgorithm.Sequential; + /// /// Provides the default s that adjust the scrolling rate of s /// inside this . @@ -30,7 +35,7 @@ namespace osu.Game.Rulesets.UI.Scrolling /// private readonly SortedList controlPoints = new SortedList(Comparer.Default); - protected virtual ScrollAlgorithm ScrollAlgorithm => ScrollAlgorithm.Sequential; + private IScrollingInfo scrollingInfo; [Cached(Type = typeof(IScrollAlgorithm))] private readonly IScrollAlgorithm algorithm; @@ -55,6 +60,8 @@ namespace osu.Game.Rulesets.UI.Scrolling [BackgroundDependencyLoader] private void load() { + scrollingInfo.Direction.BindTo(Direction); + // Calculate default multiplier control points var lastTimingPoint = new TimingControlPoint(); var lastDifficultyPoint = new DifficultyControlPoint(); @@ -99,5 +106,22 @@ namespace osu.Game.Rulesets.UI.Scrolling if (controlPoints.Count == 0) controlPoints.Add(new MultiplierControlPoint { Velocity = Beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier }); } + + protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) + { + var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); + + if ((scrollingInfo = dependencies.Get()) == null) + dependencies.CacheAs(scrollingInfo = CreateScrollingInfo()); + + return dependencies; + } + + protected virtual IScrollingInfo CreateScrollingInfo() => new ScrollingInfo(); + + private class ScrollingInfo : IScrollingInfo + { + public IBindable Direction { get; } = new Bindable(); + } } } diff --git a/osu.Game/Tests/Visual/ScrollingTestContainer.cs b/osu.Game/Tests/Visual/ScrollingTestContainer.cs new file mode 100644 index 0000000000..b34dc87638 --- /dev/null +++ b/osu.Game/Tests/Visual/ScrollingTestContainer.cs @@ -0,0 +1,87 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Framework.Configuration; +using osu.Framework.Graphics.Containers; +using osu.Framework.Lists; +using osu.Game.Configuration; +using osu.Game.Rulesets.Timing; +using osu.Game.Rulesets.UI.Scrolling; +using osu.Game.Rulesets.UI.Scrolling.Algorithms; + +namespace osu.Game.Tests.Visual +{ + /// + /// A container which provides a to children. + /// This should only be used when testing + /// + public class ScrollingTestContainer : Container + { + public SortedList ControlPoints => scrollAlgorithm.ControlPoints; + + public ScrollAlgorithm ScrollAlgorithm { set => scrollAlgorithm.Algorithm = value; } + + [Cached(Type = typeof(IScrollingInfo))] + private readonly TestScrollingInfo scrollingInfo = new TestScrollingInfo(); + + [Cached(Type = typeof(IScrollAlgorithm))] + private readonly TestScrollAlgorithm scrollAlgorithm = new TestScrollAlgorithm(); + + public ScrollingTestContainer(ScrollingDirection direction) + { + scrollingInfo.Direction.Value = direction; + } + + public void Flip() => scrollingInfo.Direction.Value = scrollingInfo.Direction.Value == ScrollingDirection.Up ? ScrollingDirection.Down : ScrollingDirection.Up; + + private class TestScrollingInfo : IScrollingInfo + { + public readonly Bindable Direction = new Bindable(); + IBindable IScrollingInfo.Direction => Direction; + } + + private class TestScrollAlgorithm : IScrollAlgorithm + { + public readonly SortedList ControlPoints = new SortedList(); + + private IScrollAlgorithm implementation; + + public TestScrollAlgorithm() + { + Algorithm = ScrollAlgorithm.Constant; + } + + public ScrollAlgorithm Algorithm + { + set + { + switch (value) + { + case ScrollAlgorithm.Constant: + implementation = new ConstantScrollAlgorithm(); + break; + case ScrollAlgorithm.Overlapping: + implementation = new OverlappingScrollAlgorithm(ControlPoints); + break; + case ScrollAlgorithm.Sequential: + implementation = new SequentialScrollAlgorithm(ControlPoints); + break; + } + } + } + + public double GetDisplayStartTime(double time, double timeRange) + => implementation.GetDisplayStartTime(time, timeRange); + + public float GetLength(double startTime, double endTime, double timeRange, float scrollLength) + => implementation.GetLength(startTime, endTime, timeRange, scrollLength); + + public float PositionAt(double time, double currentTime, double timeRange, float scrollLength) + => implementation.PositionAt(time, currentTime, timeRange, scrollLength); + + public void Reset() + => implementation.Reset(); + } + } +} From 54668a0decb075f257c55e4d7e87ddc0a71b334f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 7 Nov 2018 16:43:34 +0900 Subject: [PATCH 134/155] Simplify construction of ScrollingInfo --- .../Edit/ManiaEditRulesetContainer.cs | 3 +++ .../Edit/ManiaHitObjectComposer.cs | 22 +++++++++---------- .../UI/Scrolling/ScrollingRulesetContainer.cs | 22 ++++++------------- 3 files changed, 21 insertions(+), 26 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaEditRulesetContainer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaEditRulesetContainer.cs index 138a2c0273..2404297cc3 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaEditRulesetContainer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaEditRulesetContainer.cs @@ -6,11 +6,14 @@ using OpenTK; using osu.Game.Beatmaps; using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.UI; +using osu.Game.Rulesets.UI.Scrolling; namespace osu.Game.Rulesets.Mania.Edit { public class ManiaEditRulesetContainer : ManiaRulesetContainer { + public new IScrollingInfo ScrollingInfo => base.ScrollingInfo; + public ManiaEditRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) : base(ruleset, beatmap) { diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs index 7cbf6495f5..837f940a62 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs @@ -24,15 +24,20 @@ namespace osu.Game.Rulesets.Mania.Edit { } + private DependencyContainer dependencies; + protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) - { - var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); - dependencies.CacheAs(new ScrollingInfo()); - return dependencies; - } + => dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); protected override RulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) - => new ManiaEditRulesetContainer(ruleset, beatmap); + { + var rulesetContainer = new ManiaEditRulesetContainer(ruleset, beatmap); + + // This is the earliest we can cache the scrolling info to ourselves, before masks are added to the hierarchy and inject it + dependencies.CacheAs(rulesetContainer.ScrollingInfo); + + return rulesetContainer; + } protected override IReadOnlyList CompositionTools => Array.Empty(); @@ -48,10 +53,5 @@ namespace osu.Game.Rulesets.Mania.Edit return base.CreateBlueprintFor(hitObject); } - - private class ScrollingInfo : IScrollingInfo - { - public IBindable Direction { get; } = new Bindable(); - } } } diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingRulesetContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingRulesetContainer.cs index 73fb9591da..e0e21f8990 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingRulesetContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingRulesetContainer.cs @@ -35,7 +35,8 @@ namespace osu.Game.Rulesets.UI.Scrolling /// private readonly SortedList controlPoints = new SortedList(Comparer.Default); - private IScrollingInfo scrollingInfo; + [Cached(Type = typeof(IScrollingInfo))] + protected readonly IScrollingInfo ScrollingInfo; [Cached(Type = typeof(IScrollAlgorithm))] private readonly IScrollAlgorithm algorithm; @@ -55,13 +56,14 @@ namespace osu.Game.Rulesets.UI.Scrolling algorithm = new ConstantScrollAlgorithm(); break; } + + ScrollingInfo = CreateScrollingInfo(); + ScrollingInfo.Direction.BindTo(Direction); } [BackgroundDependencyLoader] private void load() { - scrollingInfo.Direction.BindTo(Direction); - // Calculate default multiplier control points var lastTimingPoint = new TimingControlPoint(); var lastDifficultyPoint = new DifficultyControlPoint(); @@ -107,19 +109,9 @@ namespace osu.Game.Rulesets.UI.Scrolling controlPoints.Add(new MultiplierControlPoint { Velocity = Beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier }); } - protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) - { - var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); + protected virtual IScrollingInfo CreateScrollingInfo() => new LocalScrollingInfo(); - if ((scrollingInfo = dependencies.Get()) == null) - dependencies.CacheAs(scrollingInfo = CreateScrollingInfo()); - - return dependencies; - } - - protected virtual IScrollingInfo CreateScrollingInfo() => new ScrollingInfo(); - - private class ScrollingInfo : IScrollingInfo + private class LocalScrollingInfo : IScrollingInfo { public IBindable Direction { get; } = new Bindable(); } From e7969ecec7eb632414665380d752e993fa2180e7 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 7 Nov 2018 16:51:28 +0900 Subject: [PATCH 135/155] Move ScrollAlgorithm inside IScrollingInfo --- .../Edit/ManiaHitObjectComposer.cs | 2 -- .../Rulesets/UI/Scrolling/IScrollingInfo.cs | 6 +++++ .../Scrolling/ScrollingHitObjectContainer.cs | 20 +++++++--------- .../UI/Scrolling/ScrollingRulesetContainer.cs | 23 +++++++++---------- .../Tests/Visual/ScrollingTestContainer.cs | 10 ++++---- 5 files changed, 30 insertions(+), 31 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs index 837f940a62..3531b81e68 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs @@ -10,10 +10,8 @@ using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables; using System.Collections.Generic; using osu.Framework.Allocation; -using osu.Framework.Configuration; using osu.Game.Rulesets.Mania.Edit.Blueprints; using osu.Game.Rulesets.UI; -using osu.Game.Rulesets.UI.Scrolling; namespace osu.Game.Rulesets.Mania.Edit { diff --git a/osu.Game/Rulesets/UI/Scrolling/IScrollingInfo.cs b/osu.Game/Rulesets/UI/Scrolling/IScrollingInfo.cs index 151c6f01e2..eefaa80c81 100644 --- a/osu.Game/Rulesets/UI/Scrolling/IScrollingInfo.cs +++ b/osu.Game/Rulesets/UI/Scrolling/IScrollingInfo.cs @@ -3,6 +3,7 @@ using osu.Framework.Configuration; using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.UI.Scrolling.Algorithms; namespace osu.Game.Rulesets.UI.Scrolling { @@ -12,5 +13,10 @@ namespace osu.Game.Rulesets.UI.Scrolling /// The direction s should scroll in. /// IBindable Direction { get; } + + /// + /// The algorithm which controls positions and sizes. + /// + IScrollAlgorithm Algorithm { get; } } } diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index fda3a4cdc5..2cffa997c8 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -7,7 +7,6 @@ using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Types; -using osu.Game.Rulesets.UI.Scrolling.Algorithms; namespace osu.Game.Rulesets.UI.Scrolling { @@ -24,9 +23,6 @@ namespace osu.Game.Rulesets.UI.Scrolling private readonly IBindable direction = new Bindable(); - [Resolved] - private IScrollAlgorithm algorithm { get; set; } - [Resolved] private IScrollingInfo scrollingInfo { get; set; } @@ -87,7 +83,7 @@ namespace osu.Game.Rulesets.UI.Scrolling break; } - algorithm.Reset(); + scrollingInfo.Algorithm.Reset(); foreach (var obj in Objects) computeInitialStateRecursive(obj); @@ -97,7 +93,7 @@ namespace osu.Game.Rulesets.UI.Scrolling private void computeInitialStateRecursive(DrawableHitObject hitObject) { - hitObject.LifetimeStart = algorithm.GetDisplayStartTime(hitObject.HitObject.StartTime, TimeRange); + hitObject.LifetimeStart = scrollingInfo.Algorithm.GetDisplayStartTime(hitObject.HitObject.StartTime, TimeRange); if (hitObject.HitObject is IHasEndTime endTime) { @@ -105,11 +101,11 @@ namespace osu.Game.Rulesets.UI.Scrolling { case ScrollingDirection.Up: case ScrollingDirection.Down: - hitObject.Height = algorithm.GetLength(hitObject.HitObject.StartTime, endTime.EndTime, TimeRange, scrollLength); + hitObject.Height = scrollingInfo.Algorithm.GetLength(hitObject.HitObject.StartTime, endTime.EndTime, TimeRange, scrollLength); break; case ScrollingDirection.Left: case ScrollingDirection.Right: - hitObject.Width = algorithm.GetLength(hitObject.HitObject.StartTime, endTime.EndTime, TimeRange, scrollLength); + hitObject.Width = scrollingInfo.Algorithm.GetLength(hitObject.HitObject.StartTime, endTime.EndTime, TimeRange, scrollLength); break; } } @@ -137,16 +133,16 @@ namespace osu.Game.Rulesets.UI.Scrolling switch (direction.Value) { case ScrollingDirection.Up: - hitObject.Y = algorithm.PositionAt(hitObject.HitObject.StartTime, currentTime, TimeRange, scrollLength); + hitObject.Y = scrollingInfo.Algorithm.PositionAt(hitObject.HitObject.StartTime, currentTime, TimeRange, scrollLength); break; case ScrollingDirection.Down: - hitObject.Y = -algorithm.PositionAt(hitObject.HitObject.StartTime, currentTime, TimeRange, scrollLength); + hitObject.Y = -scrollingInfo.Algorithm.PositionAt(hitObject.HitObject.StartTime, currentTime, TimeRange, scrollLength); break; case ScrollingDirection.Left: - hitObject.X = algorithm.PositionAt(hitObject.HitObject.StartTime, currentTime, TimeRange, scrollLength); + hitObject.X = scrollingInfo.Algorithm.PositionAt(hitObject.HitObject.StartTime, currentTime, TimeRange, scrollLength); break; case ScrollingDirection.Right: - hitObject.X = -algorithm.PositionAt(hitObject.HitObject.StartTime, currentTime, TimeRange, scrollLength); + hitObject.X = -scrollingInfo.Algorithm.PositionAt(hitObject.HitObject.StartTime, currentTime, TimeRange, scrollLength); break; } } diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingRulesetContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingRulesetContainer.cs index e0e21f8990..d85992eefd 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingRulesetContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingRulesetContainer.cs @@ -35,30 +35,29 @@ namespace osu.Game.Rulesets.UI.Scrolling /// private readonly SortedList controlPoints = new SortedList(Comparer.Default); - [Cached(Type = typeof(IScrollingInfo))] - protected readonly IScrollingInfo ScrollingInfo; + protected IScrollingInfo ScrollingInfo => scrollingInfo; - [Cached(Type = typeof(IScrollAlgorithm))] - private readonly IScrollAlgorithm algorithm; + [Cached(Type = typeof(IScrollingInfo))] + private readonly LocalScrollingInfo scrollingInfo; protected ScrollingRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) : base(ruleset, beatmap) { + scrollingInfo = new LocalScrollingInfo(); + scrollingInfo.Direction.BindTo(Direction); + switch (ScrollAlgorithm) { case ScrollAlgorithm.Sequential: - algorithm = new SequentialScrollAlgorithm(controlPoints); + scrollingInfo.Algorithm = new SequentialScrollAlgorithm(controlPoints); break; case ScrollAlgorithm.Overlapping: - algorithm = new OverlappingScrollAlgorithm(controlPoints); + scrollingInfo.Algorithm = new OverlappingScrollAlgorithm(controlPoints); break; case ScrollAlgorithm.Constant: - algorithm = new ConstantScrollAlgorithm(); + scrollingInfo.Algorithm = new ConstantScrollAlgorithm(); break; } - - ScrollingInfo = CreateScrollingInfo(); - ScrollingInfo.Direction.BindTo(Direction); } [BackgroundDependencyLoader] @@ -109,11 +108,11 @@ namespace osu.Game.Rulesets.UI.Scrolling controlPoints.Add(new MultiplierControlPoint { Velocity = Beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier }); } - protected virtual IScrollingInfo CreateScrollingInfo() => new LocalScrollingInfo(); - private class LocalScrollingInfo : IScrollingInfo { public IBindable Direction { get; } = new Bindable(); + + public IScrollAlgorithm Algorithm { get; set; } } } } diff --git a/osu.Game/Tests/Visual/ScrollingTestContainer.cs b/osu.Game/Tests/Visual/ScrollingTestContainer.cs index b34dc87638..ad2d1abfad 100644 --- a/osu.Game/Tests/Visual/ScrollingTestContainer.cs +++ b/osu.Game/Tests/Visual/ScrollingTestContainer.cs @@ -18,16 +18,13 @@ namespace osu.Game.Tests.Visual /// public class ScrollingTestContainer : Container { - public SortedList ControlPoints => scrollAlgorithm.ControlPoints; + public SortedList ControlPoints => scrollingInfo.Algorithm.ControlPoints; - public ScrollAlgorithm ScrollAlgorithm { set => scrollAlgorithm.Algorithm = value; } + public ScrollAlgorithm ScrollAlgorithm { set => scrollingInfo.Algorithm.Algorithm = value; } [Cached(Type = typeof(IScrollingInfo))] private readonly TestScrollingInfo scrollingInfo = new TestScrollingInfo(); - [Cached(Type = typeof(IScrollAlgorithm))] - private readonly TestScrollAlgorithm scrollAlgorithm = new TestScrollAlgorithm(); - public ScrollingTestContainer(ScrollingDirection direction) { scrollingInfo.Direction.Value = direction; @@ -39,6 +36,9 @@ namespace osu.Game.Tests.Visual { public readonly Bindable Direction = new Bindable(); IBindable IScrollingInfo.Direction => Direction; + + public readonly TestScrollAlgorithm Algorithm = new TestScrollAlgorithm(); + IScrollAlgorithm IScrollingInfo.Algorithm => Algorithm; } private class TestScrollAlgorithm : IScrollAlgorithm From 10543cf1b6f75271e902297b4a81bff073ae5b55 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 7 Nov 2018 17:24:05 +0900 Subject: [PATCH 136/155] Move rest of ScrollingPlayfield into ScrollingRulesetContainer --- osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs | 4 -- .../UI/CatchRulesetContainer.cs | 3 + .../TestCaseColumn.cs | 2 +- .../TestCaseStage.cs | 3 +- osu.Game.Rulesets.Mania/UI/Column.cs | 10 +-- osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs | 9 --- .../UI/ManiaRulesetContainer.cs | 2 + osu.Game.Rulesets.Mania/UI/ManiaStage.cs | 2 - osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 4 -- .../UI/TaikoRulesetContainer.cs | 3 + .../Visual/TestCaseScrollingHitObjects.cs | 2 +- .../Rulesets/UI/Scrolling/IScrollingInfo.cs | 5 ++ .../Scrolling/ScrollingHitObjectContainer.cs | 30 ++++---- .../UI/Scrolling/ScrollingPlayfield.cs | 68 +------------------ .../UI/Scrolling/ScrollingRulesetContainer.cs | 65 +++++++++++++++++- .../Tests/Visual/ScrollingTestContainer.cs | 5 ++ 16 files changed, 104 insertions(+), 113 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs index 0782930f63..4d1d9d7e5d 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs @@ -20,8 +20,6 @@ namespace osu.Game.Rulesets.Catch.UI private readonly CatcherArea catcherArea; - protected override bool UserScrollSpeedAdjustment => false; - public CatchPlayfield(BeatmapDifficulty difficulty, Func> getVisualRepresentation) { Container explodingFruitContainer; @@ -50,8 +48,6 @@ namespace osu.Game.Rulesets.Catch.UI HitObjectContainer } }; - - VisibleTimeRange.Value = BeatmapDifficulty.DifficultyRange(difficulty.ApproachRate, 1800, 1200, 450); } public bool CheckIfWeCanCatch(CatchHitObject obj) => catcherArea.AttemptCatch(obj); diff --git a/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs b/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs index 31a6c74959..54e5d454a2 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs @@ -21,10 +21,13 @@ namespace osu.Game.Rulesets.Catch.UI { protected override ScrollAlgorithm ScrollAlgorithm => ScrollAlgorithm.Constant; + protected override bool UserScrollSpeedAdjustment => false; + public CatchRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) : base(ruleset, beatmap) { Direction.Value = ScrollingDirection.Down; + TimeRange.Value = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450); } public override ScoreProcessor CreateScoreProcessor() => new CatchScoreProcessor(this); diff --git a/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs b/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs index 048ebe39e8..d044b48553 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestCaseColumn.cs @@ -94,7 +94,6 @@ namespace osu.Game.Rulesets.Mania.Tests Height = 0.85f, AccentColour = Color4.OrangeRed, Action = { Value = action }, - VisibleTimeRange = { Value = 2000 } }; columns.Add(column); @@ -105,6 +104,7 @@ namespace osu.Game.Rulesets.Mania.Tests Origin = Anchor.Centre, AutoSizeAxes = Axes.X, RelativeSizeAxes = Axes.Y, + TimeRange = 2000, Child = column }; } diff --git a/osu.Game.Rulesets.Mania.Tests/TestCaseStage.cs b/osu.Game.Rulesets.Mania.Tests/TestCaseStage.cs index a7e3c7da41..02d5b13100 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestCaseStage.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestCaseStage.cs @@ -123,7 +123,7 @@ namespace osu.Game.Rulesets.Mania.Tests { var specialAction = ManiaAction.Special1; - var stage = new ManiaStage(0, new StageDefinition { Columns = 2 }, ref action, ref specialAction) { VisibleTimeRange = { Value = 2000 } }; + var stage = new ManiaStage(0, new StageDefinition { Columns = 2 }, ref action, ref specialAction); stages.Add(stage); return new ScrollingTestContainer(direction) @@ -132,6 +132,7 @@ namespace osu.Game.Rulesets.Mania.Tests Origin = Anchor.Centre, RelativeSizeAxes = Axes.Y, AutoSizeAxes = Axes.X, + TimeRange = 2000, Child = stage }; } diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs index 547e0abae8..576af6d93a 100644 --- a/osu.Game.Rulesets.Mania/UI/Column.cs +++ b/osu.Game.Rulesets.Mania/UI/Column.cs @@ -1,12 +1,12 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.Linq; using OpenTK.Graphics; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Rulesets.Objects.Drawables; -using System.Linq; using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Input.Bindings; @@ -134,7 +134,7 @@ namespace osu.Game.Rulesets.Mania.UI hitObject.AccentColour = AccentColour; hitObject.OnNewResult += OnNewResult; - HitObjects.Add(hitObject); + HitObjectContainer.Add(hitObject); } internal void OnNewResult(DrawableHitObject judgedObject, JudgementResult result) @@ -154,10 +154,10 @@ namespace osu.Game.Rulesets.Mania.UI return false; var nextObject = - HitObjects.AliveObjects.FirstOrDefault(h => h.HitObject.StartTime > Time.Current) ?? + HitObjectContainer.AliveObjects.FirstOrDefault(h => h.HitObject.StartTime > Time.Current) ?? // fallback to non-alive objects to find next off-screen object - HitObjects.Objects.FirstOrDefault(h => h.HitObject.StartTime > Time.Current) ?? - HitObjects.Objects.LastOrDefault(); + HitObjectContainer.Objects.FirstOrDefault(h => h.HitObject.StartTime > Time.Current) ?? + HitObjectContainer.Objects.LastOrDefault(); nextObject?.PlaySamples(); diff --git a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs index dc965ea7f4..c59917056d 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs @@ -1,13 +1,11 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using System; using System.Collections.Generic; using osu.Game.Rulesets.Mania.Beatmaps; -using osu.Game.Rulesets.Mania.Configuration; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.UI.Scrolling; @@ -42,7 +40,6 @@ namespace osu.Game.Rulesets.Mania.UI for (int i = 0; i < stageDefinitions.Count; i++) { var newStage = new ManiaStage(firstColumnIndex, stageDefinitions[i], ref normalColumnAction, ref specialColumnAction); - newStage.VisibleTimeRange.BindTo(VisibleTimeRange); playfieldGrid.Content[0][i] = newStage; @@ -69,11 +66,5 @@ namespace osu.Game.Rulesets.Mania.UI return null; } - - [BackgroundDependencyLoader] - private void load(ManiaConfigManager maniaConfig) - { - maniaConfig.BindWith(ManiaSetting.ScrollTime, VisibleTimeRange); - } } } diff --git a/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs b/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs index 34182b7219..321dd4e1cb 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs @@ -76,6 +76,8 @@ namespace osu.Game.Rulesets.Mania.UI Config.BindWith(ManiaSetting.ScrollDirection, configDirection); configDirection.BindValueChanged(v => Direction.Value = (ScrollingDirection)v, true); + + Config.BindWith(ManiaSetting.ScrollTime, TimeRange); } protected override Playfield CreatePlayfield() => new ManiaPlayfield(Beatmap.Stages) diff --git a/osu.Game.Rulesets.Mania/UI/ManiaStage.cs b/osu.Game.Rulesets.Mania/UI/ManiaStage.cs index 48caf91d7b..19e930f530 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaStage.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaStage.cs @@ -144,8 +144,6 @@ namespace osu.Game.Rulesets.Mania.UI public void AddColumn(Column c) { - c.VisibleTimeRange.BindTo(VisibleTimeRange); - topLevelContainer.Add(c.TopLevelContainer.CreateProxy()); columnFlow.Add(c); AddNested(c); diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 97fdbc5b7a..561afb0180 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -38,8 +38,6 @@ namespace osu.Game.Rulesets.Taiko.UI /// private const float left_area_size = 240; - protected override bool UserScrollSpeedAdjustment => false; - private readonly Container hitExplosionContainer; private readonly Container kiaiExplosionContainer; private readonly JudgementContainer judgementContainer; @@ -195,8 +193,6 @@ namespace osu.Game.Rulesets.Taiko.UI } } }; - - VisibleTimeRange.Value = 7000; } [BackgroundDependencyLoader] diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs b/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs index afec8094ad..0584d286f5 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs @@ -24,10 +24,13 @@ namespace osu.Game.Rulesets.Taiko.UI { protected override ScrollAlgorithm ScrollAlgorithm => ScrollAlgorithm.Overlapping; + protected override bool UserScrollSpeedAdjustment => false; + public TaikoRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) : base(ruleset, beatmap) { Direction.Value = ScrollingDirection.Left; + TimeRange.Value = 7000; } [BackgroundDependencyLoader] diff --git a/osu.Game.Tests/Visual/TestCaseScrollingHitObjects.cs b/osu.Game.Tests/Visual/TestCaseScrollingHitObjects.cs index ecc7b3ed7a..91a8d26324 100644 --- a/osu.Game.Tests/Visual/TestCaseScrollingHitObjects.cs +++ b/osu.Game.Tests/Visual/TestCaseScrollingHitObjects.cs @@ -66,7 +66,7 @@ namespace osu.Game.Tests.Visual AddStep("Overlapping scroll", () => setScrollAlgorithm(ScrollAlgorithm.Overlapping)); AddStep("Sequential scroll", () => setScrollAlgorithm(ScrollAlgorithm.Sequential)); - AddSliderStep("Time range", 100, 10000, 5000, v => playfields.ForEach(p => p.VisibleTimeRange.Value = v)); + AddSliderStep("Time range", 100, 10000, 5000, v => scrollContainers.ForEach(c => c.TimeRange = v)); AddStep("Add control point", () => addControlPoint(Time.Current + 5000)); } diff --git a/osu.Game/Rulesets/UI/Scrolling/IScrollingInfo.cs b/osu.Game/Rulesets/UI/Scrolling/IScrollingInfo.cs index eefaa80c81..21cbd855a9 100644 --- a/osu.Game/Rulesets/UI/Scrolling/IScrollingInfo.cs +++ b/osu.Game/Rulesets/UI/Scrolling/IScrollingInfo.cs @@ -14,6 +14,11 @@ namespace osu.Game.Rulesets.UI.Scrolling /// IBindable Direction { get; } + /// + /// + /// + IBindable TimeRange { get; } + /// /// The algorithm which controls positions and sizes. /// diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index 2cffa997c8..00642b3d41 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -12,14 +12,7 @@ namespace osu.Game.Rulesets.UI.Scrolling { public class ScrollingHitObjectContainer : HitObjectContainer { - /// - /// The duration required to scroll through one length of the before any control point adjustments. - /// - public readonly BindableDouble TimeRange = new BindableDouble - { - MinValue = 0, - MaxValue = double.MaxValue - }; + private readonly IBindable timeRange = new BindableDouble(); private readonly IBindable direction = new Bindable(); @@ -31,15 +24,16 @@ namespace osu.Game.Rulesets.UI.Scrolling public ScrollingHitObjectContainer() { RelativeSizeAxes = Axes.Both; - - TimeRange.ValueChanged += _ => initialStateCache.Invalidate(); - direction.ValueChanged += _ => initialStateCache.Invalidate(); } [BackgroundDependencyLoader] private void load() { direction.BindTo(scrollingInfo.Direction); + timeRange.BindTo(scrollingInfo.TimeRange); + + direction.ValueChanged += _ => initialStateCache.Invalidate(); + timeRange.ValueChanged += _ => initialStateCache.Invalidate(); } public override void Add(DrawableHitObject hitObject) @@ -93,7 +87,7 @@ namespace osu.Game.Rulesets.UI.Scrolling private void computeInitialStateRecursive(DrawableHitObject hitObject) { - hitObject.LifetimeStart = scrollingInfo.Algorithm.GetDisplayStartTime(hitObject.HitObject.StartTime, TimeRange); + hitObject.LifetimeStart = scrollingInfo.Algorithm.GetDisplayStartTime(hitObject.HitObject.StartTime, timeRange.Value); if (hitObject.HitObject is IHasEndTime endTime) { @@ -101,11 +95,11 @@ namespace osu.Game.Rulesets.UI.Scrolling { case ScrollingDirection.Up: case ScrollingDirection.Down: - hitObject.Height = scrollingInfo.Algorithm.GetLength(hitObject.HitObject.StartTime, endTime.EndTime, TimeRange, scrollLength); + hitObject.Height = scrollingInfo.Algorithm.GetLength(hitObject.HitObject.StartTime, endTime.EndTime, timeRange.Value, scrollLength); break; case ScrollingDirection.Left: case ScrollingDirection.Right: - hitObject.Width = scrollingInfo.Algorithm.GetLength(hitObject.HitObject.StartTime, endTime.EndTime, TimeRange, scrollLength); + hitObject.Width = scrollingInfo.Algorithm.GetLength(hitObject.HitObject.StartTime, endTime.EndTime, timeRange.Value, scrollLength); break; } } @@ -133,16 +127,16 @@ namespace osu.Game.Rulesets.UI.Scrolling switch (direction.Value) { case ScrollingDirection.Up: - hitObject.Y = scrollingInfo.Algorithm.PositionAt(hitObject.HitObject.StartTime, currentTime, TimeRange, scrollLength); + hitObject.Y = scrollingInfo.Algorithm.PositionAt(hitObject.HitObject.StartTime, currentTime, timeRange.Value, scrollLength); break; case ScrollingDirection.Down: - hitObject.Y = -scrollingInfo.Algorithm.PositionAt(hitObject.HitObject.StartTime, currentTime, TimeRange, scrollLength); + hitObject.Y = -scrollingInfo.Algorithm.PositionAt(hitObject.HitObject.StartTime, currentTime, timeRange.Value, scrollLength); break; case ScrollingDirection.Left: - hitObject.X = scrollingInfo.Algorithm.PositionAt(hitObject.HitObject.StartTime, currentTime, TimeRange, scrollLength); + hitObject.X = scrollingInfo.Algorithm.PositionAt(hitObject.HitObject.StartTime, currentTime, timeRange.Value, scrollLength); break; case ScrollingDirection.Right: - hitObject.X = -scrollingInfo.Algorithm.PositionAt(hitObject.HitObject.StartTime, currentTime, TimeRange, scrollLength); + hitObject.X = -scrollingInfo.Algorithm.PositionAt(hitObject.HitObject.StartTime, currentTime, timeRange.Value, scrollLength); break; } } diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs index c3b358825c..0eb67b8bb1 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs @@ -3,9 +3,6 @@ using osu.Framework.Allocation; using osu.Framework.Configuration; -using osu.Framework.Graphics; -using osu.Framework.Input.Bindings; -using osu.Game.Input.Bindings; using osu.Game.Rulesets.Objects.Drawables; namespace osu.Game.Rulesets.UI.Scrolling @@ -13,52 +10,10 @@ namespace osu.Game.Rulesets.UI.Scrolling /// /// A type of specialized towards scrolling s. /// - public abstract class ScrollingPlayfield : Playfield, IKeyBindingHandler + public abstract class ScrollingPlayfield : Playfield { - /// - /// The default span of time visible by the length of the scrolling axes. - /// This is clamped between and . - /// - private const double time_span_default = 1500; - - /// - /// The minimum span of time that may be visible by the length of the scrolling axes. - /// - private const double time_span_min = 50; - - /// - /// The maximum span of time that may be visible by the length of the scrolling axes. - /// - private const double time_span_max = 10000; - - /// - /// The step increase/decrease of the span of time visible by the length of the scrolling axes. - /// - private const double time_span_step = 200; - - /// - /// The span of time that is visible by the length of the scrolling axes. - /// For example, only hit objects with start time less than or equal to 1000 will be visible with = 1000. - /// - public readonly BindableDouble VisibleTimeRange = new BindableDouble(time_span_default) - { - Default = time_span_default, - MinValue = time_span_min, - MaxValue = time_span_max - }; - - /// - /// Whether the player can change . - /// - protected virtual bool UserScrollSpeedAdjustment => true; - protected readonly IBindable Direction = new Bindable(); - /// - /// The container that contains the s. - /// - public new ScrollingHitObjectContainer HitObjects => (ScrollingHitObjectContainer)HitObjectContainer; - [Resolved] private IScrollingInfo scrollingInfo { get; set; } @@ -66,29 +21,8 @@ namespace osu.Game.Rulesets.UI.Scrolling private void load() { Direction.BindTo(scrollingInfo.Direction); - HitObjects.TimeRange.BindTo(VisibleTimeRange); } - public bool OnPressed(GlobalAction action) - { - if (!UserScrollSpeedAdjustment) - return false; - - switch (action) - { - case GlobalAction.IncreaseScrollSpeed: - this.TransformBindableTo(VisibleTimeRange, VisibleTimeRange - time_span_step, 200, Easing.OutQuint); - return true; - case GlobalAction.DecreaseScrollSpeed: - this.TransformBindableTo(VisibleTimeRange, VisibleTimeRange + time_span_step, 200, Easing.OutQuint); - return true; - } - - return false; - } - - public bool OnReleased(GlobalAction action) => false; - protected sealed override HitObjectContainer CreateHitObjectContainer() => new ScrollingHitObjectContainer(); } } diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingRulesetContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingRulesetContainer.cs index d85992eefd..4cf6812be0 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingRulesetContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingRulesetContainer.cs @@ -5,10 +5,13 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Configuration; +using osu.Framework.Graphics; +using osu.Framework.Input.Bindings; using osu.Framework.Lists; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Configuration; +using osu.Game.Input.Bindings; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Timing; @@ -20,14 +23,51 @@ namespace osu.Game.Rulesets.UI.Scrolling /// A type of that supports a . /// s inside this will scroll within the playfield. /// - public abstract class ScrollingRulesetContainer : RulesetContainer + public abstract class ScrollingRulesetContainer : RulesetContainer, IKeyBindingHandler where TObject : HitObject where TPlayfield : ScrollingPlayfield { + /// + /// The default span of time visible by the length of the scrolling axes. + /// This is clamped between and . + /// + private const double time_span_default = 1500; + + /// + /// The minimum span of time that may be visible by the length of the scrolling axes. + /// + private const double time_span_min = 50; + + /// + /// The maximum span of time that may be visible by the length of the scrolling axes. + /// + private const double time_span_max = 10000; + + /// + /// The step increase/decrease of the span of time visible by the length of the scrolling axes. + /// + private const double time_span_step = 200; + protected readonly Bindable Direction = new Bindable(); + /// + /// The span of time that is visible by the length of the scrolling axes. + /// For example, only hit objects with start time less than or equal to 1000 will be visible with = 1000. + /// + protected readonly BindableDouble TimeRange = new BindableDouble(time_span_default) + { + Default = time_span_default, + MinValue = time_span_min, + MaxValue = time_span_max + }; + protected virtual ScrollAlgorithm ScrollAlgorithm => ScrollAlgorithm.Sequential; + /// + /// Whether the player can change . + /// + protected virtual bool UserScrollSpeedAdjustment => true; + /// /// Provides the default s that adjust the scrolling rate of s /// inside this . @@ -45,6 +85,7 @@ namespace osu.Game.Rulesets.UI.Scrolling { scrollingInfo = new LocalScrollingInfo(); scrollingInfo.Direction.BindTo(Direction); + scrollingInfo.TimeRange.BindTo(TimeRange); switch (ScrollAlgorithm) { @@ -108,10 +149,32 @@ namespace osu.Game.Rulesets.UI.Scrolling controlPoints.Add(new MultiplierControlPoint { Velocity = Beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier }); } + public bool OnPressed(GlobalAction action) + { + if (!UserScrollSpeedAdjustment) + return false; + + switch (action) + { + case GlobalAction.IncreaseScrollSpeed: + this.TransformBindableTo(TimeRange, TimeRange - time_span_step, 200, Easing.OutQuint); + return true; + case GlobalAction.DecreaseScrollSpeed: + this.TransformBindableTo(TimeRange, TimeRange + time_span_step, 200, Easing.OutQuint); + return true; + } + + return false; + } + + public bool OnReleased(GlobalAction action) => false; + private class LocalScrollingInfo : IScrollingInfo { public IBindable Direction { get; } = new Bindable(); + public IBindable TimeRange { get; } = new BindableDouble(); + public IScrollAlgorithm Algorithm { get; set; } } } diff --git a/osu.Game/Tests/Visual/ScrollingTestContainer.cs b/osu.Game/Tests/Visual/ScrollingTestContainer.cs index ad2d1abfad..c75653548b 100644 --- a/osu.Game/Tests/Visual/ScrollingTestContainer.cs +++ b/osu.Game/Tests/Visual/ScrollingTestContainer.cs @@ -22,6 +22,8 @@ namespace osu.Game.Tests.Visual public ScrollAlgorithm ScrollAlgorithm { set => scrollingInfo.Algorithm.Algorithm = value; } + public double TimeRange { set => scrollingInfo.TimeRange.Value = value; } + [Cached(Type = typeof(IScrollingInfo))] private readonly TestScrollingInfo scrollingInfo = new TestScrollingInfo(); @@ -37,6 +39,9 @@ namespace osu.Game.Tests.Visual public readonly Bindable Direction = new Bindable(); IBindable IScrollingInfo.Direction => Direction; + public readonly Bindable TimeRange = new Bindable(1000) { Value = 1000 }; + IBindable IScrollingInfo.TimeRange => TimeRange; + public readonly TestScrollAlgorithm Algorithm = new TestScrollAlgorithm(); IScrollAlgorithm IScrollingInfo.Algorithm => Algorithm; } From d8e7ad8241c15a84e11af317a9eaaba60551ade3 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 12 Nov 2018 17:36:19 +0900 Subject: [PATCH 137/155] Fix post-rebase issues --- osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs | 2 +- osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs | 2 +- osu.Game.Tests/Visual/TestCaseScrollingHitObjects.cs | 8 ++++---- .../UI/Scrolling/ScrollingRulesetContainer.cs | 10 +++++----- osu.Game/Tests/Visual/ScrollingTestContainer.cs | 12 ++++++------ 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs b/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs index 54e5d454a2..ef1bb7767f 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Catch.UI { public class CatchRulesetContainer : ScrollingRulesetContainer { - protected override ScrollAlgorithm ScrollAlgorithm => ScrollAlgorithm.Constant; + protected override ScrollVisualisationMethod VisualisationMethod => ScrollVisualisationMethod.Constant; protected override bool UserScrollSpeedAdjustment => false; diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs b/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs index 0584d286f5..99c83c243b 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Taiko.UI { public class TaikoRulesetContainer : ScrollingRulesetContainer { - protected override ScrollAlgorithm ScrollAlgorithm => ScrollAlgorithm.Overlapping; + protected override ScrollVisualisationMethod VisualisationMethod => ScrollVisualisationMethod.Overlapping; protected override bool UserScrollSpeedAdjustment => false; diff --git a/osu.Game.Tests/Visual/TestCaseScrollingHitObjects.cs b/osu.Game.Tests/Visual/TestCaseScrollingHitObjects.cs index 91a8d26324..a486abb9e8 100644 --- a/osu.Game.Tests/Visual/TestCaseScrollingHitObjects.cs +++ b/osu.Game.Tests/Visual/TestCaseScrollingHitObjects.cs @@ -62,9 +62,9 @@ namespace osu.Game.Tests.Visual } }); - AddStep("Constant scroll", () => setScrollAlgorithm(ScrollAlgorithm.Constant)); - AddStep("Overlapping scroll", () => setScrollAlgorithm(ScrollAlgorithm.Overlapping)); - AddStep("Sequential scroll", () => setScrollAlgorithm(ScrollAlgorithm.Sequential)); + AddStep("Constant scroll", () => setScrollAlgorithm(ScrollVisualisationMethod.Constant)); + AddStep("Overlapping scroll", () => setScrollAlgorithm(ScrollVisualisationMethod.Overlapping)); + AddStep("Sequential scroll", () => setScrollAlgorithm(ScrollVisualisationMethod.Sequential)); AddSliderStep("Time range", 100, 10000, 5000, v => scrollContainers.ForEach(c => c.TimeRange = v)); AddStep("Add control point", () => addControlPoint(Time.Current + 5000)); @@ -136,7 +136,7 @@ namespace osu.Game.Tests.Visual } } - private void setScrollAlgorithm(ScrollAlgorithm algorithm) => scrollContainers.ForEach(c => c.ScrollAlgorithm = algorithm); + private void setScrollAlgorithm(ScrollVisualisationMethod algorithm) => scrollContainers.ForEach(c => c.ScrollAlgorithm = algorithm); private class TestPlayfield : ScrollingPlayfield { diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingRulesetContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingRulesetContainer.cs index 4cf6812be0..83b9e31a46 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingRulesetContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingRulesetContainer.cs @@ -61,7 +61,7 @@ namespace osu.Game.Rulesets.UI.Scrolling MaxValue = time_span_max }; - protected virtual ScrollAlgorithm ScrollAlgorithm => ScrollAlgorithm.Sequential; + protected virtual ScrollVisualisationMethod VisualisationMethod => ScrollVisualisationMethod.Sequential; /// /// Whether the player can change . @@ -87,15 +87,15 @@ namespace osu.Game.Rulesets.UI.Scrolling scrollingInfo.Direction.BindTo(Direction); scrollingInfo.TimeRange.BindTo(TimeRange); - switch (ScrollAlgorithm) + switch (VisualisationMethod) { - case ScrollAlgorithm.Sequential: + case ScrollVisualisationMethod.Sequential: scrollingInfo.Algorithm = new SequentialScrollAlgorithm(controlPoints); break; - case ScrollAlgorithm.Overlapping: + case ScrollVisualisationMethod.Overlapping: scrollingInfo.Algorithm = new OverlappingScrollAlgorithm(controlPoints); break; - case ScrollAlgorithm.Constant: + case ScrollVisualisationMethod.Constant: scrollingInfo.Algorithm = new ConstantScrollAlgorithm(); break; } diff --git a/osu.Game/Tests/Visual/ScrollingTestContainer.cs b/osu.Game/Tests/Visual/ScrollingTestContainer.cs index c75653548b..18b29345c1 100644 --- a/osu.Game/Tests/Visual/ScrollingTestContainer.cs +++ b/osu.Game/Tests/Visual/ScrollingTestContainer.cs @@ -20,7 +20,7 @@ namespace osu.Game.Tests.Visual { public SortedList ControlPoints => scrollingInfo.Algorithm.ControlPoints; - public ScrollAlgorithm ScrollAlgorithm { set => scrollingInfo.Algorithm.Algorithm = value; } + public ScrollVisualisationMethod ScrollAlgorithm { set => scrollingInfo.Algorithm.Algorithm = value; } public double TimeRange { set => scrollingInfo.TimeRange.Value = value; } @@ -54,22 +54,22 @@ namespace osu.Game.Tests.Visual public TestScrollAlgorithm() { - Algorithm = ScrollAlgorithm.Constant; + Algorithm = ScrollVisualisationMethod.Constant; } - public ScrollAlgorithm Algorithm + public ScrollVisualisationMethod Algorithm { set { switch (value) { - case ScrollAlgorithm.Constant: + case ScrollVisualisationMethod.Constant: implementation = new ConstantScrollAlgorithm(); break; - case ScrollAlgorithm.Overlapping: + case ScrollVisualisationMethod.Overlapping: implementation = new OverlappingScrollAlgorithm(ControlPoints); break; - case ScrollAlgorithm.Sequential: + case ScrollVisualisationMethod.Sequential: implementation = new SequentialScrollAlgorithm(ControlPoints); break; } From 2e0e1befe94568add2e4505ce204a925b141fd8f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 6 Nov 2018 16:58:10 +0900 Subject: [PATCH 138/155] Add selection mask testcases # Conflicts: # osu.Game/Tests/Visual/SelectionBlueprintTestCase.cs --- .../TestCaseHoldNoteSelectionBlueprint.cs | 57 +++++++++++++++++++ .../TestCaseNoteSelectionBlueprint.cs | 41 +++++++++++++ .../Visual/SelectionBlueprintTestCase.cs | 5 +- 3 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Rulesets.Mania.Tests/TestCaseHoldNoteSelectionBlueprint.cs create mode 100644 osu.Game.Rulesets.Mania.Tests/TestCaseNoteSelectionBlueprint.cs diff --git a/osu.Game.Rulesets.Mania.Tests/TestCaseHoldNoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania.Tests/TestCaseHoldNoteSelectionBlueprint.cs new file mode 100644 index 0000000000..993f7520e8 --- /dev/null +++ b/osu.Game.Rulesets.Mania.Tests/TestCaseHoldNoteSelectionBlueprint.cs @@ -0,0 +1,57 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Graphics; +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Mania.Edit.Blueprints; +using osu.Game.Rulesets.Mania.Objects; +using osu.Game.Rulesets.Mania.Objects.Drawables; +using osu.Game.Rulesets.UI.Scrolling; +using osu.Game.Tests.Visual; + +namespace osu.Game.Rulesets.Mania.Tests +{ + public class TestCaseHoldNoteSelectionBlueprint : SelectionBlueprintTestCase + { + private readonly DrawableHoldNote drawableObject; + + protected override Container Content => content ?? base.Content; + private readonly Container content; + + public TestCaseHoldNoteSelectionBlueprint() + { + var holdNote = new HoldNote { Column = 0, Duration = 1000 }; + holdNote.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + + base.Content.Child = content = new ScrollingTestContainer(ScrollingDirection.Down) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Y, + Width = 50, + Child = drawableObject = new DrawableHoldNote(holdNote) + { + Height = 300, + AccentColour = OsuColour.Gray(0.3f) + } + }; + } + + protected override void Update() + { + base.Update(); + + foreach (var nested in drawableObject.NestedHitObjects) + { + double finalPosition = (nested.HitObject.StartTime - drawableObject.HitObject.StartTime) / drawableObject.HitObject.Duration; + nested.Y = (float)(-finalPosition * content.DrawHeight); + } + } + + protected override SelectionBlueprint CreateBlueprint() => new HoldNoteSelectionBlueprint(drawableObject); + } +} diff --git a/osu.Game.Rulesets.Mania.Tests/TestCaseNoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania.Tests/TestCaseNoteSelectionBlueprint.cs new file mode 100644 index 0000000000..fd26b93e5c --- /dev/null +++ b/osu.Game.Rulesets.Mania.Tests/TestCaseNoteSelectionBlueprint.cs @@ -0,0 +1,41 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Mania.Edit.Blueprints; +using osu.Game.Rulesets.Mania.Objects; +using osu.Game.Rulesets.Mania.Objects.Drawables; +using osu.Game.Rulesets.UI.Scrolling; +using osu.Game.Tests.Visual; +using OpenTK; + +namespace osu.Game.Rulesets.Mania.Tests +{ + public class TestCaseNoteSelectionBlueprint : SelectionBlueprintTestCase + { + private readonly DrawableNote drawableObject; + + protected override Container Content => content ?? base.Content; + private readonly Container content; + + public TestCaseNoteSelectionBlueprint() + { + var note = new Note { Column = 0 }; + note.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + + base.Content.Child = content = new ScrollingTestContainer(ScrollingDirection.Down) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(50, 20), + Child = drawableObject = new DrawableNote(note) + }; + } + + protected override SelectionBlueprint CreateBlueprint() => new NoteSelectionBlueprint(drawableObject); + } +} diff --git a/osu.Game/Tests/Visual/SelectionBlueprintTestCase.cs b/osu.Game/Tests/Visual/SelectionBlueprintTestCase.cs index b1df849a67..183bef7602 100644 --- a/osu.Game/Tests/Visual/SelectionBlueprintTestCase.cs +++ b/osu.Game/Tests/Visual/SelectionBlueprintTestCase.cs @@ -29,9 +29,12 @@ namespace osu.Game.Tests.Visual [BackgroundDependencyLoader] private void load() { - base.Content.Add(blueprint = CreateBlueprint()); + blueprint = CreateBlueprint(); + blueprint.Depth = float.MinValue; blueprint.SelectionRequested += (_, __) => blueprint.Select(); + Add(blueprint); + AddStep("Select", () => blueprint.Select()); AddStep("Deselect", () => blueprint.Deselect()); } From b9b20607af6e4947b3628ce97818cb0df24371ea Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 9 Nov 2018 19:55:48 +0900 Subject: [PATCH 139/155] Add IScrollAlgorithm.TimeAt() --- .../ScrollAlgorithms/ConstantScrollTest.cs | 54 +++++++++++++++ .../ScrollAlgorithms/OverlappingScrollTest.cs | 67 +++++++++++++++++++ .../ScrollAlgorithms/SequentialScrollTest.cs | 64 ++++++++++++++++++ .../Algorithms/ConstantScrollAlgorithm.cs | 3 + .../Scrolling/Algorithms/IScrollAlgorithm.cs | 10 +++ .../Algorithms/OverlappingScrollAlgorithm.cs | 28 ++++++++ .../Algorithms/SequentialScrollAlgorithm.cs | 30 +++++++++ 7 files changed, 256 insertions(+) create mode 100644 osu.Game.Tests/ScrollAlgorithms/ConstantScrollTest.cs create mode 100644 osu.Game.Tests/ScrollAlgorithms/OverlappingScrollTest.cs create mode 100644 osu.Game.Tests/ScrollAlgorithms/SequentialScrollTest.cs diff --git a/osu.Game.Tests/ScrollAlgorithms/ConstantScrollTest.cs b/osu.Game.Tests/ScrollAlgorithms/ConstantScrollTest.cs new file mode 100644 index 0000000000..5e01213a48 --- /dev/null +++ b/osu.Game.Tests/ScrollAlgorithms/ConstantScrollTest.cs @@ -0,0 +1,54 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using NUnit.Framework; +using osu.Game.Rulesets.UI.Scrolling.Algorithms; + +namespace osu.Game.Tests.ScrollAlgorithms +{ + [TestFixture] + public class ConstantScrollTest + { + private IScrollAlgorithm algorithm; + + [SetUp] + public void Setup() + { + algorithm = new ConstantScrollAlgorithm(); + } + + [Test] + public void TestDisplayStartTime() + { + Assert.AreEqual(-8000, algorithm.GetDisplayStartTime(2000, 10000)); + Assert.AreEqual(-3000, algorithm.GetDisplayStartTime(2000, 5000)); + Assert.AreEqual(2000, algorithm.GetDisplayStartTime(7000, 5000)); + Assert.AreEqual(7000, algorithm.GetDisplayStartTime(17000, 10000)); + } + + [Test] + public void TestLength() + { + Assert.AreEqual(1f / 5, algorithm.GetLength(0, 1000, 5000, 1)); + Assert.AreEqual(1f / 5, algorithm.GetLength(6000, 7000, 5000, 1)); + } + + [Test] + public void TestPosition() + { + Assert.AreEqual(1f / 5, algorithm.PositionAt(1000, 0, 5000, 1)); + Assert.AreEqual(1f / 5, algorithm.PositionAt(6000, 5000, 5000, 1)); + } + + [TestCase(1000)] + [TestCase(10000)] + [TestCase(15000)] + [TestCase(20000)] + [TestCase(25000)] + public void TestTime(double time) + { + Assert.AreEqual(time, algorithm.TimeAt(algorithm.PositionAt(time, 0, 5000, 1), 0, 5000, 1), 0.001); + Assert.AreEqual(time, algorithm.TimeAt(algorithm.PositionAt(time, 5000, 5000, 1), 5000, 5000, 1), 0.001); + } + } +} diff --git a/osu.Game.Tests/ScrollAlgorithms/OverlappingScrollTest.cs b/osu.Game.Tests/ScrollAlgorithms/OverlappingScrollTest.cs new file mode 100644 index 0000000000..c1a5a0f3c9 --- /dev/null +++ b/osu.Game.Tests/ScrollAlgorithms/OverlappingScrollTest.cs @@ -0,0 +1,67 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using NUnit.Framework; +using osu.Framework.Lists; +using osu.Game.Rulesets.Timing; +using osu.Game.Rulesets.UI.Scrolling.Algorithms; + +namespace osu.Game.Tests.ScrollAlgorithms +{ + [TestFixture] + public class OverlappingScrollTest + { + private IScrollAlgorithm algorithm; + + [SetUp] + public void Setup() + { + var controlPoints = new SortedList + { + new MultiplierControlPoint(0) { Velocity = 1 }, + new MultiplierControlPoint(10000) { Velocity = 2f }, + new MultiplierControlPoint(20000) { Velocity = 0.5f } + }; + + algorithm = new OverlappingScrollAlgorithm(controlPoints); + } + + [Test] + public void TestDisplayStartTime() + { + Assert.AreEqual(1000, algorithm.GetDisplayStartTime(2000, 1000)); // Like constant + Assert.AreEqual(10000, algorithm.GetDisplayStartTime(10500, 1000)); // 10500 - (1000 * 0.5) + Assert.AreEqual(20000, algorithm.GetDisplayStartTime(22000, 1000)); // 23000 - (1000 / 0.5) + } + + [Test] + public void TestLength() + { + Assert.AreEqual(1f / 5, algorithm.GetLength(0, 1000, 5000, 1)); // Like constant + Assert.AreEqual(1f / 5, algorithm.GetLength(10000, 10500, 5000, 1)); // (10500 - 10000) / 0.5 / 5000 + Assert.AreEqual(1f / 5, algorithm.GetLength(20000, 22000, 5000, 1)); // (22000 - 20000) * 0.5 / 5000 + } + + [Test] + public void TestPosition() + { + // Basically same calculations as TestLength() + Assert.AreEqual(1f / 5, algorithm.PositionAt(1000, 0, 5000, 1)); + Assert.AreEqual(1f / 5, algorithm.PositionAt(10500, 10000, 5000, 1)); + Assert.AreEqual(1f / 5, algorithm.PositionAt(22000, 20000, 5000, 1)); + } + + [TestCase(1000)] + [TestCase(10000)] + [TestCase(15000)] + [TestCase(20000)] + [TestCase(25000)] + [Ignore("Disabled for now because overlapping control points have multiple time values under the same position." + + "Ideally, scrolling should be changed to constant or sequential during editing of hitobjects.")] + public void TestTime(double time) + { + Assert.AreEqual(time, algorithm.TimeAt(algorithm.PositionAt(time, 0, 5000, 1), 0, 5000, 1), 0.001); + Assert.AreEqual(time, algorithm.TimeAt(algorithm.PositionAt(time, 5000, 5000, 1), 5000, 5000, 1), 0.001); + } + } +} diff --git a/osu.Game.Tests/ScrollAlgorithms/SequentialScrollTest.cs b/osu.Game.Tests/ScrollAlgorithms/SequentialScrollTest.cs new file mode 100644 index 0000000000..990fb92e6c --- /dev/null +++ b/osu.Game.Tests/ScrollAlgorithms/SequentialScrollTest.cs @@ -0,0 +1,64 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using NUnit.Framework; +using osu.Framework.Lists; +using osu.Game.Rulesets.Timing; +using osu.Game.Rulesets.UI.Scrolling.Algorithms; + +namespace osu.Game.Tests.ScrollAlgorithms +{ + [TestFixture] + public class SequentialScrollTest + { + private IScrollAlgorithm algorithm; + + [SetUp] + public void Setup() + { + var controlPoints = new SortedList + { + new MultiplierControlPoint(0) { Velocity = 1 }, + new MultiplierControlPoint(10000) { Velocity = 2f }, + new MultiplierControlPoint(20000) { Velocity = 0.5f } + }; + + algorithm = new SequentialScrollAlgorithm(controlPoints); + } + + [Test] + public void TestDisplayStartTime() + { + // Sequential scroll algorithm approximates the start time + // This should be fixed in the future + } + + [Test] + public void TestLength() + { + Assert.AreEqual(1f / 5, algorithm.GetLength(0, 1000, 5000, 1)); // Like constant + Assert.AreEqual(1f / 5, algorithm.GetLength(10000, 10500, 5000, 1)); // (10500 - 10000) / 0.5 / 5000 + Assert.AreEqual(1f / 5, algorithm.GetLength(20000, 22000, 5000, 1)); // (22000 - 20000) * 0.5 / 5000 + } + + [Test] + public void TestPosition() + { + // Basically same calculations as TestLength() + Assert.AreEqual(1f / 5, algorithm.PositionAt(1000, 0, 5000, 1)); + Assert.AreEqual(1f / 5, algorithm.PositionAt(10500, 10000, 5000, 1)); + Assert.AreEqual(1f / 5, algorithm.PositionAt(22000, 20000, 5000, 1)); + } + + [TestCase(1000)] + [TestCase(10000)] + [TestCase(15000)] + [TestCase(20000)] + [TestCase(25000)] + public void TestTime(double time) + { + Assert.AreEqual(time, algorithm.TimeAt(algorithm.PositionAt(time, 0, 5000, 1), 0, 5000, 1), 0.001); + Assert.AreEqual(time, algorithm.TimeAt(algorithm.PositionAt(time, 5000, 5000, 1), 5000, 5000, 1), 0.001); + } + } +} diff --git a/osu.Game/Rulesets/UI/Scrolling/Algorithms/ConstantScrollAlgorithm.cs b/osu.Game/Rulesets/UI/Scrolling/Algorithms/ConstantScrollAlgorithm.cs index ed61ed7022..5628fb51f3 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Algorithms/ConstantScrollAlgorithm.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Algorithms/ConstantScrollAlgorithm.cs @@ -17,6 +17,9 @@ namespace osu.Game.Rulesets.UI.Scrolling.Algorithms public float PositionAt(double time, double currentTime, double timeRange, float scrollLength) => (float)((time - currentTime) / timeRange * scrollLength); + public double TimeAt(float position, double currentTime, double timeRange, float scrollLength) + => position * timeRange / scrollLength + currentTime; + public void Reset() { } diff --git a/osu.Game/Rulesets/UI/Scrolling/Algorithms/IScrollAlgorithm.cs b/osu.Game/Rulesets/UI/Scrolling/Algorithms/IScrollAlgorithm.cs index 43bc1b2a2a..2ece9bef9b 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Algorithms/IScrollAlgorithm.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Algorithms/IScrollAlgorithm.cs @@ -36,6 +36,16 @@ namespace osu.Game.Rulesets.UI.Scrolling.Algorithms /// The absolute spatial position. float PositionAt(double time, double currentTime, double timeRange, float scrollLength); + /// + /// Computes the time which brings a point to a provided spatial position given the current time. + /// + /// The absolute spatial position. + /// The current time. + /// The amount of visible time. + /// The absolute spatial length through . + /// The time at which == . + double TimeAt(float position, double currentTime, double timeRange, float scrollLength); + /// /// Resets this to a default state. /// diff --git a/osu.Game/Rulesets/UI/Scrolling/Algorithms/OverlappingScrollAlgorithm.cs b/osu.Game/Rulesets/UI/Scrolling/Algorithms/OverlappingScrollAlgorithm.cs index f7c097e81d..4d9659c820 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Algorithms/OverlappingScrollAlgorithm.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Algorithms/OverlappingScrollAlgorithm.cs @@ -3,6 +3,7 @@ using osu.Framework.Lists; using osu.Game.Rulesets.Timing; +using OpenTK; namespace osu.Game.Rulesets.UI.Scrolling.Algorithms { @@ -36,6 +37,33 @@ namespace osu.Game.Rulesets.UI.Scrolling.Algorithms public float PositionAt(double time, double currentTime, double timeRange, float scrollLength) => (float)((time - currentTime) / timeRange * controlPointAt(time).Multiplier * scrollLength); + public double TimeAt(float position, double currentTime, double timeRange, float scrollLength) + { + // Find the control point relating to the position. + // Note: Due to velocity adjustments, overlapping control points will provide multiple valid time values for a single position + // As such, this operation provides unexpected results by using the latter of the control points. + + int i = 0; + float pos = 0; + + for (; i < controlPoints.Count; i++) + { + float lastPos = pos; + pos = PositionAt(controlPoints[i].StartTime, currentTime, timeRange, scrollLength); + + if (pos > position) + { + i--; + pos = lastPos; + break; + } + } + + i = MathHelper.Clamp(i, 0, controlPoints.Count - 1); + + return controlPoints[i].StartTime + (position - pos) * timeRange / controlPoints[i].Multiplier / scrollLength; + } + public void Reset() { } diff --git a/osu.Game/Rulesets/UI/Scrolling/Algorithms/SequentialScrollAlgorithm.cs b/osu.Game/Rulesets/UI/Scrolling/Algorithms/SequentialScrollAlgorithm.cs index 54494cfe63..8f8f546992 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Algorithms/SequentialScrollAlgorithm.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Algorithms/SequentialScrollAlgorithm.cs @@ -35,6 +35,36 @@ namespace osu.Game.Rulesets.UI.Scrolling.Algorithms return (float)((relativePositionAtCached(time, timeRange) - timelinePosition) * scrollLength); } + public double TimeAt(float position, double currentTime, double timeRange, float scrollLength) + { + // Convert the position to a length relative to time = 0 + double length = position / scrollLength + relativePositionAt(currentTime, timeRange); + + // We need to consider all timing points until the specified time and not just the currently-active one, + // since each timing point individually affects the positions of _all_ hitobjects after its start time + for (int i = 0; i < controlPoints.Count; i++) + { + var current = controlPoints[i]; + var next = i < controlPoints.Count - 1 ? controlPoints[i + 1] : null; + + // Duration of the current control point + var currentDuration = (next?.StartTime ?? double.PositiveInfinity) - current.StartTime; + + // Figure out the length of control point + var currentLength = currentDuration / timeRange * current.Multiplier; + + if (currentLength > length) + { + // The point is within this control point + return current.StartTime + length * timeRange / current.Multiplier; + } + + length -= currentLength; + } + + return 0; // Should never occur + } + private double relativePositionAtCached(double time, double timeRange) { if (!positionCache.TryGetValue(time, out double existing)) From e302d5d0058e8e7f1b3b0b2c6efa54b2d4a7a061 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 12 Nov 2018 17:59:39 +0900 Subject: [PATCH 140/155] Separate NoteSelectionBlueprint into a note piece --- .../Blueprints/Components/EditNotePiece.cs | 29 +++++++++++++++++++ .../Edit/Blueprints/NoteSelectionBlueprint.cs | 18 ++---------- 2 files changed, 32 insertions(+), 15 deletions(-) create mode 100644 osu.Game.Rulesets.Mania/Edit/Blueprints/Components/EditNotePiece.cs diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/Components/EditNotePiece.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/Components/EditNotePiece.cs new file mode 100644 index 0000000000..424ff1118c --- /dev/null +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/Components/EditNotePiece.cs @@ -0,0 +1,29 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics; +using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; + +namespace osu.Game.Rulesets.Mania.Edit.Blueprints.Components +{ + public class EditNotePiece : CompositeDrawable + { + public EditNotePiece() + { + Height = NotePiece.NOTE_HEIGHT; + + CornerRadius = 5; + Masking = true; + + InternalChild = new NotePiece(); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + Colour = colours.Yellow; + } + } +} diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/NoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/NoteSelectionBlueprint.cs index 7c0337dc4e..7df7924c51 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/NoteSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/NoteSelectionBlueprint.cs @@ -1,10 +1,9 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Framework.Allocation; -using osu.Game.Graphics; +using osu.Framework.Graphics; +using osu.Game.Rulesets.Mania.Edit.Blueprints.Components; using osu.Game.Rulesets.Mania.Objects.Drawables; -using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; namespace osu.Game.Rulesets.Mania.Edit.Blueprints { @@ -13,18 +12,7 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints public NoteSelectionBlueprint(DrawableNote note) : base(note) { - Scale = note.Scale; - - CornerRadius = 5; - Masking = true; - - AddInternal(new NotePiece()); - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - Colour = colours.Yellow; + AddInternal(new EditNotePiece { RelativeSizeAxes = Axes.X }); } protected override void Update() From fbc20d2d4dd114636037baf496d0bf5f9db66e48 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 13 Nov 2018 12:52:04 +0900 Subject: [PATCH 141/155] Hide placement when cursor is not in the playfield --- osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs | 2 ++ osu.Game/Rulesets/Edit/HitObjectComposer.cs | 22 ++++++++-------- osu.Game/Rulesets/Edit/PlacementBlueprint.cs | 8 +++--- .../Compose/Components/BlueprintContainer.cs | 26 ++++++++++++++++++- 4 files changed, 43 insertions(+), 15 deletions(-) diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs index 398680cb8d..a94d1e9039 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs @@ -84,5 +84,7 @@ namespace osu.Game.Rulesets.Osu.UI judgementLayer.Add(explosion); } + + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => HitObjectContainer.ReceivePositionalInputAt(screenSpacePos); } } diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 932cfe5789..8e2905a4df 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Edit { public abstract class HitObjectComposer : CompositeDrawable { - public IEnumerable HitObjects => rulesetContainer.Playfield.AllHitObjects; + public IEnumerable HitObjects => RulesetContainer.Playfield.AllHitObjects; protected readonly Ruleset Ruleset; @@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Edit private readonly List layerContainers = new List(); - private EditRulesetContainer rulesetContainer; + public EditRulesetContainer RulesetContainer { get; private set; } private BlueprintContainer blueprintContainer; @@ -51,8 +51,8 @@ namespace osu.Game.Rulesets.Edit try { - rulesetContainer = CreateRulesetContainer(); - rulesetContainer.Clock = framedClock; + RulesetContainer = CreateRulesetContainer(); + RulesetContainer.Clock = framedClock; } catch (Exception e) { @@ -94,7 +94,7 @@ namespace osu.Game.Rulesets.Edit Children = new Drawable[] { layerBelowRuleset, - rulesetContainer, + RulesetContainer, layerAboveRuleset } } @@ -130,10 +130,10 @@ namespace osu.Game.Rulesets.Edit layerContainers.ForEach(l => { - l.Anchor = rulesetContainer.Playfield.Anchor; - l.Origin = rulesetContainer.Playfield.Origin; - l.Position = rulesetContainer.Playfield.Position; - l.Size = rulesetContainer.Playfield.Size; + l.Anchor = RulesetContainer.Playfield.Anchor; + l.Origin = RulesetContainer.Playfield.Origin; + l.Position = RulesetContainer.Playfield.Position; + l.Size = RulesetContainer.Playfield.Size; }); } @@ -141,9 +141,9 @@ namespace osu.Game.Rulesets.Edit /// Adds a to the and visualises it. /// /// The to add. - public void Add(HitObject hitObject) => blueprintContainer.AddBlueprintFor(rulesetContainer.Add(hitObject)); + public void Add(HitObject hitObject) => blueprintContainer.AddBlueprintFor(RulesetContainer.Add(hitObject)); - public void Remove(HitObject hitObject) => blueprintContainer.RemoveBlueprintFor(rulesetContainer.Remove(hitObject)); + public void Remove(HitObject hitObject) => blueprintContainer.RemoveBlueprintFor(RulesetContainer.Remove(hitObject)); internal abstract EditRulesetContainer CreateRulesetContainer(); diff --git a/osu.Game/Rulesets/Edit/PlacementBlueprint.cs b/osu.Game/Rulesets/Edit/PlacementBlueprint.cs index b726b683ea..1ae5f5f903 100644 --- a/osu.Game/Rulesets/Edit/PlacementBlueprint.cs +++ b/osu.Game/Rulesets/Edit/PlacementBlueprint.cs @@ -37,6 +37,8 @@ namespace osu.Game.Rulesets.Edit HitObject = hitObject; RelativeSizeAxes = Axes.Both; + + Alpha = 0; } [BackgroundDependencyLoader] @@ -49,7 +51,7 @@ namespace osu.Game.Rulesets.Edit ApplyDefaultsToHitObject(); } - private bool placementBegun; + public bool PlacementBegun { get; private set; } /// /// Signals that the placement of has started. @@ -57,7 +59,7 @@ namespace osu.Game.Rulesets.Edit protected void BeginPlacement() { placementHandler.BeginPlacement(HitObject); - placementBegun = true; + PlacementBegun = true; } /// @@ -66,7 +68,7 @@ namespace osu.Game.Rulesets.Edit /// protected void EndPlacement() { - if (!placementBegun) + if (!PlacementBegun) BeginPlacement(); placementHandler.EndPlacement(HitObject); } diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index acbfd1f1d6..d1c7470336 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -7,6 +7,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Primitives; +using osu.Framework.Input; using osu.Framework.Input.Events; using osu.Framework.Input.States; using osu.Game.Rulesets.Edit; @@ -18,7 +19,10 @@ namespace osu.Game.Screens.Edit.Compose.Components public class BlueprintContainer : CompositeDrawable { private SelectionBlueprintContainer selectionBlueprints; + private Container placementBlueprintContainer; + private PlacementBlueprint currentPlacement; + private SelectionBox selectionBox; private IEnumerable selections => selectionBlueprints.Children.Where(c => c.IsAlive); @@ -26,6 +30,8 @@ namespace osu.Game.Screens.Edit.Compose.Components [Resolved] private HitObjectComposer composer { get; set; } + private InputManager inputManager; + public BlueprintContainer() { RelativeSizeAxes = Axes.Both; @@ -53,6 +59,13 @@ namespace osu.Game.Screens.Edit.Compose.Components AddBlueprintFor(obj); } + protected override void LoadComplete() + { + base.LoadComplete(); + + inputManager = GetContainingInputManager(); + } + private HitObjectCompositionTool currentTool; /// @@ -117,16 +130,27 @@ namespace osu.Game.Screens.Edit.Compose.Components return true; } + protected override void Update() + { + base.Update(); + + if (composer.RulesetContainer.Playfield.ReceivePositionalInputAt(inputManager.CurrentState.Mouse.Position)) + currentPlacement?.Show(); + else if (currentPlacement?.PlacementBegun == false) + currentPlacement?.Hide(); + } + /// /// Refreshes the current placement tool. /// private void refreshTool() { placementBlueprintContainer.Clear(); + currentPlacement = null; var blueprint = CurrentTool?.CreatePlacementBlueprint(); if (blueprint != null) - placementBlueprintContainer.Child = blueprint; + placementBlueprintContainer.Child = currentPlacement = blueprint; } From 819cba31cecbf0970dd8924afc83fedd347b1e34 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 13 Nov 2018 12:52:44 +0900 Subject: [PATCH 142/155] Fix spinners not starting placement with the first click --- .../Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs index c97adde427..804a4fcba0 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs @@ -37,6 +37,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners isPlacingEnd = true; piece.FadeTo(1f, 150, Easing.OutQuint); + + BeginPlacement(); } return true; From 6d43baf4bf49a9c03823c77889746f7ad330ac9a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 13 Nov 2018 13:00:00 +0900 Subject: [PATCH 143/155] Make show/hide only invoked once each --- osu.Game/Rulesets/Edit/PlacementBlueprint.cs | 40 ++++++++++++++++++- .../Compose/Components/BlueprintContainer.cs | 14 ++++--- 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/osu.Game/Rulesets/Edit/PlacementBlueprint.cs b/osu.Game/Rulesets/Edit/PlacementBlueprint.cs index 1ae5f5f903..45dc7e4a05 100644 --- a/osu.Game/Rulesets/Edit/PlacementBlueprint.cs +++ b/osu.Game/Rulesets/Edit/PlacementBlueprint.cs @@ -1,6 +1,8 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; +using osu.Framework; using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Graphics; @@ -18,8 +20,18 @@ namespace osu.Game.Rulesets.Edit /// /// A blueprint which governs the creation of a new to actualisation. /// - public abstract class PlacementBlueprint : CompositeDrawable, IRequireHighFrequencyMousePosition + public abstract class PlacementBlueprint : CompositeDrawable, IStateful, IRequireHighFrequencyMousePosition { + /// + /// Invoked when has changed. + /// + public event Action StateChanged; + + /// + /// Whether the is currently being placed, but has not necessarily finished being placed. + /// + public bool PlacementBegun { get; private set; } + /// /// The that is being placed. /// @@ -51,7 +63,25 @@ namespace osu.Game.Rulesets.Edit ApplyDefaultsToHitObject(); } - public bool PlacementBegun { get; private set; } + private PlacementState state; + + public PlacementState State + { + get => state; + set + { + if (state == value) + return; + state = value; + + if (state == PlacementState.Shown) + Show(); + else + Hide(); + + StateChanged?.Invoke(value); + } + } /// /// Signals that the placement of has started. @@ -95,4 +125,10 @@ namespace osu.Game.Rulesets.Edit } } } + + public enum PlacementState + { + Hidden, + Shown, + } } diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index d1c7470336..54c9efe463 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -134,10 +134,15 @@ namespace osu.Game.Screens.Edit.Compose.Components { base.Update(); - if (composer.RulesetContainer.Playfield.ReceivePositionalInputAt(inputManager.CurrentState.Mouse.Position)) - currentPlacement?.Show(); - else if (currentPlacement?.PlacementBegun == false) - currentPlacement?.Hide(); + if (currentPlacement != null) + { + bool cursorInPlayfield = composer.RulesetContainer.Playfield.ReceivePositionalInputAt(inputManager.CurrentState.Mouse.Position); + + if (cursorInPlayfield) + currentPlacement.State = PlacementState.Shown; + else if (currentPlacement?.PlacementBegun == false) + currentPlacement.State = PlacementState.Hidden; + } } /// @@ -153,7 +158,6 @@ namespace osu.Game.Screens.Edit.Compose.Components placementBlueprintContainer.Child = currentPlacement = blueprint; } - /// /// Select all masks in a given rectangle selection area. /// From f241fcdba187912afd911c0f0a6d569cdcebead6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 13 Nov 2018 15:20:40 +0900 Subject: [PATCH 144/155] Add back support for new API and private messages --- .../Visual/TestCaseChannelTabControl.cs | 7 +- osu.Game/Online/Chat/Channel.cs | 19 +- osu.Game/Online/Chat/ChannelManager.cs | 199 +++++++++--------- .../Online/Chat/IncomingMessagesHandler.cs | 72 ------- osu.Game/Online/Chat/Message.cs | 9 - osu.Game/Online/Chat/PrivateChannel.cs | 29 --- .../Overlays/Chat/Tabs/ChannelTabControl.cs | 6 +- .../Chat/Tabs/PrivateChannelTabItem.cs | 6 +- osu.Game/Overlays/ChatOverlay.cs | 22 +- 9 files changed, 135 insertions(+), 234 deletions(-) delete mode 100644 osu.Game/Online/Chat/IncomingMessagesHandler.cs delete mode 100644 osu.Game/Online/Chat/PrivateChannel.cs diff --git a/osu.Game.Tests/Visual/TestCaseChannelTabControl.cs b/osu.Game.Tests/Visual/TestCaseChannelTabControl.cs index 1c1675a67c..1d39cba81d 100644 --- a/osu.Game.Tests/Visual/TestCaseChannelTabControl.cs +++ b/osu.Game.Tests/Visual/TestCaseChannelTabControl.cs @@ -87,15 +87,18 @@ namespace osu.Game.Tests.Visual private void addRandomUser() { - channelTabControl.AddChannel(new PrivateChannel + channelTabControl.AddChannel(new Channel { - User = users?.Count > 0 + Users = + { + users?.Count > 0 ? users[RNG.Next(0, users.Count - 1)] : new User { Id = RNG.Next(), Username = "testuser" + RNG.Next(1000) } + } }); } diff --git a/osu.Game/Online/Chat/Channel.cs b/osu.Game/Online/Chat/Channel.cs index e6ad72a2bc..c49490ea19 100644 --- a/osu.Game/Online/Chat/Channel.cs +++ b/osu.Game/Online/Chat/Channel.cs @@ -17,9 +17,19 @@ namespace osu.Game.Online.Chat public readonly int MaxHistory = 300; /// - /// Contains every joined user except the current logged in user. + /// Contains every joined user except the current logged in user. Currently only returned for PM channels. /// - public readonly ObservableCollection JoinedUsers = new ObservableCollection(); + public readonly ObservableCollection Users = new ObservableCollection(); + + [JsonProperty(@"users")] + private long[] userIds + { + set + { + foreach (var id in value) + Users.Add(new User { Id = id }); + } + } /// /// Contains all the messages send in the channel. @@ -47,11 +57,6 @@ namespace osu.Game.Online.Chat /// public event Action MessageRemoved; - /// - /// Signalles whether the channels target is a private channel or public channel. - /// - public TargetType Target { get; protected set; } - public bool ReadOnly => false; //todo not yet used. public override string ToString() => Name; diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 377e9ee7bb..8099f97999 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -39,12 +39,12 @@ namespace osu.Game.Online.Chat /// /// The Channels the player has joined /// - public ObservableCollection JoinedChannels { get; } = new ObservableCollection(); + public ObservableCollection JoinedChannels { get; } = new ObservableCollection(); //todo: should be publicly readonly /// /// The channels available for the player to join /// - public ObservableCollection AvailableChannels { get; } = new ObservableCollection(); + public ObservableCollection AvailableChannels { get; } = new ObservableCollection(); //todo: should be publicly readonly /*private readonly IncomingMessagesHandler privateMessagesHandler;*/ @@ -54,12 +54,6 @@ namespace osu.Game.Online.Chat public ChannelManager() { CurrentChannel.ValueChanged += currentChannelChanged; - - /*channelMessagesHandler = new IncomingMessagesHandler( - lastId => new GetMessagesRequest(JoinedChannels.Where(c => c.Target == TargetType.Channel)), handleChannelMessages); - - privateMessagesHandler = new IncomingMessagesHandler( - lastId => new GetPrivateMessagesRequest(lastId),handleUserMessages);*/ } /// @@ -85,14 +79,13 @@ namespace osu.Game.Online.Chat if (user == null) throw new ArgumentNullException(nameof(user)); - CurrentChannel.Value = JoinedChannels.FirstOrDefault(c => c.Target == TargetType.User && c.Id == user.Id) - ?? new PrivateChannel { User = 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 } }; } private void currentChannelChanged(Channel channel) { - if (!JoinedChannels.Contains(channel)) - JoinedChannels.Add(channel); + JoinChannel(channel); } /// @@ -169,71 +162,6 @@ namespace osu.Game.Online.Chat } } - private void fetchNewMessages() - { - /*if (channelMessagesHandler.CanRequestNewMessages) - channelMessagesHandler.RequestNewMessages(api); - - if (privateMessagesHandler.CanRequestNewMessages) - privateMessagesHandler.RequestNewMessages(api);*/ - } - - private void handleUserMessages(IEnumerable messages) - { - var joinedPrivateChannels = JoinedChannels.Where(c => c.Target == TargetType.User).ToList(); - - Channel getChannelForUser(User user) - { - var channel = joinedPrivateChannels.FirstOrDefault(c => c.Id == user.Id); - - if (channel == null) - { - channel = new PrivateChannel { User = user }; - JoinedChannels.Add(channel); - joinedPrivateChannels.Add(channel); - } - - return channel; - } - - long localUserId = api.LocalUser.Value.Id; - - var outgoingGroups = messages.Where(m => m.Sender.Id == localUserId).GroupBy(m => m.ChannelId); - var incomingGroups = messages.Where(m => m.Sender.Id != localUserId).GroupBy(m => m.UserId); - - foreach (var group in incomingGroups) - { - var targetUser = group.First().Sender; - - var channel = getChannelForUser(targetUser); - - channel.AddNewMessages(group.ToArray()); - - var outgoingTargetMessages = outgoingGroups.FirstOrDefault(g => g.Key == targetUser.Id); - if (outgoingTargetMessages != null) - channel.AddNewMessages(outgoingTargetMessages.ToArray()); - } - - // Because of the way the API provides data right now, outgoing messages do not contain required - // user (or in the future, target channel) metadata. As such we need to do a second request - // to find out the specifics of the user. - var withoutReplyGroups = outgoingGroups.Where(g => joinedPrivateChannels.All(m => m.Id != g.Key)); - - foreach (var withoutReplyGroup in withoutReplyGroups) - { - var userReq = new GetUserRequest(withoutReplyGroup.First().ChannelId); - - userReq.Failure += exception => Logger.Error(exception, "Failed to get user informations."); - userReq.Success += user => - { - var channel = getChannelForUser(user); - channel.AddNewMessages(withoutReplyGroup.ToArray()); - }; - - api.Queue(userReq); - } - } - private void handleChannelMessages(IEnumerable messages) { var channels = JoinedChannels.ToList(); @@ -246,32 +174,24 @@ namespace osu.Game.Online.Chat { var req = new ListChannelsRequest(); + //var joinDefaults = JoinedChannels.Count == 0; + req.Success += channels => { foreach (var channel in channels) { - if (JoinedChannels.Any(c => c.Id == channel.Id)) - continue; - // add as available if not already if (AvailableChannels.All(c => c.Id != channel.Id)) AvailableChannels.Add(channel); // join any channels classified as "defaults" - if (defaultChannels.Any(c => c.Equals(channel.Name, StringComparison.OrdinalIgnoreCase))) - { - JoinedChannels.Add(channel); - - FetchInitalMessages(channel); - } + /*if (joinDefaults && defaultChannels.Any(c => c.Equals(channel.Name, StringComparison.OrdinalIgnoreCase))) + JoinChannel(channel);*/ } - - fetchNewMessages(); }; req.Failure += error => { Logger.Error(error, "Fetching channel list failed"); - initializeDefaultChannels(); }; @@ -285,7 +205,7 @@ namespace osu.Game.Online.Chat /// right now it caps out at 50 messages and therefore only returns one channel's worth of content. /// /// The channel - public void FetchInitalMessages(Channel channel) + private void fetchInitalMessages(Channel channel) { var fetchInitialMsgReq = new GetMessagesRequest(channel); fetchInitialMsgReq.Success += handleChannelMessages; @@ -293,6 +213,62 @@ namespace osu.Game.Online.Chat api.Queue(fetchInitialMsgReq); } + public void JoinChannel(Channel channel) + { + if (channel == null) return; + + // ReSharper disable once AccessToModifiedClosure + var existing = JoinedChannels.FirstOrDefault(c => c.Id == channel.Id); + + if (existing != 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); + if (foundSelf != null) + channel.Users.Remove(foundSelf); + + JoinedChannels.Add(channel); + + if (channel.Type == ChannelType.Public && !channel.Joined) + { + var req = new JoinChannelRequest(channel, api.LocalUser); + req.Success += () => JoinChannel(channel); + req.Failure += ex => LeaveChannel(channel); + api.Queue(req); + return; + } + } + + if (CurrentChannel.Value == null) + CurrentChannel.Value = channel; + + if (!channel.Joined.Value) + { + // let's fetch a small number of messages to bring us up-to-date with the backlog. + fetchInitalMessages(channel); + channel.Joined.Value = true; + } + } + + public void LeaveChannel(Channel channel) + { + if (channel == null) return; + + if (channel == CurrentChannel.Value) CurrentChannel.Value = null; + + JoinedChannels.Remove(channel); + + if (channel.Joined.Value) + { + api.Queue(new LeaveChannelRequest(channel, api.LocalUser)); + channel.Joined.Value = false; + } + } + public void APIStateChanged(APIAccess api, APIState state) { switch (state) @@ -301,18 +277,53 @@ namespace osu.Game.Online.Chat if (JoinedChannels.Count == 0) initializeDefaultChannels(); - fetchMessagesScheduleder = Scheduler.AddDelayed(fetchNewMessages, 1000, true); + fetchUpdates(); break; default: - /*channelMessagesHandler.CancelOngoingRequests(); - privateMessagesHandler.CancelOngoingRequests();*/ - fetchMessagesScheduleder?.Cancel(); fetchMessagesScheduleder = null; break; } } + private long lastMessageId; + private const int update_poll_interval = 1000; + + private void fetchUpdates() + { + fetchMessagesScheduleder?.Cancel(); + fetchMessagesScheduleder = Scheduler.AddDelayed(() => + { + var fetchReq = new GetUpdatesRequest(lastMessageId); + + fetchReq.Success += updates => + { + if (updates?.Presence != null) + { + foreach (var channel in updates.Presence) + { + JoinChannel(AvailableChannels.FirstOrDefault(c => c.Id == channel.Id) ?? channel); + } + + //todo: handle left channels + + handleChannelMessages(updates.Messages); + + foreach (var group in updates.Messages.GroupBy(m => m.ChannelId)) + JoinedChannels.FirstOrDefault(c => c.Id == group.Key)?.AddNewMessages(group.ToArray()); + + lastMessageId = updates.Messages.LastOrDefault()?.Id ?? lastMessageId; + } + + fetchUpdates(); + }; + + fetchReq.Failure += delegate { fetchUpdates(); }; + + api.Queue(fetchReq); + }, update_poll_interval); + } + [BackgroundDependencyLoader] private void load(IAPIProvider api) { diff --git a/osu.Game/Online/Chat/IncomingMessagesHandler.cs b/osu.Game/Online/Chat/IncomingMessagesHandler.cs deleted file mode 100644 index 46f2b805b3..0000000000 --- a/osu.Game/Online/Chat/IncomingMessagesHandler.cs +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System; -using System.Collections.Generic; -using System.Linq; -using JetBrains.Annotations; -using osu.Framework.Logging; -using osu.Game.Online.API; - -namespace osu.Game.Online.Chat -{ - /// - /// Handles tracking and updating of a specific message type, allowing polling and requesting of only new messages on an ongoing basis. - /// - public class IncomingMessagesHandler - { - public delegate APIMessagesRequest CreateRequestDelegate(long? lastMessageId); - - public long? LastMessageId { get; private set; } - - private APIMessagesRequest getMessagesRequest; - - private readonly CreateRequestDelegate createRequest; - private readonly Action> onNewMessages; - - public bool CanRequestNewMessages => getMessagesRequest == null; - - public IncomingMessagesHandler([NotNull] CreateRequestDelegate createRequest, [NotNull] Action> onNewMessages) - { - this.createRequest = createRequest ?? throw new ArgumentNullException(nameof(createRequest)); - this.onNewMessages = onNewMessages ?? throw new ArgumentNullException(nameof(onNewMessages)); - } - - public void RequestNewMessages(IAPIProvider api) - { - if (!CanRequestNewMessages) - throw new InvalidOperationException("Requesting new messages is not possible yet, because the old request is still ongoing."); - - getMessagesRequest = createRequest.Invoke(LastMessageId); - getMessagesRequest.Success += handleNewMessages; - getMessagesRequest.Failure += exception => - { - Logger.Error(exception, "Fetching messages failed."); - - // allowing new messages to be requested even after the fail. - getMessagesRequest = null; - }; - - api.Queue(getMessagesRequest); - } - - private void handleNewMessages(List messages) - { - // allowing new messages to be requested. - getMessagesRequest = null; - - // in case of no new messages we simply do nothing. - if (messages == null || messages.Count == 0) - return; - - onNewMessages.Invoke(messages); - - LastMessageId = messages.Max(m => m.Id) ?? LastMessageId; - } - - public void CancelOngoingRequests() - { - getMessagesRequest?.Cancel(); - } - } -} diff --git a/osu.Game/Online/Chat/Message.cs b/osu.Game/Online/Chat/Message.cs index b4a7b6faa7..3f0f352ac7 100644 --- a/osu.Game/Online/Chat/Message.cs +++ b/osu.Game/Online/Chat/Message.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.ComponentModel; using Newtonsoft.Json; using osu.Game.Users; @@ -69,12 +68,4 @@ namespace osu.Game.Online.Chat // ReSharper disable once ImpureMethodCallOnReadonlyValueField public override int GetHashCode() => Id.GetHashCode(); } - - public enum TargetType - { - [Description(@"channel")] - Channel, - [Description(@"user")] - User - } } diff --git a/osu.Game/Online/Chat/PrivateChannel.cs b/osu.Game/Online/Chat/PrivateChannel.cs deleted file mode 100644 index aac88ecb27..0000000000 --- a/osu.Game/Online/Chat/PrivateChannel.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using osu.Game.Users; - -namespace osu.Game.Online.Chat -{ - public class PrivateChannel : Channel - { - public User User - { - set - { - Name = value.Username; - Id = value.Id; - JoinedUsers.Add(value); - } - } - - /// - /// Contructs a private channel - /// - /// The user - public PrivateChannel() - { - Target = TargetType.User; - } - } -} diff --git a/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs b/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs index 6470963b4f..08d4e40a64 100644 --- a/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs +++ b/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs @@ -54,11 +54,11 @@ namespace osu.Game.Overlays.Chat.Tabs protected override TabItem CreateTabItem(Channel value) { - switch (value.Target) + switch (value.Type) { - case TargetType.Channel: + case ChannelType.Public: return new ChannelTabItem(value) { OnRequestClose = tabCloseRequested }; - case TargetType.User: + case ChannelType.PM: return new PrivateChannelTabItem(value) { OnRequestClose = tabCloseRequested }; default: throw new InvalidOperationException("Only TargetType User and Channel are supported."); diff --git a/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs b/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs index 7492de0123..c7ca1cb073 100644 --- a/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs +++ b/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs @@ -25,7 +25,7 @@ namespace osu.Game.Overlays.Chat.Tabs public PrivateChannelTabItem(Channel value) : base(value) { - if (value.Target != TargetType.User) + if (value.Type != ChannelType.PM) throw new ArgumentException("Argument value needs to have the targettype user!"); AddRange(new Drawable[] @@ -49,7 +49,7 @@ namespace osu.Game.Overlays.Chat.Tabs Anchor = Anchor.Centre, Origin = Anchor.Centre, Masking = true, - Child = new DelayedLoadWrapper(new Avatar(value.JoinedUsers.First()) + Child = new DelayedLoadWrapper(new Avatar(value.Users.First()) { RelativeSizeAxes = Axes.Both, OnLoadComplete = d => d.FadeInFromZero(300, Easing.OutQuint), @@ -88,7 +88,7 @@ namespace osu.Game.Overlays.Chat.Tabs [BackgroundDependencyLoader] private void load(OsuColour colours) { - var user = Value.JoinedUsers.First(); + var user = Value.Users.First(); BackgroundActive = user.Colour != null ? OsuColour.FromHex(user.Colour) : colours.BlueDark; BackgroundInactive = BackgroundActive.Darken(0.5f); diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 9fc4c15849..e45373c36f 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -153,7 +153,7 @@ namespace osu.Game.Overlays Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, RelativeSizeAxes = Axes.Both, - OnRequestLeave = channel => channelManager.JoinedChannels.Remove(channel) + OnRequestLeave = channel => channelManager.LeaveChannel(channel) }, } }, @@ -176,15 +176,9 @@ namespace osu.Game.Overlays else textbox.HoldFocus = true; }; - channelSelection.OnRequestJoin = channel => - { - if (!channelManager.JoinedChannels.Contains(channel)) - { - channelManager.JoinedChannels.Add(channel); - channelManager.FetchInitalMessages(channel); - } - }; - channelSelection.OnRequestLeave = channel => channelManager.JoinedChannels.Remove(channel); + + channelSelection.OnRequestJoin = channel => channelManager.JoinChannel(channel); + channelSelection.OnRequestLeave = channel => channelManager.LeaveChannel(channel); } private void joinedChannelsChanged(object sender, NotifyCollectionChangedEventArgs args) @@ -195,18 +189,16 @@ namespace osu.Game.Overlays foreach (Channel newChannel in args.NewItems) { channelTabControl.AddChannel(newChannel); - - newChannel.Joined.Value = true; } + break; case NotifyCollectionChangedAction.Remove: foreach (Channel removedChannel in args.OldItems) { channelTabControl.RemoveChannel(removedChannel); - - loadedChannels.Remove(loadedChannels.Find(c => c.Channel == removedChannel )); - removedChannel.Joined.Value = false; + loadedChannels.Remove(loadedChannels.Find(c => c.Channel == removedChannel)); } + break; } } From 82ebc74eeeea1b3ecc3901cda7da0850a9b986f4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 13 Nov 2018 15:36:36 +0900 Subject: [PATCH 145/155] Fix testcase --- osu.Game.Tests/Visual/TestCaseChannelTabControl.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Tests/Visual/TestCaseChannelTabControl.cs b/osu.Game.Tests/Visual/TestCaseChannelTabControl.cs index 1d39cba81d..e6a04bf5c6 100644 --- a/osu.Game.Tests/Visual/TestCaseChannelTabControl.cs +++ b/osu.Game.Tests/Visual/TestCaseChannelTabControl.cs @@ -106,6 +106,7 @@ namespace osu.Game.Tests.Visual { channelTabControl.AddChannel(new Channel { + Type = ChannelType.Public, Name = name }); } From 72ae22b0c4ab417b47c8a86e2d9bca508c9c3b3f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 13 Nov 2018 17:24:11 +0900 Subject: [PATCH 146/155] Add support for creating new PM conversations --- .../CreateNewPrivateMessageRequest.cs | 34 +++++ .../CreateNewPrivateMessageResponse.cs | 16 +++ osu.Game/Online/Chat/Channel.cs | 3 +- osu.Game/Online/Chat/ChannelManager.cs | 132 +++++++++++++----- 4 files changed, 150 insertions(+), 35 deletions(-) create mode 100644 osu.Game/Online/API/Requests/CreateNewPrivateMessageRequest.cs create mode 100644 osu.Game/Online/API/Requests/CreateNewPrivateMessageResponse.cs diff --git a/osu.Game/Online/API/Requests/CreateNewPrivateMessageRequest.cs b/osu.Game/Online/API/Requests/CreateNewPrivateMessageRequest.cs new file mode 100644 index 0000000000..00dab10c75 --- /dev/null +++ b/osu.Game/Online/API/Requests/CreateNewPrivateMessageRequest.cs @@ -0,0 +1,34 @@ +// 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 CreateNewPrivateMessageRequest : APIRequest + { + private readonly User user; + private readonly Message message; + + public CreateNewPrivateMessageRequest(User user, Message message) + { + this.user = user; + this.message = message; + } + + protected override WebRequest CreateWebRequest() + { + var req = base.CreateWebRequest(); + req.Method = HttpMethod.Post; + req.AddParameter(@"target_id", user.Id.ToString()); + req.AddParameter(@"message", message.Content); + req.AddParameter(@"is_action", message.IsAction.ToString().ToLowerInvariant()); + return req; + } + + protected override string Target => @"chat/new"; + } +} diff --git a/osu.Game/Online/API/Requests/CreateNewPrivateMessageResponse.cs b/osu.Game/Online/API/Requests/CreateNewPrivateMessageResponse.cs new file mode 100644 index 0000000000..84f1593c31 --- /dev/null +++ b/osu.Game/Online/API/Requests/CreateNewPrivateMessageResponse.cs @@ -0,0 +1,16 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using Newtonsoft.Json; +using osu.Game.Online.Chat; + +namespace osu.Game.Online.API.Requests +{ + public class CreateNewPrivateMessageResponse + { + [JsonProperty("new_channel_id")] + public int ChannelID; + + public Message Message; + } +} diff --git a/osu.Game/Online/Chat/Channel.cs b/osu.Game/Online/Chat/Channel.cs index c49490ea19..9d3b7b5cc9 100644 --- a/osu.Game/Online/Chat/Channel.cs +++ b/osu.Game/Online/Chat/Channel.cs @@ -100,7 +100,7 @@ namespace osu.Game.Online.Chat NewMessagesArrived?.Invoke(new[] { message }); } - public bool MessagesLoaded { get; private set; } + public bool MessagesLoaded; /// /// Adds new messages to the channel and purges old messages. Triggers the event. @@ -113,7 +113,6 @@ namespace osu.Game.Online.Chat if (messages.Length == 0) return; Messages.AddRange(messages); - MessagesLoaded = true; var maxMessageId = messages.Max(m => m.Id); if (maxMessageId > LastMessageId) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 8099f97999..71b1d8a80a 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -88,6 +88,12 @@ namespace osu.Game.Online.Chat JoinChannel(channel); } + + /// + /// Ensure we run post actions in sequence, once at a time. + /// + private readonly Queue postQueue = new Queue(); + /// /// Posts a message to the currently opened channel. /// @@ -100,31 +106,70 @@ namespace osu.Game.Online.Chat var currentChannel = CurrentChannel.Value; - if (!api.IsLoggedIn) + void dequeueAndRun() { - currentChannel.AddNewMessages(new ErrorMessage("Please sign in to participate in chat!")); - return; + if (postQueue.Count > 0) + postQueue.Dequeue().Invoke(); } - var message = new LocalEchoMessage + postQueue.Enqueue(() => { - Sender = api.LocalUser.Value, - Timestamp = DateTimeOffset.Now, - ChannelId = CurrentChannel.Value.Id, - IsAction = isAction, - Content = text - }; + if (!api.IsLoggedIn) + { + currentChannel.AddNewMessages(new ErrorMessage("Please sign in to participate in chat!")); + return; + } - currentChannel.AddLocalEcho(message); + var message = new LocalEchoMessage + { + Sender = api.LocalUser.Value, + Timestamp = DateTimeOffset.Now, + ChannelId = CurrentChannel.Value.Id, + IsAction = isAction, + Content = text + }; - var req = new PostMessageRequest(message); - req.Failure += exception => - { - Logger.Error(exception, "Posting message failed."); - currentChannel.ReplaceMessage(message, null); - }; - req.Success += m => currentChannel.ReplaceMessage(message, m); - api.Queue(req); + currentChannel.AddLocalEcho(message); + + // if this is a PM and the first message, we need to do a special request to create the PM channel + if (currentChannel.Type == ChannelType.PM && !currentChannel.Joined) + { + var createNewPrivateMessageRequest = new CreateNewPrivateMessageRequest(currentChannel.Users.First(), message); + createNewPrivateMessageRequest.Success += createRes => + { + currentChannel.Id = createRes.ChannelID; + currentChannel.ReplaceMessage(message, createRes.Message); + dequeueAndRun(); + }; + createNewPrivateMessageRequest.Failure += exception => + { + Logger.Error(exception, "Posting message failed."); + currentChannel.ReplaceMessage(message, null); + dequeueAndRun(); + }; + + api.Queue(createNewPrivateMessageRequest); + return; + } + + var req = new PostMessageRequest(message); + req.Success += m => + { + currentChannel.ReplaceMessage(message, m); + dequeueAndRun(); + }; + req.Failure += exception => + { + Logger.Error(exception, "Posting message failed."); + currentChannel.ReplaceMessage(message, null); + dequeueAndRun(); + }; + api.Queue(req); + }); + + // always run if the queue is empty + if (postQueue.Count == 1) + dequeueAndRun(); } /// @@ -170,11 +215,11 @@ namespace osu.Game.Online.Chat channels.Find(c => c.Id == group.Key)?.AddNewMessages(group.ToArray()); } - private void initializeDefaultChannels() + private void initializeChannels() { var req = new ListChannelsRequest(); - //var joinDefaults = JoinedChannels.Count == 0; + var joinDefaults = JoinedChannels.Count == 0; req.Success += channels => { @@ -185,14 +230,14 @@ namespace osu.Game.Online.Chat AvailableChannels.Add(channel); // join any channels classified as "defaults" - /*if (joinDefaults && defaultChannels.Any(c => c.Equals(channel.Name, StringComparison.OrdinalIgnoreCase))) - JoinChannel(channel);*/ + if (joinDefaults && defaultChannels.Any(c => c.Equals(channel.Name, StringComparison.OrdinalIgnoreCase))) + JoinChannel(channel); } }; req.Failure += error => { Logger.Error(error, "Fetching channel list failed"); - initializeDefaultChannels(); + initializeChannels(); }; api.Queue(req); @@ -207,9 +252,15 @@ namespace osu.Game.Online.Chat /// The channel private void fetchInitalMessages(Channel channel) { + if (channel.Id <= 0) return; + var fetchInitialMsgReq = new GetMessagesRequest(channel); - fetchInitialMsgReq.Success += handleChannelMessages; - fetchInitialMsgReq.Failure += exception => Logger.Error(exception, $"Failed to fetch inital messages for the channel {channel.Name}"); + fetchInitialMsgReq.Success += messages => + { + handleChannelMessages(messages); + channel.MessagesLoaded = true; // this will mark the channel as having received messages even if tehre were none. + }; + api.Queue(fetchInitialMsgReq); } @@ -236,7 +287,11 @@ namespace osu.Game.Online.Chat if (channel.Type == ChannelType.Public && !channel.Joined) { var req = new JoinChannelRequest(channel, api.LocalUser); - req.Success += () => JoinChannel(channel); + req.Success += () => + { + channel.Joined.Value = true; + JoinChannel(channel); + }; req.Failure += ex => LeaveChannel(channel); api.Queue(req); return; @@ -246,11 +301,10 @@ namespace osu.Game.Online.Chat if (CurrentChannel.Value == null) CurrentChannel.Value = channel; - if (!channel.Joined.Value) + if (!channel.MessagesLoaded) { // let's fetch a small number of messages to bring us up-to-date with the backlog. fetchInitalMessages(channel); - channel.Joined.Value = true; } } @@ -274,9 +328,6 @@ namespace osu.Game.Online.Chat switch (state) { case APIState.Online: - if (JoinedChannels.Count == 0) - initializeDefaultChannels(); - fetchUpdates(); break; default: @@ -289,6 +340,8 @@ namespace osu.Game.Online.Chat private long lastMessageId; private const int update_poll_interval = 1000; + private bool channelsInitialised; + private void fetchUpdates() { fetchMessagesScheduleder?.Cancel(); @@ -302,7 +355,20 @@ namespace osu.Game.Online.Chat { foreach (var channel in updates.Presence) { - JoinChannel(AvailableChannels.FirstOrDefault(c => c.Id == channel.Id) ?? channel); + if (!channel.Joined.Value) + { + // we received this from the server so should mark the channel already joined. + channel.Joined.Value = true; + + JoinChannel(channel); + } + } + + 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 From c77412992e14fe504eafd91a9288761fbd5d7022 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 14 Nov 2018 11:53:34 +0900 Subject: [PATCH 147/155] Merge conditionals --- osu.Game/Overlays/MusicController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index 77a3ae88a4..cb86ad8083 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -247,7 +247,7 @@ namespace osu.Game.Overlays var track = (current?.TrackLoaded ?? false) ? current.Track : null; - if (track != null && !track.IsDummyDevice) + if (track?.IsDummyDevice == false) { progressBar.EndTime = track.Length; progressBar.CurrentTime = track.CurrentTime; From b9278b3488de78c1dafb2b6c2722935d4a900664 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 14 Nov 2018 12:05:07 +0900 Subject: [PATCH 148/155] Fix brackets --- osu.Game/Overlays/MusicController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index cb86ad8083..f282b757cd 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -245,7 +245,7 @@ namespace osu.Game.Overlays { base.Update(); - var track = (current?.TrackLoaded ?? false) ? current.Track : null; + var track = current?.TrackLoaded ?? false ? current.Track : null; if (track?.IsDummyDevice == false) { From c4769f6802eef8d9659a2ddcf0aaaae1af7134b5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 14 Nov 2018 13:19:20 +0900 Subject: [PATCH 149/155] Refactors --- .../API/Requests/GetPrivateMessagesRequest.cs | 17 ----------------- osu.Game/Online/Chat/ChannelManager.cs | 11 +++-------- 2 files changed, 3 insertions(+), 25 deletions(-) delete mode 100644 osu.Game/Online/API/Requests/GetPrivateMessagesRequest.cs diff --git a/osu.Game/Online/API/Requests/GetPrivateMessagesRequest.cs b/osu.Game/Online/API/Requests/GetPrivateMessagesRequest.cs deleted file mode 100644 index dddcbe8939..0000000000 --- a/osu.Game/Online/API/Requests/GetPrivateMessagesRequest.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -namespace osu.Game.Online.API.Requests -{ - public class GetPrivateMessagesRequest : APIMessagesRequest - { - private long? since; - - public GetPrivateMessagesRequest(long? sinceId = null) - : base(sinceId) - { - } - - protected override string Target => @"chat/messages/private"; - } -} diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 71b1d8a80a..1b6a347372 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -66,8 +66,7 @@ namespace osu.Game.Online.Chat if (name == null) throw new ArgumentNullException(nameof(name)); - CurrentChannel.Value = AvailableChannels.FirstOrDefault(c => c.Name == name) - ?? throw new ChannelNotFoundException(name); + CurrentChannel.Value = AvailableChannels.FirstOrDefault(c => c.Name == name) ?? throw new ChannelNotFoundException(name); } /// @@ -83,11 +82,7 @@ namespace osu.Game.Online.Chat ?? new Channel { Name = user.Username, Users = { user } }; } - private void currentChannelChanged(Channel channel) - { - JoinChannel(channel); - } - + private void currentChannelChanged(Channel channel) => JoinChannel(channel); /// /// Ensure we run post actions in sequence, once at a time. @@ -258,7 +253,7 @@ namespace osu.Game.Online.Chat fetchInitialMsgReq.Success += messages => { handleChannelMessages(messages); - channel.MessagesLoaded = true; // this will mark the channel as having received messages even if tehre were none. + channel.MessagesLoaded = true; // this will mark the channel as having received messages even if there were none. }; api.Queue(fetchInitialMsgReq); From 9a9d5e60af8ab932a96937db6c04235d150cd4c2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 14 Nov 2018 13:59:02 +0900 Subject: [PATCH 150/155] More refactors --- osu.Game/Online/Chat/ChannelManager.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 1b6a347372..9014fce18d 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -46,8 +46,6 @@ namespace osu.Game.Online.Chat /// public ObservableCollection AvailableChannels { get; } = new ObservableCollection(); //todo: should be publicly readonly - /*private readonly IncomingMessagesHandler privateMessagesHandler;*/ - private IAPIProvider api; private ScheduledDelegate fetchMessagesScheduleder; @@ -130,12 +128,14 @@ namespace osu.Game.Online.Chat if (currentChannel.Type == ChannelType.PM && !currentChannel.Joined) { var createNewPrivateMessageRequest = new CreateNewPrivateMessageRequest(currentChannel.Users.First(), message); + createNewPrivateMessageRequest.Success += createRes => { currentChannel.Id = createRes.ChannelID; currentChannel.ReplaceMessage(message, createRes.Message); dequeueAndRun(); }; + createNewPrivateMessageRequest.Failure += exception => { Logger.Error(exception, "Posting message failed."); @@ -148,17 +148,20 @@ namespace osu.Game.Online.Chat } var req = new PostMessageRequest(message); + req.Success += m => { currentChannel.ReplaceMessage(message, m); dequeueAndRun(); }; + req.Failure += exception => { Logger.Error(exception, "Posting message failed."); currentChannel.ReplaceMessage(message, null); dequeueAndRun(); }; + api.Queue(req); }); From 7274908059cf73016a87d03c620bf5cfe04f2517 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 14 Nov 2018 15:33:09 +0900 Subject: [PATCH 151/155] Implement interface --- osu.Game/Tests/Visual/ScrollingTestContainer.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Tests/Visual/ScrollingTestContainer.cs b/osu.Game/Tests/Visual/ScrollingTestContainer.cs index 18b29345c1..1819fdb2a0 100644 --- a/osu.Game/Tests/Visual/ScrollingTestContainer.cs +++ b/osu.Game/Tests/Visual/ScrollingTestContainer.cs @@ -85,6 +85,9 @@ namespace osu.Game.Tests.Visual public float PositionAt(double time, double currentTime, double timeRange, float scrollLength) => implementation.PositionAt(time, currentTime, timeRange, scrollLength); + public double TimeAt(float position, double currentTime, double timeRange, float scrollLength) + => implementation.TimeAt(position, currentTime, timeRange, scrollLength); + public void Reset() => implementation.Reset(); } From aff5fa6169ac2c01099a0887b6ab365ceb9c7512 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 14 Nov 2018 18:02:38 +0900 Subject: [PATCH 152/155] Update with osu!-side dropdown changes --- .../Graphics/UserInterface/OsuEnumDropdown.cs | 16 +------- osu.Game/Overlays/Music/FilterControl.cs | 3 +- .../Sections/Audio/AudioDevicesSettings.cs | 22 +++++++--- .../Sections/Graphics/LayoutSettings.cs | 40 +++++++++++++----- .../Overlays/Settings/Sections/SkinSection.cs | 41 ++++++++++++++----- .../Overlays/Settings/SettingsDropdown.cs | 35 +++++++++------- .../Overlays/Settings/SettingsEnumDropdown.cs | 13 ++++-- .../Play/PlayerSettings/CollectionSettings.cs | 3 +- 8 files changed, 109 insertions(+), 64 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuEnumDropdown.cs b/osu.Game/Graphics/UserInterface/OsuEnumDropdown.cs index 502f468ec9..5c6a2a0569 100644 --- a/osu.Game/Graphics/UserInterface/OsuEnumDropdown.cs +++ b/osu.Game/Graphics/UserInterface/OsuEnumDropdown.cs @@ -2,9 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; -using System.ComponentModel; -using System.Reflection; -using System.Collections.Generic; namespace osu.Game.Graphics.UserInterface { @@ -15,18 +12,7 @@ namespace osu.Game.Graphics.UserInterface if (!typeof(T).IsEnum) throw new InvalidOperationException("OsuEnumDropdown only supports enums as the generic type argument"); - List> items = new List>(); - foreach (var val in (T[])Enum.GetValues(typeof(T))) - { - var field = typeof(T).GetField(Enum.GetName(typeof(T), val)); - items.Add( - new KeyValuePair( - field.GetCustomAttribute()?.Description ?? Enum.GetName(typeof(T), val), - val - ) - ); - } - Items = items; + Items = (T[])Enum.GetValues(typeof(T)); } } } diff --git a/osu.Game/Overlays/Music/FilterControl.cs b/osu.Game/Overlays/Music/FilterControl.cs index 2d492dcf1e..e4807baeb4 100644 --- a/osu.Game/Overlays/Music/FilterControl.cs +++ b/osu.Game/Overlays/Music/FilterControl.cs @@ -1,7 +1,6 @@ // 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 osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -37,7 +36,7 @@ namespace osu.Game.Overlays.Music new CollectionsDropdown { RelativeSizeAxes = Axes.X, - Items = new[] { new KeyValuePair(@"All", PlaylistCollection.All) }, + Items = new[] { PlaylistCollection.All }, } }, }, diff --git a/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs b/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs index d637eb96f6..ad79024f62 100644 --- a/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs @@ -6,6 +6,7 @@ using osu.Framework.Audio; using osu.Framework.Graphics; using System.Collections.Generic; using System.Linq; +using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.Settings.Sections.Audio { @@ -35,12 +36,12 @@ namespace osu.Game.Overlays.Settings.Sections.Audio private void updateItems() { - var deviceItems = new List> { new KeyValuePair("Default", string.Empty) }; - deviceItems.AddRange(audio.AudioDeviceNames.Select(d => new KeyValuePair(d, d))); + var deviceItems = new List { string.Empty }; + deviceItems.AddRange(audio.AudioDeviceNames); var preferredDeviceName = audio.AudioDevice.Value; - if (deviceItems.All(kv => kv.Value != preferredDeviceName)) - deviceItems.Add(new KeyValuePair(preferredDeviceName, preferredDeviceName)); + if (deviceItems.All(kv => kv != preferredDeviceName)) + deviceItems.Add(preferredDeviceName); // The option dropdown for audio device selection lists all audio // device names. Dropdowns, however, may not have multiple identical @@ -59,7 +60,7 @@ namespace osu.Game.Overlays.Settings.Sections.Audio Children = new Drawable[] { - dropdown = new SettingsDropdown() + dropdown = new AudioDeviceSettingsDropdown() }; updateItems(); @@ -69,5 +70,16 @@ namespace osu.Game.Overlays.Settings.Sections.Audio audio.OnNewDevice += onDeviceChanged; audio.OnLostDevice += onDeviceChanged; } + + private class AudioDeviceSettingsDropdown : SettingsDropdown + { + protected override OsuDropdown CreateDropdown() => new AudioDeviceDropdownControl { Items = Items }; + + private class AudioDeviceDropdownControl : DropdownControl + { + protected override string GenerateItemText(string item) + => string.IsNullOrEmpty(item) ? "Default" : base.GenerateItemText(item); + } + } } } diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs index 254de6c6f7..685244e06b 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs @@ -6,9 +6,9 @@ using System.Drawing; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Configuration; -using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.Settings.Sections.Graphics { @@ -85,7 +85,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics if (resolutions.Count > 1) { - resolutionSettingsContainer.Child = resolutionDropdown = new SettingsDropdown + resolutionSettingsContainer.Child = resolutionDropdown = new ResolutionSettingsDropdown { LabelText = "Resolution", ShowsDefaultIndicator = false, @@ -115,18 +115,36 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics }, true); } - private IReadOnlyList> getResolutions() + private IReadOnlyList getResolutions() { - var resolutions = new KeyValuePair("Default", new Size(9999, 9999)).Yield(); + var resolutions = new List { new Size(9999, 9999) }; if (game.Window != null) - resolutions = resolutions.Concat(game.Window.AvailableResolutions - .Where(r => r.Width >= 800 && r.Height >= 600) - .OrderByDescending(r => r.Width) - .ThenByDescending(r => r.Height) - .Select(res => new KeyValuePair($"{res.Width}x{res.Height}", new Size(res.Width, res.Height))) - .Distinct()); - return resolutions.ToList(); + { + resolutions.AddRange(game.Window.AvailableResolutions + .Where(r => r.Width >= 800 && r.Height >= 600) + .OrderByDescending(r => r.Width) + .ThenByDescending(r => r.Height) + .Select(res => new Size(res.Width, res.Height)) + .Distinct()); + } + + return resolutions; + } + + private class ResolutionSettingsDropdown : SettingsDropdown + { + protected override OsuDropdown CreateDropdown() => new ResolutionDropdownControl { Items = Items }; + + private class ResolutionDropdownControl : DropdownControl + { + protected override string GenerateItemText(Size item) + { + if (item == new Size(9999, 9999)) + return "Default"; + return $"{item.Width}x{item.Height}"; + } + } } } } diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index 15787d29f7..f8ea65c8ae 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -1,9 +1,9 @@ // 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 System.Linq; using osu.Framework.Allocation; +using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Game.Configuration; using osu.Game.Graphics; @@ -15,12 +15,15 @@ namespace osu.Game.Overlays.Settings.Sections { public class SkinSection : SettingsSection { - private SettingsDropdown skinDropdown; + private SkinSettingsDropdown skinDropdown; public override string Header => "Skin"; public override FontAwesome Icon => FontAwesome.fa_paint_brush; + private readonly Bindable dropdownBindable = new Bindable(); + private readonly Bindable configBindable = new Bindable(); + private SkinManager skins; [BackgroundDependencyLoader] @@ -31,7 +34,7 @@ namespace osu.Game.Overlays.Settings.Sections FlowContent.Spacing = new Vector2(0, 5); Children = new Drawable[] { - skinDropdown = new SettingsDropdown(), + skinDropdown = new SkinSettingsDropdown(), new SettingsSlider { LabelText = "Menu cursor size", @@ -54,19 +57,21 @@ namespace osu.Game.Overlays.Settings.Sections skins.ItemAdded += itemAdded; skins.ItemRemoved += itemRemoved; - skinDropdown.Items = skins.GetAllUsableSkins().Select(s => new KeyValuePair(s.ToString(), s.ID)); + config.BindWith(OsuSetting.Skin, configBindable); - var skinBindable = config.GetBindable(OsuSetting.Skin); + skinDropdown.Bindable = dropdownBindable; + skinDropdown.Items = skins.GetAllUsableSkins().Select(s => new SkinDescription { Id = s.ID, Name = s.ToString() }).ToArray(); // Todo: This should not be necessary when OsuConfigManager is databased - if (skinDropdown.Items.All(s => s.Value != skinBindable.Value)) - skinBindable.Value = 0; + if (skinDropdown.Items.All(s => s.Id != configBindable.Value)) + configBindable.Value = 0; - skinDropdown.Bindable = skinBindable; + configBindable.BindValueChanged(v => dropdownBindable.Value = skinDropdown.Items.Single(s => s.Id == v), true); + dropdownBindable.BindValueChanged(v => configBindable.Value = v.Id); } - private void itemRemoved(SkinInfo s) => skinDropdown.Items = skinDropdown.Items.Where(i => i.Value != s.ID); - private void itemAdded(SkinInfo s) => skinDropdown.Items = skinDropdown.Items.Append(new KeyValuePair(s.ToString(), s.ID)); + private void itemRemoved(SkinInfo s) => skinDropdown.Items = skinDropdown.Items.Where(i => i.Id != s.ID).ToArray(); + private void itemAdded(SkinInfo s) => skinDropdown.Items = skinDropdown.Items.Append(new SkinDescription { Id = s.ID, Name = s.ToString() }).ToArray(); protected override void Dispose(bool isDisposing) { @@ -83,5 +88,21 @@ namespace osu.Game.Overlays.Settings.Sections { public override string TooltipText => Current.Value.ToString(@"0.##x"); } + + private class SkinSettingsDropdown : SettingsDropdown + { + protected override OsuDropdown CreateDropdown() => new SkinDropdownControl { Items = Items }; + + private class SkinDropdownControl : DropdownControl + { + protected override string GenerateItemText(SkinDescription item) => item.Name; + } + } + + private struct SkinDescription + { + public int Id; + public string Name; + } } } diff --git a/osu.Game/Overlays/Settings/SettingsDropdown.cs b/osu.Game/Overlays/Settings/SettingsDropdown.cs index 33a8af7d91..1c3eb6c245 100644 --- a/osu.Game/Overlays/Settings/SettingsDropdown.cs +++ b/osu.Game/Overlays/Settings/SettingsDropdown.cs @@ -2,36 +2,41 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System.Collections.Generic; +using System.Linq; using osu.Framework.Graphics; -using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.Settings { public class SettingsDropdown : SettingsItem { - private Dropdown dropdown; + protected new OsuDropdown Control => (OsuDropdown)base.Control; - private IEnumerable> items = new KeyValuePair[] { }; - public IEnumerable> Items + private IEnumerable items = Enumerable.Empty(); + + public IEnumerable Items { - get - { - return items; - } + get => items; set { items = value; - if (dropdown != null) - dropdown.Items = value; + + if (Control != null) + Control.Items = value; } } - protected override Drawable CreateControl() => dropdown = new OsuDropdown + protected sealed override Drawable CreateControl() => CreateDropdown(); + + protected virtual OsuDropdown CreateDropdown() => new DropdownControl { Items = Items }; + + protected class DropdownControl : OsuDropdown { - Margin = new MarginPadding { Top = 5 }, - RelativeSizeAxes = Axes.X, - Items = Items, - }; + public DropdownControl() + { + Margin = new MarginPadding { Top = 5 }; + RelativeSizeAxes = Axes.X; + } + } } } diff --git a/osu.Game/Overlays/Settings/SettingsEnumDropdown.cs b/osu.Game/Overlays/Settings/SettingsEnumDropdown.cs index 64811137a6..2a98b80816 100644 --- a/osu.Game/Overlays/Settings/SettingsEnumDropdown.cs +++ b/osu.Game/Overlays/Settings/SettingsEnumDropdown.cs @@ -8,10 +8,15 @@ namespace osu.Game.Overlays.Settings { public class SettingsEnumDropdown : SettingsDropdown { - protected override Drawable CreateControl() => new OsuEnumDropdown + protected override OsuDropdown CreateDropdown() => new DropdownControl(); + + protected class DropdownControl : OsuEnumDropdown { - Margin = new MarginPadding { Top = 5 }, - RelativeSizeAxes = Axes.X, - }; + public DropdownControl() + { + Margin = new MarginPadding { Top = 5 }; + RelativeSizeAxes = Axes.X; + } + } } } diff --git a/osu.Game/Screens/Play/PlayerSettings/CollectionSettings.cs b/osu.Game/Screens/Play/PlayerSettings/CollectionSettings.cs index 9a654d3bfd..da47de8a9b 100644 --- a/osu.Game/Screens/Play/PlayerSettings/CollectionSettings.cs +++ b/osu.Game/Screens/Play/PlayerSettings/CollectionSettings.cs @@ -1,7 +1,6 @@ // 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 osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Graphics.Sprites; @@ -25,7 +24,7 @@ namespace osu.Game.Screens.Play.PlayerSettings new CollectionsDropdown { RelativeSizeAxes = Axes.X, - Items = new[] { new KeyValuePair(@"All", PlaylistCollection.All) }, + Items = new[] { PlaylistCollection.All }, }, }; } From c963fc7cd2e9293d2dc313fa925946940ec9ffdf Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 14 Nov 2018 18:34:13 +0900 Subject: [PATCH 153/155] Reduce chaining --- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 37 +++++++++++++------ .../Compose/Components/BlueprintContainer.cs | 14 +------ 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 8e2905a4df..86ecbc0bb0 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -8,6 +8,7 @@ using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Input; using osu.Framework.Logging; using osu.Framework.Timing; using osu.Game.Beatmaps; @@ -23,7 +24,7 @@ namespace osu.Game.Rulesets.Edit { public abstract class HitObjectComposer : CompositeDrawable { - public IEnumerable HitObjects => RulesetContainer.Playfield.AllHitObjects; + public IEnumerable HitObjects => rulesetContainer.Playfield.AllHitObjects; protected readonly Ruleset Ruleset; @@ -33,10 +34,12 @@ namespace osu.Game.Rulesets.Edit private readonly List layerContainers = new List(); - public EditRulesetContainer RulesetContainer { get; private set; } + private EditRulesetContainer rulesetContainer; private BlueprintContainer blueprintContainer; + private InputManager inputManager; + internal HitObjectComposer(Ruleset ruleset) { Ruleset = ruleset; @@ -51,8 +54,8 @@ namespace osu.Game.Rulesets.Edit try { - RulesetContainer = CreateRulesetContainer(); - RulesetContainer.Clock = framedClock; + rulesetContainer = CreateRulesetContainer(); + rulesetContainer.Clock = framedClock; } catch (Exception e) { @@ -94,7 +97,7 @@ namespace osu.Game.Rulesets.Edit Children = new Drawable[] { layerBelowRuleset, - RulesetContainer, + rulesetContainer, layerAboveRuleset } } @@ -114,6 +117,13 @@ namespace osu.Game.Rulesets.Edit toolboxCollection.Items[0].Select(); } + protected override void LoadComplete() + { + base.LoadComplete(); + + inputManager = GetContainingInputManager(); + } + protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) { var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); @@ -130,20 +140,25 @@ namespace osu.Game.Rulesets.Edit layerContainers.ForEach(l => { - l.Anchor = RulesetContainer.Playfield.Anchor; - l.Origin = RulesetContainer.Playfield.Origin; - l.Position = RulesetContainer.Playfield.Position; - l.Size = RulesetContainer.Playfield.Size; + l.Anchor = rulesetContainer.Playfield.Anchor; + l.Origin = rulesetContainer.Playfield.Origin; + l.Position = rulesetContainer.Playfield.Position; + l.Size = rulesetContainer.Playfield.Size; }); } + /// + /// Whether the user's cursor is currently in an area of the that is valid for placement. + /// + public virtual bool CursorInPlacementArea => rulesetContainer.Playfield.ReceivePositionalInputAt(inputManager.CurrentState.Mouse.Position); + /// /// Adds a to the and visualises it. /// /// The to add. - public void Add(HitObject hitObject) => blueprintContainer.AddBlueprintFor(RulesetContainer.Add(hitObject)); + public void Add(HitObject hitObject) => blueprintContainer.AddBlueprintFor(rulesetContainer.Add(hitObject)); - public void Remove(HitObject hitObject) => blueprintContainer.RemoveBlueprintFor(RulesetContainer.Remove(hitObject)); + public void Remove(HitObject hitObject) => blueprintContainer.RemoveBlueprintFor(rulesetContainer.Remove(hitObject)); internal abstract EditRulesetContainer CreateRulesetContainer(); diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index 54c9efe463..1623ef0100 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -7,7 +7,6 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Primitives; -using osu.Framework.Input; using osu.Framework.Input.Events; using osu.Framework.Input.States; using osu.Game.Rulesets.Edit; @@ -30,8 +29,6 @@ namespace osu.Game.Screens.Edit.Compose.Components [Resolved] private HitObjectComposer composer { get; set; } - private InputManager inputManager; - public BlueprintContainer() { RelativeSizeAxes = Axes.Both; @@ -59,13 +56,6 @@ namespace osu.Game.Screens.Edit.Compose.Components AddBlueprintFor(obj); } - protected override void LoadComplete() - { - base.LoadComplete(); - - inputManager = GetContainingInputManager(); - } - private HitObjectCompositionTool currentTool; /// @@ -136,9 +126,7 @@ namespace osu.Game.Screens.Edit.Compose.Components if (currentPlacement != null) { - bool cursorInPlayfield = composer.RulesetContainer.Playfield.ReceivePositionalInputAt(inputManager.CurrentState.Mouse.Position); - - if (cursorInPlayfield) + if (composer.CursorInPlacementArea) currentPlacement.State = PlacementState.Shown; else if (currentPlacement?.PlacementBegun == false) currentPlacement.State = PlacementState.Hidden; From f1f2fc133a3b1446766441c009b9845fb4780a92 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 14 Nov 2018 19:29:20 +0900 Subject: [PATCH 154/155] Use SkinInfo directly --- .../Overlays/Settings/Sections/SkinSection.cs | 26 +++++++------------ osu.Game/osu.Game.csproj | 2 +- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index f8ea65c8ae..af7864836b 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -21,7 +21,7 @@ namespace osu.Game.Overlays.Settings.Sections public override FontAwesome Icon => FontAwesome.fa_paint_brush; - private readonly Bindable dropdownBindable = new Bindable(); + private readonly Bindable dropdownBindable = new Bindable(); private readonly Bindable configBindable = new Bindable(); private SkinManager skins; @@ -60,18 +60,18 @@ namespace osu.Game.Overlays.Settings.Sections config.BindWith(OsuSetting.Skin, configBindable); skinDropdown.Bindable = dropdownBindable; - skinDropdown.Items = skins.GetAllUsableSkins().Select(s => new SkinDescription { Id = s.ID, Name = s.ToString() }).ToArray(); + skinDropdown.Items = skins.GetAllUsableSkins().ToArray(); // Todo: This should not be necessary when OsuConfigManager is databased - if (skinDropdown.Items.All(s => s.Id != configBindable.Value)) + if (skinDropdown.Items.All(s => s.ID != configBindable.Value)) configBindable.Value = 0; - configBindable.BindValueChanged(v => dropdownBindable.Value = skinDropdown.Items.Single(s => s.Id == v), true); - dropdownBindable.BindValueChanged(v => configBindable.Value = v.Id); + configBindable.BindValueChanged(v => dropdownBindable.Value = skinDropdown.Items.Single(s => s.ID == v), true); + dropdownBindable.BindValueChanged(v => configBindable.Value = v.ID); } - private void itemRemoved(SkinInfo s) => skinDropdown.Items = skinDropdown.Items.Where(i => i.Id != s.ID).ToArray(); - private void itemAdded(SkinInfo s) => skinDropdown.Items = skinDropdown.Items.Append(new SkinDescription { Id = s.ID, Name = s.ToString() }).ToArray(); + private void itemRemoved(SkinInfo s) => skinDropdown.Items = skinDropdown.Items.Where(i => i.ID != s.ID).ToArray(); + private void itemAdded(SkinInfo s) => skinDropdown.Items = skinDropdown.Items.Append(s).ToArray(); protected override void Dispose(bool isDisposing) { @@ -89,20 +89,14 @@ namespace osu.Game.Overlays.Settings.Sections public override string TooltipText => Current.Value.ToString(@"0.##x"); } - private class SkinSettingsDropdown : SettingsDropdown + private class SkinSettingsDropdown : SettingsDropdown { - protected override OsuDropdown CreateDropdown() => new SkinDropdownControl { Items = Items }; + protected override OsuDropdown CreateDropdown() => new SkinDropdownControl { Items = Items }; private class SkinDropdownControl : DropdownControl { - protected override string GenerateItemText(SkinDescription item) => item.Name; + protected override string GenerateItemText(SkinInfo item) => item.ToString(); } } - - private struct SkinDescription - { - public int Id; - public string Name; - } } } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 9f7996a5fd..5f11e4293d 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -18,7 +18,7 @@ - + From caaa5645e3720fe45b9eba2404d61e88f3d2f82e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 14 Nov 2018 20:04:03 +0900 Subject: [PATCH 155/155] Correct framework version --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 5f11e4293d..8c47df654a 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -18,7 +18,7 @@ - +