From 56de6c10670199f6d0633e3bd59720610bd1376d Mon Sep 17 00:00:00 2001 From: miterosan Date: Wed, 28 Mar 2018 21:11:06 +0200 Subject: [PATCH 001/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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/333] 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 4a5a453c7f442cfddf5a166c260051bf0f0bec39 Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 23 Jul 2018 21:28:56 +0200 Subject: [PATCH 053/333] Create an inital cake buildscript --- .gitignore | 4 + build.cake | 47 +++++++++ build.ps1 | 236 ++++++++++++++++++++++++++++++++++++++++++ build.sh | 117 +++++++++++++++++++++ cake.config | 2 + tools/packages.config | 4 + 6 files changed, 410 insertions(+) create mode 100644 build.cake create mode 100644 build.ps1 create mode 100644 build.sh create mode 100644 cake.config create mode 100644 tools/packages.config diff --git a/.gitignore b/.gitignore index 5138e940ed..be43e1a79c 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,10 @@ # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs +### Cake ### +tools/* +!tools/packages.config + # Build results bin/[Dd]ebug/ [Dd]ebugPublic/ diff --git a/build.cake b/build.cake new file mode 100644 index 0000000000..ca005279ad --- /dev/null +++ b/build.cake @@ -0,0 +1,47 @@ +#tool Microsoft.TestPlatform.Portable + +/////////////////////////////////////////////////////////////////////////////// +// ARGUMENTS +/////////////////////////////////////////////////////////////////////////////// + +var target = Argument("target", "Test"); +var framework = Argument("framework", "net471"); +var configuration = Argument("configuration", "Debug"); + +var osuDesktop = new FilePath("./osu.Desktop/osu.Desktop.csproj"); + +var testProjects = new [] { + new FilePath("./osu.Game.Tests/osu.Game.Tests.csproj"), + new FilePath("./osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj"), + new FilePath("./osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj"), + new FilePath("./osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj"), + new FilePath("./osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj"), +}; + +/////////////////////////////////////////////////////////////////////////////// +// TASKS +/////////////////////////////////////////////////////////////////////////////// + +Task("Compile") +.Does(() => { + DotNetCoreBuild(osuDesktop.FullPath, new DotNetCoreBuildSettings { + Framework = framework, + Configuration = "Debug" + }); +}); + +Task("CompileTests") +.DoesForEach(testProjects, testProject => { + DotNetCoreBuild(testProject.FullPath, new DotNetCoreBuildSettings { + Framework = framework + }); +}); + + +Task("Test") +.IsDependentOn("CompileTests") +.Does(() => { + VSTest($"./*.Tests/bin/{configuration}/{framework}/**/*Tests.exe"); +}); + +RunTarget(target); \ No newline at end of file diff --git a/build.ps1 b/build.ps1 new file mode 100644 index 0000000000..dc42c4595a --- /dev/null +++ b/build.ps1 @@ -0,0 +1,236 @@ +########################################################################## +# This is the Cake bootstrapper script for PowerShell. +# This file was downloaded from https://github.com/cake-build/resources +# Feel free to change this file to fit your needs. +########################################################################## + +<# + +.SYNOPSIS +This is a Powershell script to bootstrap a Cake build. + +.DESCRIPTION +This Powershell script will download NuGet if missing, restore NuGet tools (including Cake) +and execute your Cake build script with the parameters you provide. + +.PARAMETER Script +The build script to execute. +.PARAMETER Target +The build script target to run. +.PARAMETER Configuration +The build configuration to use. +.PARAMETER Verbosity +Specifies the amount of information to be displayed. +.PARAMETER ShowDescription +Shows description about tasks. +.PARAMETER DryRun +Performs a dry run. +.PARAMETER Experimental +Uses the nightly builds of the Roslyn script engine. +.PARAMETER Mono +Uses the Mono Compiler rather than the Roslyn script engine. +.PARAMETER SkipToolPackageRestore +Skips restoring of packages. +.PARAMETER ScriptArgs +Remaining arguments are added here. + +.LINK +https://cakebuild.net + +#> + +[CmdletBinding()] +Param( + [string]$Script = "build.cake", + [string]$Target, + [string]$Configuration, + [ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")] + [string]$Verbosity, + [switch]$ShowDescription, + [Alias("WhatIf", "Noop")] + [switch]$DryRun, + [switch]$Experimental, + [switch]$Mono, + [switch]$SkipToolPackageRestore, + [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)] + [string[]]$ScriptArgs +) + +[Reflection.Assembly]::LoadWithPartialName("System.Security") | Out-Null +function MD5HashFile([string] $filePath) +{ + if ([string]::IsNullOrEmpty($filePath) -or !(Test-Path $filePath -PathType Leaf)) + { + return $null + } + + [System.IO.Stream] $file = $null; + [System.Security.Cryptography.MD5] $md5 = $null; + try + { + $md5 = [System.Security.Cryptography.MD5]::Create() + $file = [System.IO.File]::OpenRead($filePath) + return [System.BitConverter]::ToString($md5.ComputeHash($file)) + } + finally + { + if ($file -ne $null) + { + $file.Dispose() + } + } +} + +function GetProxyEnabledWebClient +{ + $wc = New-Object System.Net.WebClient + $proxy = [System.Net.WebRequest]::GetSystemWebProxy() + $proxy.Credentials = [System.Net.CredentialCache]::DefaultCredentials + $wc.Proxy = $proxy + return $wc +} + +Write-Host "Preparing to run build script..." + +if(!$PSScriptRoot){ + $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent +} + +$TOOLS_DIR = Join-Path $PSScriptRoot "tools" +$ADDINS_DIR = Join-Path $TOOLS_DIR "Addins" +$MODULES_DIR = Join-Path $TOOLS_DIR "Modules" +$NUGET_EXE = Join-Path $TOOLS_DIR "nuget.exe" +$CAKE_EXE = Join-Path $TOOLS_DIR "Cake/Cake.exe" +$NUGET_URL = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" +$PACKAGES_CONFIG = Join-Path $TOOLS_DIR "packages.config" +$PACKAGES_CONFIG_MD5 = Join-Path $TOOLS_DIR "packages.config.md5sum" +$ADDINS_PACKAGES_CONFIG = Join-Path $ADDINS_DIR "packages.config" +$MODULES_PACKAGES_CONFIG = Join-Path $MODULES_DIR "packages.config" + +# Make sure tools folder exists +if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) { + Write-Verbose -Message "Creating tools directory..." + New-Item -Path $TOOLS_DIR -Type directory | out-null +} + +# Make sure that packages.config exist. +if (!(Test-Path $PACKAGES_CONFIG)) { + Write-Verbose -Message "Downloading packages.config..." + try { + $wc = GetProxyEnabledWebClient + $wc.DownloadFile("https://cakebuild.net/download/bootstrapper/packages", $PACKAGES_CONFIG) + } catch { + Throw "Could not download packages.config." + } +} + +# Try find NuGet.exe in path if not exists +if (!(Test-Path $NUGET_EXE)) { + Write-Verbose -Message "Trying to find nuget.exe in PATH..." + $existingPaths = $Env:Path -Split ';' | Where-Object { (![string]::IsNullOrEmpty($_)) -and (Test-Path $_ -PathType Container) } + $NUGET_EXE_IN_PATH = Get-ChildItem -Path $existingPaths -Filter "nuget.exe" | Select -First 1 + if ($NUGET_EXE_IN_PATH -ne $null -and (Test-Path $NUGET_EXE_IN_PATH.FullName)) { + Write-Verbose -Message "Found in PATH at $($NUGET_EXE_IN_PATH.FullName)." + $NUGET_EXE = $NUGET_EXE_IN_PATH.FullName + } +} + +# Try download NuGet.exe if not exists +if (!(Test-Path $NUGET_EXE)) { + Write-Verbose -Message "Downloading NuGet.exe..." + try { + $wc = GetProxyEnabledWebClient + $wc.DownloadFile($NUGET_URL, $NUGET_EXE) + } catch { + Throw "Could not download NuGet.exe." + } +} + +# Save nuget.exe path to environment to be available to child processed +$ENV:NUGET_EXE = $NUGET_EXE + +# Restore tools from NuGet? +if(-Not $SkipToolPackageRestore.IsPresent) { + Push-Location + Set-Location $TOOLS_DIR + + # Check for changes in packages.config and remove installed tools if true. + [string] $md5Hash = MD5HashFile($PACKAGES_CONFIG) + if((!(Test-Path $PACKAGES_CONFIG_MD5)) -Or + ($md5Hash -ne (Get-Content $PACKAGES_CONFIG_MD5 ))) { + Write-Verbose -Message "Missing or changed package.config hash..." + Get-ChildItem -Exclude packages.config,nuget.exe,Cake.Bakery | + Remove-Item -Recurse + } + + Write-Verbose -Message "Restoring tools from NuGet..." + $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$TOOLS_DIR`"" + + if ($LASTEXITCODE -ne 0) { + Throw "An error occurred while restoring NuGet tools." + } + else + { + $md5Hash | Out-File $PACKAGES_CONFIG_MD5 -Encoding "ASCII" + } + Write-Verbose -Message ($NuGetOutput | out-string) + + Pop-Location +} + +# Restore addins from NuGet +if (Test-Path $ADDINS_PACKAGES_CONFIG) { + Push-Location + Set-Location $ADDINS_DIR + + Write-Verbose -Message "Restoring addins from NuGet..." + $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$ADDINS_DIR`"" + + if ($LASTEXITCODE -ne 0) { + Throw "An error occurred while restoring NuGet addins." + } + + Write-Verbose -Message ($NuGetOutput | out-string) + + Pop-Location +} + +# Restore modules from NuGet +if (Test-Path $MODULES_PACKAGES_CONFIG) { + Push-Location + Set-Location $MODULES_DIR + + Write-Verbose -Message "Restoring modules from NuGet..." + $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$MODULES_DIR`"" + + if ($LASTEXITCODE -ne 0) { + Throw "An error occurred while restoring NuGet modules." + } + + Write-Verbose -Message ($NuGetOutput | out-string) + + Pop-Location +} + +# Make sure that Cake has been installed. +if (!(Test-Path $CAKE_EXE)) { + Throw "Could not find Cake.exe at $CAKE_EXE" +} + + + +# Build Cake arguments +$cakeArguments = @("$Script"); +if ($Target) { $cakeArguments += "-target=$Target" } +if ($Configuration) { $cakeArguments += "-configuration=$Configuration" } +if ($Verbosity) { $cakeArguments += "-verbosity=$Verbosity" } +if ($ShowDescription) { $cakeArguments += "-showdescription" } +if ($DryRun) { $cakeArguments += "-dryrun" } +if ($Experimental) { $cakeArguments += "-experimental" } +if ($Mono) { $cakeArguments += "-mono" } +$cakeArguments += $ScriptArgs + +# Start Cake +Write-Host "Running build script..." +&$CAKE_EXE $cakeArguments +exit $LASTEXITCODE diff --git a/build.sh b/build.sh new file mode 100644 index 0000000000..b9e12527f1 --- /dev/null +++ b/build.sh @@ -0,0 +1,117 @@ +#!/usr/bin/env bash + +########################################################################## +# This is the Cake bootstrapper script for Linux and OS X. +# This file was downloaded from https://github.com/cake-build/resources +# Feel free to change this file to fit your needs. +########################################################################## + +# Define directories. +SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) +TOOLS_DIR=$SCRIPT_DIR/tools +ADDINS_DIR=$TOOLS_DIR/Addins +MODULES_DIR=$TOOLS_DIR/Modules +NUGET_EXE=$TOOLS_DIR/nuget.exe +CAKE_EXE=$TOOLS_DIR/Cake/Cake.exe +PACKAGES_CONFIG=$TOOLS_DIR/packages.config +PACKAGES_CONFIG_MD5=$TOOLS_DIR/packages.config.md5sum +ADDINS_PACKAGES_CONFIG=$ADDINS_DIR/packages.config +MODULES_PACKAGES_CONFIG=$MODULES_DIR/packages.config + +# Define md5sum or md5 depending on Linux/OSX +MD5_EXE= +if [[ "$(uname -s)" == "Darwin" ]]; then + MD5_EXE="md5 -r" +else + MD5_EXE="md5sum" +fi + +# Define default arguments. +SCRIPT="build.cake" +CAKE_ARGUMENTS=() + +# Parse arguments. +for i in "$@"; do + case $1 in + -s|--script) SCRIPT="$2"; shift ;; + --) shift; CAKE_ARGUMENTS+=("$@"); break ;; + *) CAKE_ARGUMENTS+=("$1") ;; + esac + shift +done + +# Make sure the tools folder exist. +if [ ! -d "$TOOLS_DIR" ]; then + mkdir "$TOOLS_DIR" +fi + +# Make sure that packages.config exist. +if [ ! -f "$TOOLS_DIR/packages.config" ]; then + echo "Downloading packages.config..." + curl -Lsfo "$TOOLS_DIR/packages.config" https://cakebuild.net/download/bootstrapper/packages + if [ $? -ne 0 ]; then + echo "An error occurred while downloading packages.config." + exit 1 + fi +fi + +# Download NuGet if it does not exist. +if [ ! -f "$NUGET_EXE" ]; then + echo "Downloading NuGet..." + curl -Lsfo "$NUGET_EXE" https://dist.nuget.org/win-x86-commandline/latest/nuget.exe + if [ $? -ne 0 ]; then + echo "An error occurred while downloading nuget.exe." + exit 1 + fi +fi + +# Restore tools from NuGet. +pushd "$TOOLS_DIR" >/dev/null +if [ ! -f "$PACKAGES_CONFIG_MD5" ] || [ "$( cat "$PACKAGES_CONFIG_MD5" | sed 's/\r$//' )" != "$( $MD5_EXE "$PACKAGES_CONFIG" | awk '{ print $1 }' )" ]; then + find . -type d ! -name . ! -name 'Cake.Bakery' | xargs rm -rf +fi + +mono "$NUGET_EXE" install -ExcludeVersion +if [ $? -ne 0 ]; then + echo "Could not restore NuGet tools." + exit 1 +fi + +$MD5_EXE "$PACKAGES_CONFIG" | awk '{ print $1 }' >| "$PACKAGES_CONFIG_MD5" + +popd >/dev/null + +# Restore addins from NuGet. +if [ -f "$ADDINS_PACKAGES_CONFIG" ]; then + pushd "$ADDINS_DIR" >/dev/null + + mono "$NUGET_EXE" install -ExcludeVersion + if [ $? -ne 0 ]; then + echo "Could not restore NuGet addins." + exit 1 + fi + + popd >/dev/null +fi + +# Restore modules from NuGet. +if [ -f "$MODULES_PACKAGES_CONFIG" ]; then + pushd "$MODULES_DIR" >/dev/null + + mono "$NUGET_EXE" install -ExcludeVersion + if [ $? -ne 0 ]; then + echo "Could not restore NuGet modules." + exit 1 + fi + + popd >/dev/null +fi + +# Make sure that Cake has been installed. +if [ ! -f "$CAKE_EXE" ]; then + echo "Could not find Cake.exe at '$CAKE_EXE'." + exit 1 +fi + +# Start Cake +exec mono "$CAKE_EXE" $SCRIPT "${CAKE_ARGUMENTS[@]}" diff --git a/cake.config b/cake.config new file mode 100644 index 0000000000..9dbafb5e95 --- /dev/null +++ b/cake.config @@ -0,0 +1,2 @@ +[Nuget] +UseInProcessClient=false \ No newline at end of file diff --git a/tools/packages.config b/tools/packages.config new file mode 100644 index 0000000000..227ecd9e52 --- /dev/null +++ b/tools/packages.config @@ -0,0 +1,4 @@ + + + + From d9611dcffbf2de4dad02e90146e79033266562c3 Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 23 Jul 2018 22:06:40 +0200 Subject: [PATCH 054/333] 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 055/333] 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 056/333] 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 057/333] 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 058/333] 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 059/333] 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 060/333] 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 061/333] 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 062/333] 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 063/333] 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 064/333] 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 065/333] 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 066/333] 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 067/333] 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 068/333] 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 91ca245c584921864a44f15b9c8934147c53d469 Mon Sep 17 00:00:00 2001 From: miterosan Date: Thu, 26 Jul 2018 03:40:28 +0200 Subject: [PATCH 069/333] Allow testing --- build.cake | 39 ++++++++++++++++----------------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/build.cake b/build.cake index ca005279ad..07d2e7df03 100644 --- a/build.cake +++ b/build.cake @@ -1,22 +1,14 @@ -#tool Microsoft.TestPlatform.Portable - /////////////////////////////////////////////////////////////////////////////// // ARGUMENTS /////////////////////////////////////////////////////////////////////////////// -var target = Argument("target", "Test"); +var target = Argument("target", "Build"); var framework = Argument("framework", "net471"); -var configuration = Argument("configuration", "Debug"); +var configuration = Argument("configuration", "Release"); var osuDesktop = new FilePath("./osu.Desktop/osu.Desktop.csproj"); -var testProjects = new [] { - new FilePath("./osu.Game.Tests/osu.Game.Tests.csproj"), - new FilePath("./osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj"), - new FilePath("./osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj"), - new FilePath("./osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj"), - new FilePath("./osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj"), -}; +var testProjects = GetFiles("**/*.Tests.csproj"); /////////////////////////////////////////////////////////////////////////////// // TASKS @@ -26,22 +18,23 @@ Task("Compile") .Does(() => { DotNetCoreBuild(osuDesktop.FullPath, new DotNetCoreBuildSettings { Framework = framework, - Configuration = "Debug" + Configuration = configuration }); }); -Task("CompileTests") -.DoesForEach(testProjects, testProject => { - DotNetCoreBuild(testProject.FullPath, new DotNetCoreBuildSettings { - Framework = framework - }); -}); - - Task("Test") -.IsDependentOn("CompileTests") -.Does(() => { - VSTest($"./*.Tests/bin/{configuration}/{framework}/**/*Tests.exe"); +.ContinueOnError() +.DoesForEach(testProjects, testProject => { + DotNetCoreTest(testProject.FullPath, new DotNetCoreTestSettings {3 + Framework = framework, + Configuration = configuration, + Logger = $"trx;LogFileName={testProject.GetFilename()}.trx", + ResultsDirectory = "./TestResults/" + }); }); +Task("Build") +.IsDependentOn("Compile") +.IsDependentOn("Test"); + RunTarget(target); \ No newline at end of file From 6a661d1766e473e0a013cafe5b227a7723f59a59 Mon Sep 17 00:00:00 2001 From: miterosan Date: Sun, 29 Jul 2018 20:49:26 +0200 Subject: [PATCH 070/333] Prepare inspect code --- build.cake | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/build.cake b/build.cake index 07d2e7df03..98ad292d7b 100644 --- a/build.cake +++ b/build.cake @@ -1,3 +1,5 @@ +#tool "nuget:?package=JetBrains.ReSharper.CommandLineTools" + /////////////////////////////////////////////////////////////////////////////// // ARGUMENTS /////////////////////////////////////////////////////////////////////////////// @@ -25,7 +27,7 @@ Task("Compile") Task("Test") .ContinueOnError() .DoesForEach(testProjects, testProject => { - DotNetCoreTest(testProject.FullPath, new DotNetCoreTestSettings {3 + DotNetCoreTest(testProject.FullPath, new DotNetCoreTestSettings { Framework = framework, Configuration = configuration, Logger = $"trx;LogFileName={testProject.GetFilename()}.trx", @@ -33,6 +35,11 @@ Task("Test") }); }); +Task("InspectCode") +.Does(() => { + +}); + Task("Build") .IsDependentOn("Compile") .IsDependentOn("Test"); From 95cb21299a30a89113bb482fb26f49ba8490a453 Mon Sep 17 00:00:00 2001 From: miterosan Date: Sun, 29 Jul 2018 21:18:37 +0200 Subject: [PATCH 071/333] 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 072/333] 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 073/333] 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 aef824b13dda77cad2c27946106a8b87e24a3df3 Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 30 Jul 2018 02:12:39 +0200 Subject: [PATCH 074/333] Also analyze the code for spaces and warnings. --- .gitignore | 1 + appveyor.yml | 22 +++------------------- build.cake | 22 ++++++++++++++++++++-- cake.config | 2 -- inspectcodereport.xml | 18 ++++++++++++++++++ 5 files changed, 42 insertions(+), 23 deletions(-) delete mode 100644 cake.config create mode 100644 inspectcodereport.xml diff --git a/.gitignore b/.gitignore index be43e1a79c..26a8752b66 100644 --- a/.gitignore +++ b/.gitignore @@ -102,6 +102,7 @@ $tf/ _ReSharper*/ *.[Rr]e[Ss]harper *.DotSettings.user +inspectcode # JustCode is a .NET coding add-in .JustCode diff --git a/appveyor.yml b/appveyor.yml index 7c08eb9e9c..68c6725d0c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,24 +1,8 @@ clone_depth: 1 version: '{branch}-{build}' image: Visual Studio 2017 -configuration: Debug -cache: - - C:\ProgramData\chocolatey\bin -> appveyor.yml - - C:\ProgramData\chocolatey\lib -> appveyor.yml +test: off install: - cmd: git submodule update --init --recursive --depth=5 - - cmd: choco install resharper-clt -y - - cmd: choco install nvika -y - - cmd: appveyor DownloadFile https://github.com/peppy/CodeFileSanity/releases/download/v0.2.5/CodeFileSanity.exe -before_build: - - cmd: CodeFileSanity.exe - - cmd: nuget restore -verbosity quiet -environment: - TargetFramework: net471 -build: - project: osu.sln - parallel: true - verbosity: minimal -after_build: - - cmd: inspectcode --o="inspectcodereport.xml" --projects:osu.Game* --caches-home="inspectcode" osu.sln > NUL - - cmd: NVika parsereport "inspectcodereport.xml" --treatwarningsaserrors +build_script: +- cmd: PowerShell -Version 2.0 .\build.ps1 diff --git a/build.cake b/build.cake index 98ad292d7b..6d11aade77 100644 --- a/build.cake +++ b/build.cake @@ -1,4 +1,7 @@ #tool "nuget:?package=JetBrains.ReSharper.CommandLineTools" +#tool "nuget:?package=NVika.MSBuild" +var NVikaToolPath = GetFiles("./tools/NVika.MSBuild.*/tools/NVika.exe").First(); +var CodeFileSanityToolPath = DownloadFile("https://github.com/peppy/CodeFileSanity/releases/download/v0.2.5/CodeFileSanity.exe"); /////////////////////////////////////////////////////////////////////////////// // ARGUMENTS @@ -9,7 +12,7 @@ var framework = Argument("framework", "net471"); var configuration = Argument("configuration", "Release"); var osuDesktop = new FilePath("./osu.Desktop/osu.Desktop.csproj"); - +var osuSolution = new FilePath("./osu.sln"); var testProjects = GetFiles("**/*.Tests.csproj"); /////////////////////////////////////////////////////////////////////////////// @@ -37,11 +40,26 @@ Task("Test") Task("InspectCode") .Does(() => { - + InspectCode(osuSolution, new InspectCodeSettings { + CachesHome = "inspectcode", + OutputFile = "inspectcodereport.xml", + }); + + StartProcess(NVikaToolPath, @"parsereport ""inspectcodereport.xml"" --treatwarningsaserrors"); +}); + +Task("CodeFileSanity") +.Does(() => { + var result = StartProcess(CodeFileSanityToolPath); + + if (result != 0) + throw new Exception("Code sanity failed."); }); Task("Build") +.IsDependentOn("CodeFileSanity") .IsDependentOn("Compile") +.IsDependentOn("InspectCode") .IsDependentOn("Test"); RunTarget(target); \ No newline at end of file diff --git a/cake.config b/cake.config deleted file mode 100644 index 9dbafb5e95..0000000000 --- a/cake.config +++ /dev/null @@ -1,2 +0,0 @@ -[Nuget] -UseInProcessClient=false \ No newline at end of file diff --git a/inspectcodereport.xml b/inspectcodereport.xml new file mode 100644 index 0000000000..f4b531f547 --- /dev/null +++ b/inspectcodereport.xml @@ -0,0 +1,18 @@ + + + + + osu.sln + + Solution + + + + + + + + + + + \ No newline at end of file From 8652c48c1801421fbe65369322d1845551198ce3 Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 30 Jul 2018 02:23:31 +0200 Subject: [PATCH 075/333] Restore nuget before analyzing the binaries. --- build.cake | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build.cake b/build.cake index 6d11aade77..304037f486 100644 --- a/build.cake +++ b/build.cake @@ -38,7 +38,11 @@ Task("Test") }); }); +Task("Restore Nuget") +.Does(() => NuGetRestore(osuSolution)); + Task("InspectCode") +.IsDependentOn("Restore Nuget") .Does(() => { InspectCode(osuSolution, new InspectCodeSettings { CachesHome = "inspectcode", From 9e477140c1ca3e8c012ea2ca4d805886fcbc0948 Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 30 Jul 2018 21:45:15 +0200 Subject: [PATCH 076/333] Build against netcoreapp2.1 instead of net471 --- build.cake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.cake b/build.cake index 304037f486..6f512b8628 100644 --- a/build.cake +++ b/build.cake @@ -8,7 +8,7 @@ var CodeFileSanityToolPath = DownloadFile("https://github.com/peppy/CodeFileSani /////////////////////////////////////////////////////////////////////////////// var target = Argument("target", "Build"); -var framework = Argument("framework", "net471"); +var framework = Argument("framework", "netcoreapp2.1"); var configuration = Argument("configuration", "Release"); var osuDesktop = new FilePath("./osu.Desktop/osu.Desktop.csproj"); From 1b779dae779a469f80d42cbe91c903e0a2bd562c Mon Sep 17 00:00:00 2001 From: miterosan Date: Sat, 4 Aug 2018 00:01:17 +0200 Subject: [PATCH 077/333] Use CodeFileSanity as a cake addin. --- build.cake | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/build.cake b/build.cake index 6f512b8628..160db5148e 100644 --- a/build.cake +++ b/build.cake @@ -1,7 +1,7 @@ #tool "nuget:?package=JetBrains.ReSharper.CommandLineTools" #tool "nuget:?package=NVika.MSBuild" +#addin "nuget:?package=CodeFileSanity" var NVikaToolPath = GetFiles("./tools/NVika.MSBuild.*/tools/NVika.exe").First(); -var CodeFileSanityToolPath = DownloadFile("https://github.com/peppy/CodeFileSanity/releases/download/v0.2.5/CodeFileSanity.exe"); /////////////////////////////////////////////////////////////////////////////// // ARGUMENTS @@ -54,10 +54,10 @@ Task("InspectCode") Task("CodeFileSanity") .Does(() => { - var result = StartProcess(CodeFileSanityToolPath); - - if (result != 0) - throw new Exception("Code sanity failed."); + ValidateCodeSanity(new ValidateCodeSanitySettings { + RootDirectory = ".", + IsAppveyorBuild = AppVeyor.IsRunningOnAppVeyor + }); }); Task("Build") From 309e74afac74dfb7420e69995e5173ba832389f4 Mon Sep 17 00:00:00 2001 From: miterosan Date: Sat, 4 Aug 2018 00:02:31 +0200 Subject: [PATCH 078/333] Move compile to the correct task. The dotnetcore... commands all contain compiling. --- build.cake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.cake b/build.cake index 160db5148e..e945115570 100644 --- a/build.cake +++ b/build.cake @@ -43,6 +43,7 @@ Task("Restore Nuget") Task("InspectCode") .IsDependentOn("Restore Nuget") +.IsDependentOn("Compile") .Does(() => { InspectCode(osuSolution, new InspectCodeSettings { CachesHome = "inspectcode", @@ -62,7 +63,6 @@ Task("CodeFileSanity") Task("Build") .IsDependentOn("CodeFileSanity") -.IsDependentOn("Compile") .IsDependentOn("InspectCode") .IsDependentOn("Test"); From 2ce64104a40a4cdd0554697e74d5201de19c560c Mon Sep 17 00:00:00 2001 From: miterosan Date: Sat, 4 Aug 2018 00:03:03 +0200 Subject: [PATCH 079/333] :V JetBrains.ReSharper.CommandLineTools is an addin and not a tool --- build.cake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.cake b/build.cake index e945115570..20b2685351 100644 --- a/build.cake +++ b/build.cake @@ -1,4 +1,4 @@ -#tool "nuget:?package=JetBrains.ReSharper.CommandLineTools" +#addin "nuget:?package=JetBrains.ReSharper.CommandLineTools" #tool "nuget:?package=NVika.MSBuild" #addin "nuget:?package=CodeFileSanity" var NVikaToolPath = GetFiles("./tools/NVika.MSBuild.*/tools/NVika.exe").First(); From 358c3469238e6abf73c43b2e76c3161a5aecdb86 Mon Sep 17 00:00:00 2001 From: miterosan Date: Sat, 4 Aug 2018 00:44:16 +0200 Subject: [PATCH 080/333] 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 081/333] 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 e69e225ad3332808a0a5b325b7206772f78e2bee Mon Sep 17 00:00:00 2001 From: miterosan Date: Sun, 5 Aug 2018 21:08:11 +0200 Subject: [PATCH 082/333] Use coreclr instead of .framework. --- tools/packages.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/packages.config b/tools/packages.config index 227ecd9e52..e37e9304d5 100644 --- a/tools/packages.config +++ b/tools/packages.config @@ -1,4 +1,4 @@ - + From abe10741e6892344b7691ef7fceaa1f3b2648728 Mon Sep 17 00:00:00 2001 From: miterosan Date: Sun, 5 Aug 2018 21:45:14 +0200 Subject: [PATCH 083/333] Use netcore cake --- build.ps1 | 168 ++---------------------------------------------------- 1 file changed, 5 insertions(+), 163 deletions(-) diff --git a/build.ps1 b/build.ps1 index dc42c4595a..e923331793 100644 --- a/build.ps1 +++ b/build.ps1 @@ -25,12 +25,6 @@ Specifies the amount of information to be displayed. Shows description about tasks. .PARAMETER DryRun Performs a dry run. -.PARAMETER Experimental -Uses the nightly builds of the Roslyn script engine. -.PARAMETER Mono -Uses the Mono Compiler rather than the Roslyn script engine. -.PARAMETER SkipToolPackageRestore -Skips restoring of packages. .PARAMETER ScriptArgs Remaining arguments are added here. @@ -49,47 +43,10 @@ Param( [switch]$ShowDescription, [Alias("WhatIf", "Noop")] [switch]$DryRun, - [switch]$Experimental, - [switch]$Mono, - [switch]$SkipToolPackageRestore, [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)] [string[]]$ScriptArgs ) -[Reflection.Assembly]::LoadWithPartialName("System.Security") | Out-Null -function MD5HashFile([string] $filePath) -{ - if ([string]::IsNullOrEmpty($filePath) -or !(Test-Path $filePath -PathType Leaf)) - { - return $null - } - - [System.IO.Stream] $file = $null; - [System.Security.Cryptography.MD5] $md5 = $null; - try - { - $md5 = [System.Security.Cryptography.MD5]::Create() - $file = [System.IO.File]::OpenRead($filePath) - return [System.BitConverter]::ToString($md5.ComputeHash($file)) - } - finally - { - if ($file -ne $null) - { - $file.Dispose() - } - } -} - -function GetProxyEnabledWebClient -{ - $wc = New-Object System.Net.WebClient - $proxy = [System.Net.WebRequest]::GetSystemWebProxy() - $proxy.Credentials = [System.Net.CredentialCache]::DefaultCredentials - $wc.Proxy = $proxy - return $wc -} - Write-Host "Preparing to run build script..." if(!$PSScriptRoot){ @@ -97,127 +54,12 @@ if(!$PSScriptRoot){ } $TOOLS_DIR = Join-Path $PSScriptRoot "tools" -$ADDINS_DIR = Join-Path $TOOLS_DIR "Addins" -$MODULES_DIR = Join-Path $TOOLS_DIR "Modules" -$NUGET_EXE = Join-Path $TOOLS_DIR "nuget.exe" -$CAKE_EXE = Join-Path $TOOLS_DIR "Cake/Cake.exe" -$NUGET_URL = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" -$PACKAGES_CONFIG = Join-Path $TOOLS_DIR "packages.config" -$PACKAGES_CONFIG_MD5 = Join-Path $TOOLS_DIR "packages.config.md5sum" -$ADDINS_PACKAGES_CONFIG = Join-Path $ADDINS_DIR "packages.config" -$MODULES_PACKAGES_CONFIG = Join-Path $MODULES_DIR "packages.config" - -# Make sure tools folder exists -if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) { - Write-Verbose -Message "Creating tools directory..." - New-Item -Path $TOOLS_DIR -Type directory | out-null -} - -# Make sure that packages.config exist. -if (!(Test-Path $PACKAGES_CONFIG)) { - Write-Verbose -Message "Downloading packages.config..." - try { - $wc = GetProxyEnabledWebClient - $wc.DownloadFile("https://cakebuild.net/download/bootstrapper/packages", $PACKAGES_CONFIG) - } catch { - Throw "Could not download packages.config." - } -} - -# Try find NuGet.exe in path if not exists -if (!(Test-Path $NUGET_EXE)) { - Write-Verbose -Message "Trying to find nuget.exe in PATH..." - $existingPaths = $Env:Path -Split ';' | Where-Object { (![string]::IsNullOrEmpty($_)) -and (Test-Path $_ -PathType Container) } - $NUGET_EXE_IN_PATH = Get-ChildItem -Path $existingPaths -Filter "nuget.exe" | Select -First 1 - if ($NUGET_EXE_IN_PATH -ne $null -and (Test-Path $NUGET_EXE_IN_PATH.FullName)) { - Write-Verbose -Message "Found in PATH at $($NUGET_EXE_IN_PATH.FullName)." - $NUGET_EXE = $NUGET_EXE_IN_PATH.FullName - } -} - -# Try download NuGet.exe if not exists -if (!(Test-Path $NUGET_EXE)) { - Write-Verbose -Message "Downloading NuGet.exe..." - try { - $wc = GetProxyEnabledWebClient - $wc.DownloadFile($NUGET_URL, $NUGET_EXE) - } catch { - Throw "Could not download NuGet.exe." - } -} - -# Save nuget.exe path to environment to be available to child processed -$ENV:NUGET_EXE = $NUGET_EXE - -# Restore tools from NuGet? -if(-Not $SkipToolPackageRestore.IsPresent) { - Push-Location - Set-Location $TOOLS_DIR - - # Check for changes in packages.config and remove installed tools if true. - [string] $md5Hash = MD5HashFile($PACKAGES_CONFIG) - if((!(Test-Path $PACKAGES_CONFIG_MD5)) -Or - ($md5Hash -ne (Get-Content $PACKAGES_CONFIG_MD5 ))) { - Write-Verbose -Message "Missing or changed package.config hash..." - Get-ChildItem -Exclude packages.config,nuget.exe,Cake.Bakery | - Remove-Item -Recurse - } - - Write-Verbose -Message "Restoring tools from NuGet..." - $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$TOOLS_DIR`"" - - if ($LASTEXITCODE -ne 0) { - Throw "An error occurred while restoring NuGet tools." - } - else - { - $md5Hash | Out-File $PACKAGES_CONFIG_MD5 -Encoding "ASCII" - } - Write-Verbose -Message ($NuGetOutput | out-string) - - Pop-Location -} - -# Restore addins from NuGet -if (Test-Path $ADDINS_PACKAGES_CONFIG) { - Push-Location - Set-Location $ADDINS_DIR - - Write-Verbose -Message "Restoring addins from NuGet..." - $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$ADDINS_DIR`"" - - if ($LASTEXITCODE -ne 0) { - Throw "An error occurred while restoring NuGet addins." - } - - Write-Verbose -Message ($NuGetOutput | out-string) - - Pop-Location -} - -# Restore modules from NuGet -if (Test-Path $MODULES_PACKAGES_CONFIG) { - Push-Location - Set-Location $MODULES_DIR - - Write-Verbose -Message "Restoring modules from NuGet..." - $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$MODULES_DIR`"" - - if ($LASTEXITCODE -ne 0) { - Throw "An error occurred while restoring NuGet modules." - } - - Write-Verbose -Message ($NuGetOutput | out-string) - - Pop-Location -} - -# Make sure that Cake has been installed. -if (!(Test-Path $CAKE_EXE)) { - Throw "Could not find Cake.exe at $CAKE_EXE" -} +$CAKE_CSPROJ = Join-Path $TOOLS_DIR "cake.csproj" +Invoke-Expression "dotnet restore `"$CAKE_CSPROJ`" --packages `"$TOOLS_DIR`"" +# Find the Cake executable +$CAKE_EXECUTABLE = (Get-ChildItem -Path ./tools/cake.coreclr/ -Filter Cake.dll -Recurse).FullName # Build Cake arguments $cakeArguments = @("$Script"); @@ -232,5 +74,5 @@ $cakeArguments += $ScriptArgs # Start Cake Write-Host "Running build script..." -&$CAKE_EXE $cakeArguments +Invoke-Expression "dotnet `"$CAKE_EXECUTABLE`" $cakeArguments" exit $LASTEXITCODE From cefabf14d9418a381c9d4956654c02038c528229 Mon Sep 17 00:00:00 2001 From: miterosan Date: Sun, 5 Aug 2018 21:46:28 +0200 Subject: [PATCH 084/333] Linux users can use powershell on, linux --- build.sh | 117 ------------------------------------------------------- 1 file changed, 117 deletions(-) delete mode 100644 build.sh diff --git a/build.sh b/build.sh deleted file mode 100644 index b9e12527f1..0000000000 --- a/build.sh +++ /dev/null @@ -1,117 +0,0 @@ -#!/usr/bin/env bash - -########################################################################## -# This is the Cake bootstrapper script for Linux and OS X. -# This file was downloaded from https://github.com/cake-build/resources -# Feel free to change this file to fit your needs. -########################################################################## - -# Define directories. -SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) -TOOLS_DIR=$SCRIPT_DIR/tools -ADDINS_DIR=$TOOLS_DIR/Addins -MODULES_DIR=$TOOLS_DIR/Modules -NUGET_EXE=$TOOLS_DIR/nuget.exe -CAKE_EXE=$TOOLS_DIR/Cake/Cake.exe -PACKAGES_CONFIG=$TOOLS_DIR/packages.config -PACKAGES_CONFIG_MD5=$TOOLS_DIR/packages.config.md5sum -ADDINS_PACKAGES_CONFIG=$ADDINS_DIR/packages.config -MODULES_PACKAGES_CONFIG=$MODULES_DIR/packages.config - -# Define md5sum or md5 depending on Linux/OSX -MD5_EXE= -if [[ "$(uname -s)" == "Darwin" ]]; then - MD5_EXE="md5 -r" -else - MD5_EXE="md5sum" -fi - -# Define default arguments. -SCRIPT="build.cake" -CAKE_ARGUMENTS=() - -# Parse arguments. -for i in "$@"; do - case $1 in - -s|--script) SCRIPT="$2"; shift ;; - --) shift; CAKE_ARGUMENTS+=("$@"); break ;; - *) CAKE_ARGUMENTS+=("$1") ;; - esac - shift -done - -# Make sure the tools folder exist. -if [ ! -d "$TOOLS_DIR" ]; then - mkdir "$TOOLS_DIR" -fi - -# Make sure that packages.config exist. -if [ ! -f "$TOOLS_DIR/packages.config" ]; then - echo "Downloading packages.config..." - curl -Lsfo "$TOOLS_DIR/packages.config" https://cakebuild.net/download/bootstrapper/packages - if [ $? -ne 0 ]; then - echo "An error occurred while downloading packages.config." - exit 1 - fi -fi - -# Download NuGet if it does not exist. -if [ ! -f "$NUGET_EXE" ]; then - echo "Downloading NuGet..." - curl -Lsfo "$NUGET_EXE" https://dist.nuget.org/win-x86-commandline/latest/nuget.exe - if [ $? -ne 0 ]; then - echo "An error occurred while downloading nuget.exe." - exit 1 - fi -fi - -# Restore tools from NuGet. -pushd "$TOOLS_DIR" >/dev/null -if [ ! -f "$PACKAGES_CONFIG_MD5" ] || [ "$( cat "$PACKAGES_CONFIG_MD5" | sed 's/\r$//' )" != "$( $MD5_EXE "$PACKAGES_CONFIG" | awk '{ print $1 }' )" ]; then - find . -type d ! -name . ! -name 'Cake.Bakery' | xargs rm -rf -fi - -mono "$NUGET_EXE" install -ExcludeVersion -if [ $? -ne 0 ]; then - echo "Could not restore NuGet tools." - exit 1 -fi - -$MD5_EXE "$PACKAGES_CONFIG" | awk '{ print $1 }' >| "$PACKAGES_CONFIG_MD5" - -popd >/dev/null - -# Restore addins from NuGet. -if [ -f "$ADDINS_PACKAGES_CONFIG" ]; then - pushd "$ADDINS_DIR" >/dev/null - - mono "$NUGET_EXE" install -ExcludeVersion - if [ $? -ne 0 ]; then - echo "Could not restore NuGet addins." - exit 1 - fi - - popd >/dev/null -fi - -# Restore modules from NuGet. -if [ -f "$MODULES_PACKAGES_CONFIG" ]; then - pushd "$MODULES_DIR" >/dev/null - - mono "$NUGET_EXE" install -ExcludeVersion - if [ $? -ne 0 ]; then - echo "Could not restore NuGet modules." - exit 1 - fi - - popd >/dev/null -fi - -# Make sure that Cake has been installed. -if [ ! -f "$CAKE_EXE" ]; then - echo "Could not find Cake.exe at '$CAKE_EXE'." - exit 1 -fi - -# Start Cake -exec mono "$CAKE_EXE" $SCRIPT "${CAKE_ARGUMENTS[@]}" From fce2be9dc7118db2caa6a32729f9fb709d4f68bd Mon Sep 17 00:00:00 2001 From: miterosan Date: Sun, 5 Aug 2018 22:24:52 +0200 Subject: [PATCH 085/333] Allow running inspect core with cakeclr. Sadly window only because nvika and resharper cmd tools require net45. --- build.cake | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/build.cake b/build.cake index 20b2685351..a341e93a0b 100644 --- a/build.cake +++ b/build.cake @@ -1,7 +1,7 @@ +#addin "nuget:?package=CodeFileSanity" #addin "nuget:?package=JetBrains.ReSharper.CommandLineTools" #tool "nuget:?package=NVika.MSBuild" -#addin "nuget:?package=CodeFileSanity" -var NVikaToolPath = GetFiles("./tools/NVika.MSBuild.*/tools/NVika.exe").First(); +#tool "nuget:?package=NuGet.CommandLine" /////////////////////////////////////////////////////////////////////////////// // ARGUMENTS @@ -38,13 +38,17 @@ Task("Test") }); }); -Task("Restore Nuget") -.Does(() => NuGetRestore(osuSolution)); - +// windows only because both inspectcore and nvike depend on net45 +// will be ignored on linux Task("InspectCode") -.IsDependentOn("Restore Nuget") +.WithCriteria(IsRunningOnWindows()) .IsDependentOn("Compile") .Does(() => { + var NVikaToolPath = GetFiles("./tools/NVika.MSBuild.*/tools/NVika.exe").First(); + var NugetToolPath = GetFiles("./tools/NuGet.CommandLine.*/tools/NuGet.exe").First(); + + StartProcess(NugetToolPath, $"restore {osuSolution}"); + InspectCode(osuSolution, new InspectCodeSettings { CachesHome = "inspectcode", OutputFile = "inspectcodereport.xml", From 90c08a447e4741efaa1f0db6a4285c02bab38655 Mon Sep 17 00:00:00 2001 From: miterosan Date: Sun, 5 Aug 2018 22:26:32 +0200 Subject: [PATCH 086/333] Add inspectcodereport to the gitignore --- .gitignore | 2 ++ inspectcodereport.xml | 18 ------------------ 2 files changed, 2 insertions(+), 18 deletions(-) delete mode 100644 inspectcodereport.xml diff --git a/.gitignore b/.gitignore index 26a8752b66..78986dee1d 100644 --- a/.gitignore +++ b/.gitignore @@ -262,3 +262,5 @@ paket-files/ __pycache__/ *.pyc Staging/ + +inspectcodereport.xml diff --git a/inspectcodereport.xml b/inspectcodereport.xml deleted file mode 100644 index f4b531f547..0000000000 --- a/inspectcodereport.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - osu.sln - - Solution - - - - - - - - - - - \ No newline at end of file From b430cf34e73760e136cebc4f87045826b76557be Mon Sep 17 00:00:00 2001 From: miterosan Date: Sun, 5 Aug 2018 22:27:51 +0200 Subject: [PATCH 087/333] remove unfnished comment. --- build.cake | 1 - 1 file changed, 1 deletion(-) diff --git a/build.cake b/build.cake index a341e93a0b..60219d4fb0 100644 --- a/build.cake +++ b/build.cake @@ -39,7 +39,6 @@ Task("Test") }); // windows only because both inspectcore and nvike depend on net45 -// will be ignored on linux Task("InspectCode") .WithCriteria(IsRunningOnWindows()) .IsDependentOn("Compile") From 580d478dc80bafbbe39eede20ff1e9f6dc234dc6 Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 6 Aug 2018 22:50:23 +0200 Subject: [PATCH 088/333] Allow running on mono if possible. (non windows) --- build.cake | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/build.cake b/build.cake index 60219d4fb0..28c314a41b 100644 --- a/build.cake +++ b/build.cake @@ -1,4 +1,4 @@ -#addin "nuget:?package=CodeFileSanity" +#addin "nuget:http://localhost:8081/repository/hm?package=CodeFileSanity&version=1.0.10" #addin "nuget:?package=JetBrains.ReSharper.CommandLineTools" #tool "nuget:?package=NVika.MSBuild" #tool "nuget:?package=NuGet.CommandLine" @@ -38,24 +38,48 @@ Task("Test") }); }); -// windows only because both inspectcore and nvike depend on net45 Task("InspectCode") -.WithCriteria(IsRunningOnWindows()) .IsDependentOn("Compile") .Does(() => { - var NVikaToolPath = GetFiles("./tools/NVika.MSBuild.*/tools/NVika.exe").First(); - var NugetToolPath = GetFiles("./tools/NuGet.CommandLine.*/tools/NuGet.exe").First(); + var nVikaToolPath = GetFiles("./tools/NVika.MSBuild.*/tools/NVika.exe").First(); + var nugetToolPath = GetFiles("./tools/NuGet.CommandLine.*/tools/NuGet.exe").First(); - StartProcess(NugetToolPath, $"restore {osuSolution}"); + if (!IsRunningOnWindows()) { + RunInpectCodeInMono(nVikaToolPath, nugetToolPath); + return; + } + + StartProcess(nugetToolPath, $"restore {osuSolution}"); InspectCode(osuSolution, new InspectCodeSettings { CachesHome = "inspectcode", OutputFile = "inspectcodereport.xml", }); - StartProcess(NVikaToolPath, @"parsereport ""inspectcodereport.xml"" --treatwarningsaserrors"); + StartProcess(nVikaToolPath, @"parsereport ""inspectcodereport.xml"" --treatwarningsaserrors"); }); +void RunInpectCodeInMono(FilePath nugetToolPath, FilePath nVikaToolPath) { + var inspectcodeToolPath = GetFiles("./tools/NuGet.CommandLine.*/tools/NuGet.exe").First(); + + if (!FileExists("mono")) { + Information("Running on an os other than windows and mono is not installed. Skipping InpectCode."); + return; + } + + StartProcess("mono", $"{nugetToolPath} restore {osuSolution}"); + + StartProcess("mono", @"--o=""inspectcodereport.xml"" --caches-home=""inspectcode"" "); + + InspectCode(osuSolution, new InspectCodeSettings { + CachesHome = "inspectcode", + OutputFile = "inspectcodereport.xml", + + }); + + StartProcess("mono", $@"{nVikaToolPath} parsereport ""inspectcodereport.xml"" --treatwarningsaserrors"); +} + Task("CodeFileSanity") .Does(() => { ValidateCodeSanity(new ValidateCodeSanitySettings { From 058a6d9e13b9d91275326fa0508fc776a128df28 Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 6 Aug 2018 23:14:51 +0200 Subject: [PATCH 089/333] Add cake.csproj --- .gitignore | 1 + tools/cake.csproj | 9 +++++++++ 2 files changed, 10 insertions(+) create mode 100644 tools/cake.csproj diff --git a/.gitignore b/.gitignore index 78986dee1d..c75c19f9f5 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ ### Cake ### tools/* !tools/packages.config +!tools/cake.csproj # Build results bin/[Dd]ebug/ diff --git a/tools/cake.csproj b/tools/cake.csproj new file mode 100644 index 0000000000..06692627d2 --- /dev/null +++ b/tools/cake.csproj @@ -0,0 +1,9 @@ + + + Exe + netcoreapp2.0 + + + + + \ No newline at end of file From 2b293add9ecfa22d65dbed2d2b22db68a4c04558 Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 6 Aug 2018 23:36:24 +0200 Subject: [PATCH 090/333] Use the correct tool executable. Better mono detection --- build.cake | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/build.cake b/build.cake index 28c314a41b..98add57062 100644 --- a/build.cake +++ b/build.cake @@ -45,7 +45,7 @@ Task("InspectCode") var nugetToolPath = GetFiles("./tools/NuGet.CommandLine.*/tools/NuGet.exe").First(); if (!IsRunningOnWindows()) { - RunInpectCodeInMono(nVikaToolPath, nugetToolPath); + RunInpectCodeInMono(nugetToolPath, nVikaToolPath); return; } @@ -62,20 +62,14 @@ Task("InspectCode") void RunInpectCodeInMono(FilePath nugetToolPath, FilePath nVikaToolPath) { var inspectcodeToolPath = GetFiles("./tools/NuGet.CommandLine.*/tools/NuGet.exe").First(); - if (!FileExists("mono")) { + if (!StartProcess("mono", "--version") != 0) { Information("Running on an os other than windows and mono is not installed. Skipping InpectCode."); return; } StartProcess("mono", $"{nugetToolPath} restore {osuSolution}"); - StartProcess("mono", @"--o=""inspectcodereport.xml"" --caches-home=""inspectcode"" "); - - InspectCode(osuSolution, new InspectCodeSettings { - CachesHome = "inspectcode", - OutputFile = "inspectcodereport.xml", - - }); + StartProcess("mono", $@"{inspectcodeToolPath} --o=""inspectcodereport.xml"" --caches-home=""inspectcode"" "); StartProcess("mono", $@"{nVikaToolPath} parsereport ""inspectcodereport.xml"" --treatwarningsaserrors"); } From de6c25c052a24beb621a2089a5b1aada6b1d561f Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 6 Aug 2018 23:37:47 +0200 Subject: [PATCH 091/333] rm bad sign --- build.cake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.cake b/build.cake index 98add57062..8fdf04d827 100644 --- a/build.cake +++ b/build.cake @@ -62,7 +62,7 @@ Task("InspectCode") void RunInpectCodeInMono(FilePath nugetToolPath, FilePath nVikaToolPath) { var inspectcodeToolPath = GetFiles("./tools/NuGet.CommandLine.*/tools/NuGet.exe").First(); - if (!StartProcess("mono", "--version") != 0) { + if (StartProcess("mono", "--version") != 0) { Information("Running on an os other than windows and mono is not installed. Skipping InpectCode."); return; } From 8ed8efd06dea56957f2aabfe690654bcac0a5a1a Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 6 Aug 2018 23:46:08 +0200 Subject: [PATCH 092/333] silent the test for mono --- build.cake | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/build.cake b/build.cake index 8fdf04d827..c52523908f 100644 --- a/build.cake +++ b/build.cake @@ -62,7 +62,12 @@ Task("InspectCode") void RunInpectCodeInMono(FilePath nugetToolPath, FilePath nVikaToolPath) { var inspectcodeToolPath = GetFiles("./tools/NuGet.CommandLine.*/tools/NuGet.exe").First(); - if (StartProcess("mono", "--version") != 0) { + var testMonoArguments = new ProcessArgumentBuilder(); + testMonoArguments.AppendSwitch("version", ""); + + if (StartProcess("mono", new ProcessSettings { + Silent = true, Arguments = testMonoArguments } + ) != 0) { Information("Running on an os other than windows and mono is not installed. Skipping InpectCode."); return; } From b98611dd8ffee7db45e4221437661c3637887fd9 Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 6 Aug 2018 23:47:48 +0200 Subject: [PATCH 093/333] minus minus --- build.cake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.cake b/build.cake index c52523908f..4c5eb92948 100644 --- a/build.cake +++ b/build.cake @@ -63,7 +63,7 @@ void RunInpectCodeInMono(FilePath nugetToolPath, FilePath nVikaToolPath) { var inspectcodeToolPath = GetFiles("./tools/NuGet.CommandLine.*/tools/NuGet.exe").First(); var testMonoArguments = new ProcessArgumentBuilder(); - testMonoArguments.AppendSwitch("version", ""); + testMonoArguments.AppendSwitch("--version", ""); if (StartProcess("mono", new ProcessSettings { Silent = true, Arguments = testMonoArguments } From 7c6ae73be1e82c3a4d5de5fce613ffd1a2273953 Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 6 Aug 2018 23:53:09 +0200 Subject: [PATCH 094/333] adjust the path to the commandline tools --- build.cake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.cake b/build.cake index 4c5eb92948..ceebbf3d83 100644 --- a/build.cake +++ b/build.cake @@ -60,7 +60,7 @@ Task("InspectCode") }); void RunInpectCodeInMono(FilePath nugetToolPath, FilePath nVikaToolPath) { - var inspectcodeToolPath = GetFiles("./tools/NuGet.CommandLine.*/tools/NuGet.exe").First(); + var inspectcodeToolPath = GetFiles("./tools/Addins/JetBrains.Resharper.CommandLineTools.*/**/inspectcode.exe").First(); var testMonoArguments = new ProcessArgumentBuilder(); testMonoArguments.AppendSwitch("--version", ""); From 1a03ef13f4dd29556c629907902425206d4df135 Mon Sep 17 00:00:00 2001 From: miterosan Date: Tue, 7 Aug 2018 22:36:52 +0200 Subject: [PATCH 095/333] Revert "Allow running on mono if possible. (non windows)" https://youtrack.jetbrains.com/issue/RSRP-410004 This reverts commit 580d478dc80bafbbe39eede20ff1e9f6dc234dc6. --- build.cake | 29 +++-------------------------- 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/build.cake b/build.cake index ceebbf3d83..6a06f843db 100644 --- a/build.cake +++ b/build.cake @@ -1,4 +1,4 @@ -#addin "nuget:http://localhost:8081/repository/hm?package=CodeFileSanity&version=1.0.10" +#addin "nuget:?package=CodeFileSanity" #addin "nuget:?package=JetBrains.ReSharper.CommandLineTools" #tool "nuget:?package=NVika.MSBuild" #tool "nuget:?package=NuGet.CommandLine" @@ -38,17 +38,14 @@ Task("Test") }); }); +// windows only because both inspectcore and nvika depend on net45 Task("InspectCode") +.WithCriteria(IsRunningOnWindows()) .IsDependentOn("Compile") .Does(() => { var nVikaToolPath = GetFiles("./tools/NVika.MSBuild.*/tools/NVika.exe").First(); var nugetToolPath = GetFiles("./tools/NuGet.CommandLine.*/tools/NuGet.exe").First(); - if (!IsRunningOnWindows()) { - RunInpectCodeInMono(nugetToolPath, nVikaToolPath); - return; - } - StartProcess(nugetToolPath, $"restore {osuSolution}"); InspectCode(osuSolution, new InspectCodeSettings { @@ -59,26 +56,6 @@ Task("InspectCode") StartProcess(nVikaToolPath, @"parsereport ""inspectcodereport.xml"" --treatwarningsaserrors"); }); -void RunInpectCodeInMono(FilePath nugetToolPath, FilePath nVikaToolPath) { - var inspectcodeToolPath = GetFiles("./tools/Addins/JetBrains.Resharper.CommandLineTools.*/**/inspectcode.exe").First(); - - var testMonoArguments = new ProcessArgumentBuilder(); - testMonoArguments.AppendSwitch("--version", ""); - - if (StartProcess("mono", new ProcessSettings { - Silent = true, Arguments = testMonoArguments } - ) != 0) { - Information("Running on an os other than windows and mono is not installed. Skipping InpectCode."); - return; - } - - StartProcess("mono", $"{nugetToolPath} restore {osuSolution}"); - - StartProcess("mono", $@"{inspectcodeToolPath} --o=""inspectcodereport.xml"" --caches-home=""inspectcode"" "); - - StartProcess("mono", $@"{nVikaToolPath} parsereport ""inspectcodereport.xml"" --treatwarningsaserrors"); -} - Task("CodeFileSanity") .Does(() => { ValidateCodeSanity(new ValidateCodeSanitySettings { From 2763f0be6bbc8fbbbc37878f40b9e1ee55422ff7 Mon Sep 17 00:00:00 2001 From: miterosan Date: Thu, 9 Aug 2018 20:45:34 +0200 Subject: [PATCH 096/333] Remove the usage of windows nuget restore and replace it with dotnet restore --- build.cake | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/build.cake b/build.cake index 6a06f843db..6508150a3b 100644 --- a/build.cake +++ b/build.cake @@ -1,7 +1,6 @@ #addin "nuget:?package=CodeFileSanity" #addin "nuget:?package=JetBrains.ReSharper.CommandLineTools" #tool "nuget:?package=NVika.MSBuild" -#tool "nuget:?package=NuGet.CommandLine" /////////////////////////////////////////////////////////////////////////////// // ARGUMENTS @@ -44,9 +43,8 @@ Task("InspectCode") .IsDependentOn("Compile") .Does(() => { var nVikaToolPath = GetFiles("./tools/NVika.MSBuild.*/tools/NVika.exe").First(); - var nugetToolPath = GetFiles("./tools/NuGet.CommandLine.*/tools/NuGet.exe").First(); - - StartProcess(nugetToolPath, $"restore {osuSolution}"); + + DotNetCoreRestore(osuSolution.FullPath); InspectCode(osuSolution, new InspectCodeSettings { CachesHome = "inspectcode", From 119f81b86e560004ae106330172b3887768680b4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Sep 2018 15:56:04 +0900 Subject: [PATCH 097/333] 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 098/333] 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 099/333] 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 100/333] 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 101/333] 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 399d456edb7e06ccd892fbb66aa03439be208c13 Mon Sep 17 00:00:00 2001 From: miterosan Date: Tue, 11 Sep 2018 21:49:10 +0200 Subject: [PATCH 102/333] Pin the addin and tool versions down. --- build.cake | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.cake b/build.cake index 6508150a3b..4f6883cab0 100644 --- a/build.cake +++ b/build.cake @@ -1,6 +1,6 @@ -#addin "nuget:?package=CodeFileSanity" -#addin "nuget:?package=JetBrains.ReSharper.CommandLineTools" -#tool "nuget:?package=NVika.MSBuild" +#addin "nuget:?package=CodeFileSanity&version=0.0.21" +#addin "nuget:?package=JetBrains.ReSharper.CommandLineTools&version=2018.2.2" +#tool "nuget:?package=NVika.MSBuild&version=1.0.1" /////////////////////////////////////////////////////////////////////////////// // ARGUMENTS From 2e91b86e00a47249df5a56f757ed0be0466d78c7 Mon Sep 17 00:00:00 2001 From: miterosan Date: Tue, 11 Sep 2018 22:07:14 +0200 Subject: [PATCH 103/333] Remove Redundant parentheses --- osu.Game/Storyboards/CommandTimeline.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Storyboards/CommandTimeline.cs b/osu.Game/Storyboards/CommandTimeline.cs index 7de0756dbd..8a032064d3 100644 --- a/osu.Game/Storyboards/CommandTimeline.cs +++ b/osu.Game/Storyboards/CommandTimeline.cs @@ -16,10 +16,10 @@ namespace osu.Game.Storyboards public bool HasCommands => commands.Count > 0; private Cached startTimeBacking; - public double StartTime => startTimeBacking.IsValid ? startTimeBacking : (startTimeBacking.Value = HasCommands ? commands.Min(c => c.StartTime) : double.MinValue); + public double StartTime => startTimeBacking.IsValid ? startTimeBacking : startTimeBacking.Value = HasCommands ? commands.Min(c => c.StartTime) : double.MinValue; private Cached endTimeBacking; - public double EndTime => endTimeBacking.IsValid ? endTimeBacking : (endTimeBacking.Value = HasCommands ? commands.Max(c => c.EndTime) : double.MaxValue); + public double EndTime => endTimeBacking.IsValid ? endTimeBacking : endTimeBacking.Value = HasCommands ? commands.Max(c => c.EndTime) : double.MaxValue; public T StartValue => HasCommands ? commands.OrderBy(c => c.StartTime).First().StartValue : default(T); public T EndValue => HasCommands ? commands.OrderByDescending(c => c.EndTime).First().EndValue : default(T); From e20b0849002120c9981312853a68ef8ae9c39821 Mon Sep 17 00:00:00 2001 From: miterosan Date: Tue, 11 Sep 2018 22:11:25 +0200 Subject: [PATCH 104/333] Report the test results to appveyor --- build.cake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.cake b/build.cake index 4f6883cab0..7e1f1bdda7 100644 --- a/build.cake +++ b/build.cake @@ -32,7 +32,7 @@ Task("Test") DotNetCoreTest(testProject.FullPath, new DotNetCoreTestSettings { Framework = framework, Configuration = configuration, - Logger = $"trx;LogFileName={testProject.GetFilename()}.trx", + Logger = AppVeyor.IsRunningOnAppVeyor ? "Appveyor" : $"trx;LogFileName={testProject.GetFilename()}.trx", ResultsDirectory = "./TestResults/" }); }); From 761d7629cd2c5778669dbaf78656b7e3b090aaeb Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Wed, 12 Sep 2018 18:09:19 +0300 Subject: [PATCH 105/333] Return to large logo after idle period --- osu.Game/OsuGame.cs | 6 +++++- osu.Game/Screens/Menu/ButtonSystem.cs | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 6fcb948298..fce11e0a79 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -84,6 +84,9 @@ namespace osu.Game public float ToolbarOffset => Toolbar.Position.Y + Toolbar.DrawHeight; + private InputManager inputManager; + public double IdleTime => inputManager?.IdleTime ?? 0; + public readonly Bindable OverlayActivationMode = new Bindable(); private OsuScreen screenStack; @@ -113,7 +116,7 @@ namespace osu.Game forwardLoggedErrorsToNotifications(); - RavenLogger = new RavenLogger(this); + RavenLogger = new RavenLogger(this); } public void ToggleSettings() => settings.ToggleVisibility(); @@ -446,6 +449,7 @@ namespace osu.Game settings.StateChanged += _ => updateScreenOffset(); notifications.StateChanged += _ => updateScreenOffset(); + inputManager = GetContainingInputManager(); } private void forwardLoggedErrorsToNotifications() diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index b9a799328e..9a21df04d0 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -266,8 +266,8 @@ namespace osu.Game.Screens.Menu protected override void Update() { - //if (OsuGame.IdleTime > 6000 && State != MenuState.Exit) - // State = MenuState.Initial; + if (game.IdleTime > 6000 && State != ButtonSystemState.Exit) + State = ButtonSystemState.Initial; base.Update(); From 749e89bd2549c3c2f605889433d200d1d87a662d Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Wed, 12 Sep 2018 20:34:52 +0300 Subject: [PATCH 106/333] Introduce IdleTracker --- osu.Game/OsuGame.cs | 8 +++--- osu.Game/Screens/Menu/IdleTracker.cs | 37 ++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 4 deletions(-) create mode 100644 osu.Game/Screens/Menu/IdleTracker.cs diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index fce11e0a79..b14650eca0 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -84,8 +84,8 @@ namespace osu.Game public float ToolbarOffset => Toolbar.Position.Y + Toolbar.DrawHeight; - private InputManager inputManager; - public double IdleTime => inputManager?.IdleTime ?? 0; + private IdleTracker idleTracker; + public double IdleTime => idleTracker?.IdleTime ?? 0; public readonly Bindable OverlayActivationMode = new Bindable(); @@ -116,7 +116,7 @@ namespace osu.Game forwardLoggedErrorsToNotifications(); - RavenLogger = new RavenLogger(this); + RavenLogger = new RavenLogger(this); } public void ToggleSettings() => settings.ToggleVisibility(); @@ -321,6 +321,7 @@ namespace osu.Game }, mainContent = new Container { RelativeSizeAxes = Axes.Both }, overlayContent = new Container { RelativeSizeAxes = Axes.Both, Depth = float.MinValue }, + idleTracker = new IdleTracker() { RelativeSizeAxes = Axes.Both } }); loadComponentSingleFile(screenStack = new Loader(), d => @@ -449,7 +450,6 @@ namespace osu.Game settings.StateChanged += _ => updateScreenOffset(); notifications.StateChanged += _ => updateScreenOffset(); - inputManager = GetContainingInputManager(); } private void forwardLoggedErrorsToNotifications() diff --git a/osu.Game/Screens/Menu/IdleTracker.cs b/osu.Game/Screens/Menu/IdleTracker.cs new file mode 100644 index 0000000000..4a3089a76a --- /dev/null +++ b/osu.Game/Screens/Menu/IdleTracker.cs @@ -0,0 +1,37 @@ +// 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.Framework.Input.Bindings; +using osu.Framework.Input.EventArgs; +using osu.Framework.Input.States; + +namespace osu.Game.Screens.Menu +{ + public class IdleTracker : Component, IKeyBindingHandler + { + private double lastInteractionTime; + public double IdleTime => Clock.CurrentTime - lastInteractionTime; + + private bool updateLastInteractionTime() + { + lastInteractionTime = Clock.CurrentTime; + return false; + } + + public bool OnPressed(PlatformAction action) => updateLastInteractionTime(); + + public bool OnReleased(PlatformAction action) => updateLastInteractionTime(); + + protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) => updateLastInteractionTime(); + + protected override bool OnKeyUp(InputState state, KeyUpEventArgs args) => updateLastInteractionTime(); + + protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) => updateLastInteractionTime(); + + protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) => updateLastInteractionTime(); + + protected override bool OnMouseMove(InputState state) => updateLastInteractionTime(); + } +} From 60c0428979054e5cafca7742a5970a24ba6715c8 Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Wed, 12 Sep 2018 20:54:40 +0300 Subject: [PATCH 107/333] Remove redundant empty argument list --- osu.Game/OsuGame.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index b14650eca0..eb5532800f 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -321,7 +321,7 @@ namespace osu.Game }, mainContent = new Container { RelativeSizeAxes = Axes.Both }, overlayContent = new Container { RelativeSizeAxes = Axes.Both, Depth = float.MinValue }, - idleTracker = new IdleTracker() { RelativeSizeAxes = Axes.Both } + idleTracker = new IdleTracker { RelativeSizeAxes = Axes.Both } }); loadComponentSingleFile(screenStack = new Loader(), d => From be1365fb187f5a11117c6ae7f170615827ce8572 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Sep 2018 11:58:23 +0900 Subject: [PATCH 108/333] 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 109/333] 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 03ff695a674787c99ee80a84c3421d2c8ed6c4c0 Mon Sep 17 00:00:00 2001 From: miterosan Date: Sun, 16 Sep 2018 16:25:19 +0200 Subject: [PATCH 110/333] Use Dotnet core VSTest This allows only running one testrun. --- build.cake | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/build.cake b/build.cake index 7e1f1bdda7..6808bb3dfc 100644 --- a/build.cake +++ b/build.cake @@ -12,7 +12,6 @@ var configuration = Argument("configuration", "Release"); var osuDesktop = new FilePath("./osu.Desktop/osu.Desktop.csproj"); var osuSolution = new FilePath("./osu.sln"); -var testProjects = GetFiles("**/*.Tests.csproj"); /////////////////////////////////////////////////////////////////////////////// // TASKS @@ -27,13 +26,13 @@ Task("Compile") }); Task("Test") -.ContinueOnError() -.DoesForEach(testProjects, testProject => { - DotNetCoreTest(testProject.FullPath, new DotNetCoreTestSettings { - Framework = framework, - Configuration = configuration, - Logger = AppVeyor.IsRunningOnAppVeyor ? "Appveyor" : $"trx;LogFileName={testProject.GetFilename()}.trx", - ResultsDirectory = "./TestResults/" +.Does(() => { + var testAssemblies = GetFiles("**/*.Tests/bin/**/*.Tests.dll"); + + DotNetCoreVSTest(testAssemblies, new DotNetCoreVSTestSettings { + Logger = AppVeyor.IsRunningOnAppVeyor ? "Appveyor" : $"trx", + Parallel = true, + ToolTimeout = TimeSpan.FromMinutes(10), }); }); From 0491fd581a4516bf55a1d474de40e893351553cb Mon Sep 17 00:00:00 2001 From: miterosan Date: Sun, 16 Sep 2018 16:25:40 +0200 Subject: [PATCH 111/333] Reduce the verbosity of the Restore. --- build.cake | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build.cake b/build.cake index 6808bb3dfc..9fd1b33f9b 100644 --- a/build.cake +++ b/build.cake @@ -43,7 +43,9 @@ Task("InspectCode") .Does(() => { var nVikaToolPath = GetFiles("./tools/NVika.MSBuild.*/tools/NVika.exe").First(); - DotNetCoreRestore(osuSolution.FullPath); + DotNetCoreRestore(osuSolution.FullPath, new DotNetCoreRestoreSettings { + Verbosity = DotNetCoreVerbosity.Quiet + }); InspectCode(osuSolution, new InspectCodeSettings { CachesHome = "inspectcode", From ead2e388823dc8afb8272a972e21e2b1b478030c Mon Sep 17 00:00:00 2001 From: miterosan Date: Sun, 16 Sep 2018 16:40:40 +0200 Subject: [PATCH 112/333] Build the projects before testing --- build.cake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.cake b/build.cake index 9fd1b33f9b..b8d84b7be6 100644 --- a/build.cake +++ b/build.cake @@ -10,7 +10,6 @@ var target = Argument("target", "Build"); var framework = Argument("framework", "netcoreapp2.1"); var configuration = Argument("configuration", "Release"); -var osuDesktop = new FilePath("./osu.Desktop/osu.Desktop.csproj"); var osuSolution = new FilePath("./osu.sln"); /////////////////////////////////////////////////////////////////////////////// @@ -19,13 +18,14 @@ var osuSolution = new FilePath("./osu.sln"); Task("Compile") .Does(() => { - DotNetCoreBuild(osuDesktop.FullPath, new DotNetCoreBuildSettings { + DotNetCoreBuild(osuSolution.FullPath, new DotNetCoreBuildSettings { Framework = framework, Configuration = configuration }); }); Task("Test") +.IsDependentOn("Compile") .Does(() => { var testAssemblies = GetFiles("**/*.Tests/bin/**/*.Tests.dll"); From 3870980f3e3f25676670ef6c9d608bac9298f289 Mon Sep 17 00:00:00 2001 From: miterosan Date: Sun, 16 Sep 2018 16:57:53 +0200 Subject: [PATCH 113/333] Seperate the compile from restoring. --- build.cake | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/build.cake b/build.cake index b8d84b7be6..fff39079b6 100644 --- a/build.cake +++ b/build.cake @@ -16,11 +16,17 @@ var osuSolution = new FilePath("./osu.sln"); // TASKS /////////////////////////////////////////////////////////////////////////////// +Task("Restore") +.Does(() => { + DotNetCoreRestore(osuSolution.FullPath); +}); + Task("Compile") +.IsDependentOn("Restore") .Does(() => { DotNetCoreBuild(osuSolution.FullPath, new DotNetCoreBuildSettings { - Framework = framework, - Configuration = configuration + Configuration = configuration, + NoRestore = true, }); }); @@ -42,10 +48,6 @@ Task("InspectCode") .IsDependentOn("Compile") .Does(() => { var nVikaToolPath = GetFiles("./tools/NVika.MSBuild.*/tools/NVika.exe").First(); - - DotNetCoreRestore(osuSolution.FullPath, new DotNetCoreRestoreSettings { - Verbosity = DotNetCoreVerbosity.Quiet - }); InspectCode(osuSolution, new InspectCodeSettings { CachesHome = "inspectcode", From 5c741eaa898b5be1d4e339fe61fd94e5e8284167 Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Fri, 21 Sep 2018 17:07:46 +0300 Subject: [PATCH 114/333] Fix possible game nullref --- osu.Game/Screens/Menu/ButtonSystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 9a21df04d0..fa9f6ceb8b 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -266,7 +266,7 @@ namespace osu.Game.Screens.Menu protected override void Update() { - if (game.IdleTime > 6000 && State != ButtonSystemState.Exit) + if (game?.IdleTime > 6000 && State != ButtonSystemState.Exit) State = ButtonSystemState.Initial; base.Update(); From c7b3fa51d537a8451e8deaad71bc4a1a7b498b18 Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Tue, 25 Sep 2018 19:58:50 +0300 Subject: [PATCH 115/333] Inject IdleTracker into ButtonSystem --- osu.Game/OsuGame.cs | 2 +- osu.Game/Screens/Menu/ButtonSystem.cs | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index b12d2a3d3a..4e933f57bc 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -85,7 +85,6 @@ namespace osu.Game public float ToolbarOffset => Toolbar.Position.Y + Toolbar.DrawHeight; private IdleTracker idleTracker; - public double IdleTime => idleTracker?.IdleTime ?? 0; public readonly Bindable OverlayActivationMode = new Bindable(); @@ -378,6 +377,7 @@ namespace osu.Game Depth = -6, }, overlayContent.Add); + dependencies.Cache(idleTracker); dependencies.Cache(settings); dependencies.Cache(onscreenDisplay); dependencies.Cache(social); diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 015557fa82..8082c7b262 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -64,6 +64,8 @@ namespace osu.Game.Screens.Menu private SampleChannel sampleBack; + private IdleTracker idleTracker; + public ButtonSystem() { RelativeSizeAxes = Axes.Both; @@ -102,9 +104,10 @@ namespace osu.Game.Screens.Menu private OsuGame game; [BackgroundDependencyLoader(true)] - private void load(AudioManager audio, OsuGame game) + private void load(AudioManager audio, OsuGame game, IdleTracker idleTracker) { this.game = game; + this.idleTracker = idleTracker; sampleBack = audio.Sample.Get(@"Menu/button-back-select"); } @@ -266,7 +269,7 @@ namespace osu.Game.Screens.Menu protected override void Update() { - if (game?.IdleTime > 6000 && State != ButtonSystemState.Exit) + if (idleTracker.IdleTime > 6000 && State != ButtonSystemState.Exit) State = ButtonSystemState.Initial; base.Update(); From bdba22a576ab635d68affcb51563deaaa6e37125 Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Tue, 25 Sep 2018 20:11:10 +0300 Subject: [PATCH 116/333] Override Handle(UIEvent e) in IdleTracker --- osu.Game/Screens/Menu/IdleTracker.cs | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/osu.Game/Screens/Menu/IdleTracker.cs b/osu.Game/Screens/Menu/IdleTracker.cs index 4a3089a76a..8e7c835823 100644 --- a/osu.Game/Screens/Menu/IdleTracker.cs +++ b/osu.Game/Screens/Menu/IdleTracker.cs @@ -4,8 +4,7 @@ using osu.Framework.Graphics; using osu.Framework.Input; using osu.Framework.Input.Bindings; -using osu.Framework.Input.EventArgs; -using osu.Framework.Input.States; +using osu.Framework.Input.Events; namespace osu.Game.Screens.Menu { @@ -24,14 +23,19 @@ namespace osu.Game.Screens.Menu public bool OnReleased(PlatformAction action) => updateLastInteractionTime(); - protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) => updateLastInteractionTime(); - - protected override bool OnKeyUp(InputState state, KeyUpEventArgs args) => updateLastInteractionTime(); - - protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) => updateLastInteractionTime(); - - protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) => updateLastInteractionTime(); - - protected override bool OnMouseMove(InputState state) => updateLastInteractionTime(); + protected override bool Handle(UIEvent e) + { + switch (e) + { + case KeyDownEvent _: + case KeyUpEvent _: + case MouseDownEvent _: + case MouseUpEvent _: + case MouseMoveEvent _: + return updateLastInteractionTime(); + default: + return base.Handle(e); + } + } } } From baf9e028c30910012c0ca3d5236eb148fbf93c4a Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Wed, 26 Sep 2018 19:44:01 +0300 Subject: [PATCH 117/333] Fix possible idleTracker nullref --- osu.Game/{Screens/Menu => Input}/IdleTracker.cs | 2 +- osu.Game/OsuGame.cs | 1 + osu.Game/Screens/Menu/ButtonSystem.cs | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) rename osu.Game/{Screens/Menu => Input}/IdleTracker.cs (97%) diff --git a/osu.Game/Screens/Menu/IdleTracker.cs b/osu.Game/Input/IdleTracker.cs similarity index 97% rename from osu.Game/Screens/Menu/IdleTracker.cs rename to osu.Game/Input/IdleTracker.cs index 8e7c835823..bbc15fe7af 100644 --- a/osu.Game/Screens/Menu/IdleTracker.cs +++ b/osu.Game/Input/IdleTracker.cs @@ -6,7 +6,7 @@ using osu.Framework.Input; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; -namespace osu.Game.Screens.Menu +namespace osu.Game.Input { public class IdleTracker : Component, IKeyBindingHandler { diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 4e933f57bc..bb721afec4 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -26,6 +26,7 @@ using osu.Framework.Platform; using osu.Framework.Threading; using osu.Game.Beatmaps; using osu.Game.Graphics; +using osu.Game.Input; using osu.Game.Rulesets.Scoring; using osu.Game.Overlays.Notifications; using osu.Game.Rulesets; diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 8082c7b262..d86d7529a8 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -14,6 +14,7 @@ using osu.Framework.Input.Bindings; using osu.Framework.Logging; using osu.Framework.Threading; using osu.Game.Graphics; +using osu.Game.Input; using osu.Game.Input.Bindings; using osu.Game.Overlays; using OpenTK; @@ -269,7 +270,7 @@ namespace osu.Game.Screens.Menu protected override void Update() { - if (idleTracker.IdleTime > 6000 && State != ButtonSystemState.Exit) + if (idleTracker?.IdleTime > 6000 && State != ButtonSystemState.Exit) State = ButtonSystemState.Initial; base.Update(); From b84994e64398dc174d020c7bb2d08d2915823311 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 27 Sep 2018 15:29:22 +0900 Subject: [PATCH 118/333] Make GetTexture return the post-scaled texture --- osu.Game/Skinning/LegacySkin.cs | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index ce7edf8683..58b1117598 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -58,25 +58,29 @@ namespace osu.Game.Skinning break; } - float ratio = 0.72f; // brings sizing roughly in-line with stable - - var texture = GetTexture($"{componentName}@2x"); - if (texture == null) - { - ratio *= 2; - texture = GetTexture(componentName); - } + var texture = GetTexture(componentName); if (texture == null) return null; - return new Sprite - { - Texture = texture, - Scale = new Vector2(ratio), - }; + return new Sprite { Texture = texture }; } - public override Texture GetTexture(string componentName) => Textures.Get(componentName); + public override Texture GetTexture(string componentName) + { + float ratio = 2; + + var texture = Textures.Get($"{componentName}@2x"); + if (texture == null) + { + ratio = 1; + texture = Textures.Get(componentName); + } + + if (texture != null) + texture.ScaleAdjust = ratio / 0.72f; // brings sizing roughly in-line with stable + + return texture; + } public override SampleChannel GetSample(string sampleName) => Samples.Get(sampleName); From 0d8276c5f86a811b49d252271d6781f5ab48b708 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 27 Sep 2018 16:27:11 +0900 Subject: [PATCH 119/333] Implement skinnable sprite text --- .../Objects/Drawables/Pieces/NumberPiece.cs | 12 +++-- osu.Game/Skinning/LegacySkin.cs | 44 ++++++++++++++++++- osu.Game/Skinning/SkinnableDrawable.cs | 29 +++++++----- osu.Game/Skinning/SkinnableSpriteText.cs | 40 +++++++++++++++++ 4 files changed, 104 insertions(+), 21 deletions(-) create mode 100644 osu.Game/Skinning/SkinnableSpriteText.cs diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/NumberPiece.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/NumberPiece.cs index 30140484de..acb3ee92ff 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/NumberPiece.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/NumberPiece.cs @@ -4,7 +4,6 @@ using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Sprites; using osu.Game.Graphics.Sprites; using OpenTK.Graphics; using osu.Framework.Graphics.Shapes; @@ -14,7 +13,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces { public class NumberPiece : Container { - private readonly SpriteText number; + private readonly SkinnableSpriteText number; public string Text { @@ -41,15 +40,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces }, Child = new Box() }, s => s.GetTexture("Play/osu/hitcircle") == null), - number = new OsuSpriteText + number = new SkinnableSpriteText("Play/osu/number-text", _ => new OsuSpriteText { - Text = @"1", Font = @"Venera", UseFullGlyphHeight = false, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, TextSize = 40, - Alpha = 1 + }, restrictSize: false) + { + Text = @"1" } }; } diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 58b1117598..160cc412b4 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -12,7 +12,7 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; using osu.Game.Database; -using OpenTK; +using osu.Game.Graphics.Sprites; namespace osu.Game.Skinning { @@ -56,11 +56,15 @@ namespace osu.Game.Skinning case "Play/Great": componentName = "hit300"; break; + case "Play/osu/number-text": + // Todo: Not necessarily default font + return hasFont("default") ? new LegacySpriteText(Textures, "default") : null; } var texture = GetTexture(componentName); - if (texture == null) return null; + if (texture == null) + return null; return new Sprite { Texture = texture }; } @@ -84,6 +88,8 @@ namespace osu.Game.Skinning public override SampleChannel GetSample(string sampleName) => Samples.Get(sampleName); + private bool hasFont(string fontName) => GetTexture($"{fontName}-0") != null; + protected class LegacySkinResourceStore : IResourceStore where T : INamedFileInfo { @@ -146,5 +152,39 @@ namespace osu.Game.Skinning #endregion } + + private class LegacySpriteText : OsuSpriteText + { + private readonly TextureStore textures; + private readonly string font; + + public LegacySpriteText(TextureStore textures, string font) + { + this.textures = textures; + this.font = font; + + Shadow = false; + UseFullGlyphHeight = false; + } + + protected override Texture GetTextureForCharacter(char c) + { + string textureName = $"{font}-{c}"; + + float ratio = 36; + + var texture = textures.Get($"{textureName}@2x"); + if (texture == null) + { + ratio = 18; + texture = textures.Get(textureName); + } + + if (texture != null) + texture.ScaleAdjust = ratio; + + return texture; + } + } } } diff --git a/osu.Game/Skinning/SkinnableDrawable.cs b/osu.Game/Skinning/SkinnableDrawable.cs index a40c3da82d..9ecd9e647a 100644 --- a/osu.Game/Skinning/SkinnableDrawable.cs +++ b/osu.Game/Skinning/SkinnableDrawable.cs @@ -18,6 +18,8 @@ namespace osu.Game.Skinning public class SkinnableDrawable : SkinReloadableDrawable where T : Drawable { + protected Drawable Drawable { get; private set; } + private readonly Func createDefault; private readonly string componentName; @@ -31,7 +33,8 @@ namespace osu.Game.Skinning /// A function to create the default skin implementation of this element. /// A conditional to decide whether to allow fallback to the default implementation if a skinned element is not present. /// Whether a user-skin drawable should be limited to the size of our parent. - public SkinnableDrawable(string name, Func defaultImplementation, Func allowFallback = null, bool restrictSize = true) : base(allowFallback) + public SkinnableDrawable(string name, Func defaultImplementation, Func allowFallback = null, bool restrictSize = true) + : base(allowFallback) { componentName = name; createDefault = defaultImplementation; @@ -42,26 +45,28 @@ namespace osu.Game.Skinning protected override void SkinChanged(ISkinSource skin, bool allowFallback) { - var drawable = skin.GetDrawableComponent(componentName); - if (drawable != null) + Drawable = null; + Drawable = skin.GetDrawableComponent(componentName); + + if (Drawable != null) { if (restrictSize) { - drawable.RelativeSizeAxes = Axes.Both; - drawable.Size = Vector2.One; - drawable.Scale = Vector2.One; - drawable.FillMode = FillMode.Fit; + Drawable.RelativeSizeAxes = Axes.Both; + Drawable.Size = Vector2.One; + Drawable.Scale = Vector2.One; + Drawable.FillMode = FillMode.Fit; } } else if (allowFallback) - drawable = createDefault(componentName); + Drawable = createDefault(componentName); - if (drawable != null) + if (Drawable != null) { - drawable.Origin = Anchor.Centre; - drawable.Anchor = Anchor.Centre; + Drawable.Origin = Anchor.Centre; + Drawable.Anchor = Anchor.Centre; - InternalChild = drawable; + InternalChild = Drawable; } else ClearInternal(); diff --git a/osu.Game/Skinning/SkinnableSpriteText.cs b/osu.Game/Skinning/SkinnableSpriteText.cs new file mode 100644 index 0000000000..8b09417bed --- /dev/null +++ b/osu.Game/Skinning/SkinnableSpriteText.cs @@ -0,0 +1,40 @@ +// 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.Sprites; + +namespace osu.Game.Skinning +{ + public class SkinnableSpriteText : SkinnableDrawable, IHasText + { + public SkinnableSpriteText(string name, Func defaultImplementation, Func allowFallback = null, bool restrictSize = true) + : base(name, defaultImplementation, allowFallback, restrictSize) + { + } + + protected override void SkinChanged(ISkinSource skin, bool allowFallback) + { + base.SkinChanged(skin, allowFallback); + + if (Drawable is IHasText textDrawable) + textDrawable.Text = Text; + } + + private string text; + + public string Text + { + get => text; + set + { + if (text == value) + return; + text = value; + + if (Drawable is IHasText textDrawable) + textDrawable.Text = value; + } + } + } +} From 8191f03503b5ee06bcb1e64345c643a52de9db3a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 27 Sep 2018 17:27:24 +0900 Subject: [PATCH 120/333] Implement HitCircleFont skin configuration --- osu.Game/Skinning/LegacySkin.cs | 3 +-- osu.Game/Skinning/LegacySkinDecoder.cs | 15 +++++++++++++++ osu.Game/Skinning/SkinConfiguration.cs | 2 ++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 160cc412b4..bb37531c3e 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -57,8 +57,7 @@ namespace osu.Game.Skinning componentName = "hit300"; break; case "Play/osu/number-text": - // Todo: Not necessarily default font - return hasFont("default") ? new LegacySpriteText(Textures, "default") : null; + return hasFont(Configuration.HitCircleFont) ? new LegacySpriteText(Textures, Configuration.HitCircleFont) : null; } var texture = GetTexture(componentName); diff --git a/osu.Game/Skinning/LegacySkinDecoder.cs b/osu.Game/Skinning/LegacySkinDecoder.cs index d4f1c5c6f1..67a031fb50 100644 --- a/osu.Game/Skinning/LegacySkinDecoder.cs +++ b/osu.Game/Skinning/LegacySkinDecoder.cs @@ -19,6 +19,7 @@ namespace osu.Game.Skinning switch (section) { case Section.General: + { var pair = SplitKeyVal(line); switch (pair.Key) @@ -32,6 +33,20 @@ namespace osu.Game.Skinning } break; + } + case Section.Fonts: + { + var pair = SplitKeyVal(line); + + switch (pair.Key) + { + case "HitCirclePrefix": + skin.HitCircleFont = pair.Value; + break; + } + + break; + } } base.ParseLine(skin, section, line); diff --git a/osu.Game/Skinning/SkinConfiguration.cs b/osu.Game/Skinning/SkinConfiguration.cs index ac59fcc7db..40f5c158cc 100644 --- a/osu.Game/Skinning/SkinConfiguration.cs +++ b/osu.Game/Skinning/SkinConfiguration.cs @@ -14,5 +14,7 @@ namespace osu.Game.Skinning public List ComboColours { get; set; } = new List(); public Dictionary CustomColours { get; set; } = new Dictionary(); + + public string HitCircleFont { get; set; } = "default"; } } From 1c242556ca73c5d3044c713d3138242a2bb049ea Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 27 Sep 2018 17:33:27 +0900 Subject: [PATCH 121/333] Add comments + cleanup --- osu.Game/Skinning/LegacySkin.cs | 1 + osu.Game/Skinning/SkinnableDrawable.cs | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index bb37531c3e..67a498730a 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -170,6 +170,7 @@ namespace osu.Game.Skinning { string textureName = $"{font}-{c}"; + // Approximate value that brings character sizing roughly in-line with stable float ratio = 36; var texture = textures.Get($"{textureName}@2x"); diff --git a/osu.Game/Skinning/SkinnableDrawable.cs b/osu.Game/Skinning/SkinnableDrawable.cs index 9ecd9e647a..5195daee65 100644 --- a/osu.Game/Skinning/SkinnableDrawable.cs +++ b/osu.Game/Skinning/SkinnableDrawable.cs @@ -18,6 +18,9 @@ namespace osu.Game.Skinning public class SkinnableDrawable : SkinReloadableDrawable where T : Drawable { + /// + /// The displayed component. May or may not be a type- member. + /// protected Drawable Drawable { get; private set; } private readonly Func createDefault; @@ -45,7 +48,6 @@ namespace osu.Game.Skinning protected override void SkinChanged(ISkinSource skin, bool allowFallback) { - Drawable = null; Drawable = skin.GetDrawableComponent(componentName); if (Drawable != null) From 3539874262e7d512206f057b4d0a55d1af023973 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 28 Sep 2018 11:01:53 +0900 Subject: [PATCH 122/333] Add missing scale Makes about a 1px difference. --- osu.Game/Skinning/LegacySkin.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 67a498730a..bd7ca22fa1 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -13,6 +13,7 @@ using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; using osu.Game.Database; using osu.Game.Graphics.Sprites; +using OpenTK; namespace osu.Game.Skinning { @@ -57,7 +58,7 @@ namespace osu.Game.Skinning componentName = "hit300"; break; case "Play/osu/number-text": - return hasFont(Configuration.HitCircleFont) ? new LegacySpriteText(Textures, Configuration.HitCircleFont) : null; + return !hasFont(Configuration.HitCircleFont) ? null : new LegacySpriteText(Textures, Configuration.HitCircleFont) { Scale = new Vector2(0.96f) }; } var texture = GetTexture(componentName); From 4cdb6dcea5307c328be87b2635996ffc0f3b2f69 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 3 Oct 2018 13:28:00 +0900 Subject: [PATCH 123/333] Rename HitObjectMask -> SelectionMask --- ...ldNoteMask.cs => HoldNoteSelectionMask.cs} | 12 +++--- .../{NoteMask.cs => NoteSelectionMask.cs} | 4 +- .../Edit/ManiaHitObjectComposer.cs | 6 +-- ...ircleMask.cs => HitCircleSelectionMask.cs} | 4 +- ...leMask.cs => SliderCircleSelectionMask.cs} | 8 ++-- .../{SliderMask.cs => SliderSelectionMask.cs} | 8 ++-- .../Edit/OsuHitObjectComposer.cs | 6 +-- osu.Game/Beatmaps/BeatmapManager.cs | 2 +- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 4 +- .../{HitObjectMask.cs => SelectionMask.cs} | 30 +++++++-------- .../Edit/Screens/Compose/Layers/DragLayer.cs | 4 +- .../Screens/Compose/Layers/MaskContainer.cs | 38 +++++++++---------- .../Screens/Compose/Layers/MaskSelection.cs | 14 +++---- 13 files changed, 70 insertions(+), 70 deletions(-) rename osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/{HoldNoteMask.cs => HoldNoteSelectionMask.cs} (87%) rename osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/{NoteMask.cs => NoteSelectionMask.cs} (90%) rename osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/{HitCircleMask.cs => HitCircleSelectionMask.cs} (88%) rename osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/{SliderCircleMask.cs => SliderCircleSelectionMask.cs} (81%) rename osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/{SliderMask.cs => SliderSelectionMask.cs} (87%) rename osu.Game/Rulesets/Edit/{HitObjectMask.cs => SelectionMask.cs} (80%) diff --git a/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/HoldNoteMask.cs b/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/HoldNoteSelectionMask.cs similarity index 87% rename from osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/HoldNoteMask.cs rename to osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/HoldNoteSelectionMask.cs index 03d2ba19cb..b4f62ea170 100644 --- a/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/HoldNoteMask.cs +++ b/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/HoldNoteSelectionMask.cs @@ -15,7 +15,7 @@ using OpenTK.Graphics; namespace osu.Game.Rulesets.Mania.Edit.Layers.Selection.Overlays { - public class HoldNoteMask : HitObjectMask + public class HoldNoteSelectionMask : SelectionMask { public new DrawableHoldNote HitObject => (DrawableHoldNote)base.HitObject; @@ -23,13 +23,13 @@ namespace osu.Game.Rulesets.Mania.Edit.Layers.Selection.Overlays private readonly BodyPiece body; - public HoldNoteMask(DrawableHoldNote hold) + public HoldNoteSelectionMask(DrawableHoldNote hold) : base(hold) { InternalChildren = new Drawable[] { - new HoldNoteNoteMask(hold.Head), - new HoldNoteNoteMask(hold.Tail), + new HoldNoteNoteSelectionMask(hold.Head), + new HoldNoteNoteSelectionMask(hold.Tail), body = new BodyPiece { AccentColour = Color4.Transparent @@ -59,9 +59,9 @@ namespace osu.Game.Rulesets.Mania.Edit.Layers.Selection.Overlays Y -= HitObject.Tail.DrawHeight; } - private class HoldNoteNoteMask : NoteMask + private class HoldNoteNoteSelectionMask : NoteSelectionMask { - public HoldNoteNoteMask(DrawableNote note) + public HoldNoteNoteSelectionMask(DrawableNote note) : base(note) { Select(); diff --git a/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/NoteMask.cs b/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/NoteSelectionMask.cs similarity index 90% rename from osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/NoteMask.cs rename to osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/NoteSelectionMask.cs index 78f876cb14..d976386d6e 100644 --- a/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/NoteMask.cs +++ b/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/NoteSelectionMask.cs @@ -9,9 +9,9 @@ using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; namespace osu.Game.Rulesets.Mania.Edit.Layers.Selection.Overlays { - public class NoteMask : HitObjectMask + public class NoteSelectionMask : SelectionMask { - public NoteMask(DrawableNote note) + public NoteSelectionMask(DrawableNote note) : base(note) { Scale = note.Scale; diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs index f37d8134ce..7cc473c712 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs @@ -40,14 +40,14 @@ namespace osu.Game.Rulesets.Mania.Edit new HitObjectCompositionTool("Hold"), }; - public override HitObjectMask CreateMaskFor(DrawableHitObject hitObject) + public override SelectionMask CreateMaskFor(DrawableHitObject hitObject) { switch (hitObject) { case DrawableNote note: - return new NoteMask(note); + return new NoteSelectionMask(note); case DrawableHoldNote holdNote: - return new HoldNoteMask(holdNote); + return new HoldNoteSelectionMask(holdNote); } return base.CreateMaskFor(hitObject); diff --git a/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/HitCircleMask.cs b/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/HitCircleSelectionMask.cs similarity index 88% rename from osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/HitCircleMask.cs rename to osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/HitCircleSelectionMask.cs index a2aa639004..aa8044af15 100644 --- a/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/HitCircleMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/HitCircleSelectionMask.cs @@ -10,9 +10,9 @@ using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; namespace osu.Game.Rulesets.Osu.Edit.Layers.Selection.Overlays { - public class HitCircleMask : HitObjectMask + public class HitCircleSelectionMask : SelectionMask { - public HitCircleMask(DrawableHitCircle hitCircle) + public HitCircleSelectionMask(DrawableHitCircle hitCircle) : base(hitCircle) { Origin = Anchor.Centre; diff --git a/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderCircleMask.cs b/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderCircleSelectionMask.cs similarity index 81% rename from osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderCircleMask.cs rename to osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderCircleSelectionMask.cs index 151564a2a8..4d6a530eda 100644 --- a/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderCircleMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderCircleSelectionMask.cs @@ -12,21 +12,21 @@ using OpenTK; namespace osu.Game.Rulesets.Osu.Edit.Layers.Selection.Overlays { - public class SliderCircleMask : HitObjectMask + public class SliderCircleSelectionMask : SelectionMask { - public SliderCircleMask(DrawableHitCircle sliderHead, DrawableSlider slider) + public SliderCircleSelectionMask(DrawableHitCircle sliderHead, DrawableSlider slider) : this(sliderHead, Vector2.Zero, slider) { } - public SliderCircleMask(DrawableSliderTail sliderTail, DrawableSlider slider) + public SliderCircleSelectionMask(DrawableSliderTail sliderTail, DrawableSlider slider) : this(sliderTail, ((Slider)slider.HitObject).Curve.PositionAt(1), slider) { } private readonly DrawableOsuHitObject hitObject; - private SliderCircleMask(DrawableOsuHitObject hitObject, Vector2 position, DrawableSlider slider) + private SliderCircleSelectionMask(DrawableOsuHitObject hitObject, Vector2 position, DrawableSlider slider) : base(hitObject) { this.hitObject = hitObject; diff --git a/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderMask.cs b/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderSelectionMask.cs similarity index 87% rename from osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderMask.cs rename to osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderSelectionMask.cs index aff42dd233..40c2026937 100644 --- a/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderSelectionMask.cs @@ -14,12 +14,12 @@ using OpenTK.Graphics; namespace osu.Game.Rulesets.Osu.Edit.Layers.Selection.Overlays { - public class SliderMask : HitObjectMask + public class SliderSelectionMask : SelectionMask { private readonly SliderBody body; private readonly DrawableSlider slider; - public SliderMask(DrawableSlider slider) + public SliderSelectionMask(DrawableSlider slider) : base(slider) { this.slider = slider; @@ -35,8 +35,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Layers.Selection.Overlays AccentColour = Color4.Transparent, PathWidth = sliderObject.Scale * 64 }, - new SliderCircleMask(slider.HeadCircle, slider), - new SliderCircleMask(slider.TailCircle, slider), + new SliderCircleSelectionMask(slider.HeadCircle, slider), + new SliderCircleSelectionMask(slider.TailCircle, slider), }; sliderObject.PositionChanged += _ => Position = slider.Position; diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index dce1fc2851..04f573596b 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -33,14 +33,14 @@ namespace osu.Game.Rulesets.Osu.Edit protected override ScalableContainer CreateLayerContainer() => new ScalableContainer(OsuPlayfield.BASE_SIZE.X) { RelativeSizeAxes = Axes.Both }; - public override HitObjectMask CreateMaskFor(DrawableHitObject hitObject) + public override SelectionMask CreateMaskFor(DrawableHitObject hitObject) { switch (hitObject) { case DrawableHitCircle circle: - return new HitCircleMask(circle); + return new HitCircleSelectionMask(circle); case DrawableSlider slider: - return new SliderMask(slider); + return new SliderSelectionMask(slider); } return base.CreateMaskFor(hitObject); diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index aa653d88f9..758a98e317 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -348,7 +348,7 @@ namespace osu.Game.Beatmaps OnlineBeatmapSetID = beatmap.BeatmapInfo.BeatmapSet?.OnlineBeatmapSetID, Beatmaps = new List(), Hash = computeBeatmapSetHash(reader), - Metadata = beatmap.Metadata + Metadata = beatmap.Metadata, }; } diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index a3253250f2..8e8bc7edb8 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -151,10 +151,10 @@ namespace osu.Game.Rulesets.Edit protected abstract IReadOnlyList CompositionTools { get; } /// - /// Creates a for a specific . + /// Creates a for a specific . /// /// The to create the overlay for. - public virtual HitObjectMask CreateMaskFor(DrawableHitObject hitObject) => null; + public virtual SelectionMask CreateMaskFor(DrawableHitObject hitObject) => null; /// /// Creates a which outlines s diff --git a/osu.Game/Rulesets/Edit/HitObjectMask.cs b/osu.Game/Rulesets/Edit/SelectionMask.cs similarity index 80% rename from osu.Game/Rulesets/Edit/HitObjectMask.cs rename to osu.Game/Rulesets/Edit/SelectionMask.cs index 636ea418f3..9582c30457 100644 --- a/osu.Game/Rulesets/Edit/HitObjectMask.cs +++ b/osu.Game/Rulesets/Edit/SelectionMask.cs @@ -16,31 +16,31 @@ namespace osu.Game.Rulesets.Edit /// /// A mask placed above a adding editing functionality. /// - public class HitObjectMask : CompositeDrawable, IStateful + public class SelectionMask : 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; @@ -48,7 +48,7 @@ namespace osu.Game.Rulesets.Edit public override bool HandlePositionalInput => ShouldBeAlive; public override bool RemoveWhenNotAlive => false; - public HitObjectMask(DrawableHitObject hitObject) + public SelectionMask(DrawableHitObject hitObject) { HitObject = hitObject; @@ -83,12 +83,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; @@ -130,12 +130,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 => ScreenSpaceDrawQuad.Centre; /// - /// The screen-space quad that outlines this for selections. + /// The screen-space quad that outlines this for selections. /// public virtual Quad SelectionQuad => ScreenSpaceDrawQuad; } diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/DragLayer.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/DragLayer.cs index 981ddd989c..fdc0dee0ce 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/DragLayer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Layers/DragLayer.cs @@ -14,7 +14,7 @@ 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 layer that handles and displays drag selection for a collection of s. /// public class DragLayer : CompositeDrawable { @@ -30,7 +30,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers /// /// Creates a new . /// - /// The selectable s. + /// The selectable s. public DragLayer(Action performSelection) { this.performSelection = performSelection; diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskContainer.cs index 19258d669e..42a7757721 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskContainer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskContainer.cs @@ -13,36 +13,36 @@ using RectangleF = osu.Framework.Graphics.Primitives.RectangleF; namespace osu.Game.Screens.Edit.Screens.Compose.Layers { - public class MaskContainer : Container + public class MaskContainer : Container { /// - /// Invoked when any is selected. + /// Invoked when any is selected. /// - public event Action MaskSelected; + public event Action MaskSelected; /// - /// Invoked when any is deselected. + /// Invoked when any is deselected. /// - public event Action MaskDeselected; + public event Action MaskDeselected; /// - /// Invoked when any requests selection. + /// Invoked when any requests selection. /// - public event Action MaskSelectionRequested; + public event Action MaskSelectionRequested; /// - /// Invoked when any requests drag. + /// Invoked when any requests drag. /// - public event Action MaskDragRequested; + public event Action MaskDragRequested; - private IEnumerable aliveMasks => AliveInternalChildren.Cast(); + private IEnumerable aliveMasks => AliveInternalChildren.Cast(); public MaskContainer() { RelativeSizeAxes = Axes.Both; } - public override void Add(HitObjectMask drawable) + public override void Add(SelectionMask drawable) { if (drawable == null) throw new ArgumentNullException(nameof(drawable)); @@ -54,7 +54,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers drawable.DragRequested += onDragRequested; } - public override bool Remove(HitObjectMask drawable) + public override bool Remove(SelectionMask drawable) { if (drawable == null) throw new ArgumentNullException(nameof(drawable)); @@ -87,33 +87,33 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers } /// - /// Deselects all selected s. + /// Deselects all selected s. /// public void DeselectAll() => aliveMasks.ToList().ForEach(m => m.Deselect()); - private void onMaskSelected(HitObjectMask mask) + private void onMaskSelected(SelectionMask mask) { MaskSelected?.Invoke(mask); ChangeChildDepth(mask, 1); } - private void onMaskDeselected(HitObjectMask mask) + private void onMaskDeselected(SelectionMask mask) { MaskDeselected?.Invoke(mask); ChangeChildDepth(mask, 0); } - private void onSelectionRequested(HitObjectMask mask, InputState state) => MaskSelectionRequested?.Invoke(mask, state); - private void onDragRequested(HitObjectMask mask, Vector2 delta, InputState state) => MaskDragRequested?.Invoke(mask, delta, state); + 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 HitObjectMask xMask) || !(y is HitObjectMask yMask)) + if (!(x is SelectionMask xMask) || !(y is SelectionMask yMask)) return base.Compare(x, y); return Compare(xMask, yMask); } - public int Compare(HitObjectMask x, HitObjectMask y) + 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); diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskSelection.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskSelection.cs index 635edf82da..1231737122 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskSelection.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskSelection.cs @@ -16,19 +16,19 @@ using OpenTK; 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 MaskSelection : CompositeDrawable { public const float BORDER_RADIUS = 2; - private readonly List selectedMasks; + private readonly List selectedMasks; private Drawable outline; public MaskSelection() { - selectedMasks = new List(); + selectedMasks = new List(); RelativeSizeAxes = Axes.Both; AlwaysPresent = true; @@ -54,7 +54,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers #region User Input Handling - public void HandleDrag(HitObjectMask m, Vector2 delta, InputState state) + public void HandleDrag(SelectionMask m, Vector2 delta, InputState state) { // Todo: Various forms of snapping @@ -82,13 +82,13 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers /// Handle a mask becoming selected. /// /// The mask. - public void HandleSelected(HitObjectMask mask) => selectedMasks.Add(mask); + public void HandleSelected(SelectionMask mask) => selectedMasks.Add(mask); /// /// Handle a mask becoming deselected. /// /// The mask. - public void HandleDeselected(HitObjectMask mask) + public void HandleDeselected(SelectionMask mask) { selectedMasks.Remove(mask); @@ -101,7 +101,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers /// Handle a mask requesting selection. /// /// The mask. - public void HandleSelectionRequested(HitObjectMask mask, InputState state) + public void HandleSelectionRequested(SelectionMask mask, InputState state) { if (state.Keyboard.ControlPressed) { From 1164108a95da3d9d32b7c6cd1d3cfe7402b391d1 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 3 Oct 2018 13:45:41 +0900 Subject: [PATCH 124/333] Renamespace ruleset masks --- osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs | 2 +- .../Selection/Overlays => Masks}/HoldNoteSelectionMask.cs | 2 +- .../{Layers/Selection/Overlays => Masks}/NoteSelectionMask.cs | 2 +- .../Selection/Overlays => Masks}/HitCircleSelectionMask.cs | 4 ++-- .../Selection/Overlays => Masks}/SliderCircleSelectionMask.cs | 2 +- .../Selection/Overlays => Masks}/SliderSelectionMask.cs | 2 +- osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) rename osu.Game.Rulesets.Mania/Edit/{Layers/Selection/Overlays => Masks}/HoldNoteSelectionMask.cs (97%) rename osu.Game.Rulesets.Mania/Edit/{Layers/Selection/Overlays => Masks}/NoteSelectionMask.cs (93%) rename osu.Game.Rulesets.Osu/Edit/{Layers/Selection/Overlays => Masks}/HitCircleSelectionMask.cs (94%) rename osu.Game.Rulesets.Osu/Edit/{Layers/Selection/Overlays => Masks}/SliderCircleSelectionMask.cs (96%) rename osu.Game.Rulesets.Osu/Edit/{Layers/Selection/Overlays => Masks}/SliderSelectionMask.cs (97%) diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs index 7cc473c712..1053e998be 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs @@ -4,7 +4,6 @@ using osu.Game.Beatmaps; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Tools; -using osu.Game.Rulesets.Mania.Edit.Layers.Selection.Overlays; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables; @@ -12,6 +11,7 @@ using osu.Game.Rulesets.UI; 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.UI; namespace osu.Game.Rulesets.Mania.Edit diff --git a/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/HoldNoteSelectionMask.cs b/osu.Game.Rulesets.Mania/Edit/Masks/HoldNoteSelectionMask.cs similarity index 97% rename from osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/HoldNoteSelectionMask.cs rename to osu.Game.Rulesets.Mania/Edit/Masks/HoldNoteSelectionMask.cs index b4f62ea170..a2c01d7a0e 100644 --- a/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/HoldNoteSelectionMask.cs +++ b/osu.Game.Rulesets.Mania/Edit/Masks/HoldNoteSelectionMask.cs @@ -13,7 +13,7 @@ using osu.Game.Rulesets.UI.Scrolling; using OpenTK; using OpenTK.Graphics; -namespace osu.Game.Rulesets.Mania.Edit.Layers.Selection.Overlays +namespace osu.Game.Rulesets.Mania.Edit.Masks { public class HoldNoteSelectionMask : SelectionMask { diff --git a/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/NoteSelectionMask.cs b/osu.Game.Rulesets.Mania/Edit/Masks/NoteSelectionMask.cs similarity index 93% rename from osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/NoteSelectionMask.cs rename to osu.Game.Rulesets.Mania/Edit/Masks/NoteSelectionMask.cs index d976386d6e..18f042a483 100644 --- a/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/NoteSelectionMask.cs +++ b/osu.Game.Rulesets.Mania/Edit/Masks/NoteSelectionMask.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.Layers.Selection.Overlays +namespace osu.Game.Rulesets.Mania.Edit.Masks { public class NoteSelectionMask : SelectionMask { diff --git a/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/HitCircleSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleSelectionMask.cs similarity index 94% rename from osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/HitCircleSelectionMask.cs rename to osu.Game.Rulesets.Osu/Edit/Masks/HitCircleSelectionMask.cs index aa8044af15..6c96b40b33 100644 --- a/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/HitCircleSelectionMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleSelectionMask.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 osu.Framework.Graphics; using osu.Framework.Allocation; +using osu.Framework.Graphics; using osu.Game.Graphics; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; -namespace osu.Game.Rulesets.Osu.Edit.Layers.Selection.Overlays +namespace osu.Game.Rulesets.Osu.Edit.Masks { public class HitCircleSelectionMask : SelectionMask { diff --git a/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderCircleSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderCircleSelectionMask.cs similarity index 96% rename from osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderCircleSelectionMask.cs rename to osu.Game.Rulesets.Osu/Edit/Masks/SliderCircleSelectionMask.cs index 4d6a530eda..1ed22c2ac1 100644 --- a/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderCircleSelectionMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderCircleSelectionMask.cs @@ -10,7 +10,7 @@ using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; using OpenTK; -namespace osu.Game.Rulesets.Osu.Edit.Layers.Selection.Overlays +namespace osu.Game.Rulesets.Osu.Edit.Masks { public class SliderCircleSelectionMask : SelectionMask { diff --git a/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderSelectionMask.cs similarity index 97% rename from osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderSelectionMask.cs rename to osu.Game.Rulesets.Osu/Edit/Masks/SliderSelectionMask.cs index 40c2026937..b775854038 100644 --- a/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderSelectionMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderSelectionMask.cs @@ -12,7 +12,7 @@ using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; using OpenTK; using OpenTK.Graphics; -namespace osu.Game.Rulesets.Osu.Edit.Layers.Selection.Overlays +namespace osu.Game.Rulesets.Osu.Edit.Masks { public class SliderSelectionMask : SelectionMask { diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index 04f573596b..3e88004e6e 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -7,7 +7,7 @@ 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.Layers.Selection.Overlays; +using osu.Game.Rulesets.Osu.Edit.Masks; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.UI; From 28b0ab6123c9935f81ee99f3a4b3f3b78124afcf Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 3 Oct 2018 14:35:26 +0900 Subject: [PATCH 125/333] Split visuals of HitCircleSelectionMask into HitCircleMask --- .../Edit/Masks/HitCircleMask.cs | 35 +++++++++++++++++++ .../Edit/Masks/HitCircleSelectionMask.cs | 18 ++-------- 2 files changed, 38 insertions(+), 15 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMask.cs diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMask.cs new file mode 100644 index 0000000000..76f876fb42 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMask.cs @@ -0,0 +1,35 @@ +// 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 osu.Game.Graphics; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; +using OpenTK; + +namespace osu.Game.Rulesets.Osu.Edit.Masks +{ + public class HitCircleMask : CompositeDrawable + { + public HitCircleMask(HitCircle hitCircle) + { + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + + Size = new Vector2((float)OsuHitObject.OBJECT_RADIUS * 2); + Scale = new Vector2(hitCircle.Scale); + + CornerRadius = Size.X / 2; + + AddInternal(new RingPiece()); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + Colour = colours.Yellow; + } + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleSelectionMask.cs index 6c96b40b33..b9ca95b837 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleSelectionMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleSelectionMask.cs @@ -1,12 +1,10 @@ // 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.Game.Graphics; using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; -using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; namespace osu.Game.Rulesets.Osu.Edit.Masks { @@ -16,22 +14,12 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks : base(hitCircle) { Origin = Anchor.Centre; - + AutoSizeAxes = Axes.Both; Position = hitCircle.Position; - Size = hitCircle.Size; - Scale = hitCircle.Scale; - CornerRadius = Size.X / 2; - - AddInternal(new RingPiece()); + InternalChild = new HitCircleMask((HitCircle)hitCircle.HitObject); hitCircle.HitObject.PositionChanged += _ => Position = hitCircle.Position; } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - Colour = colours.Yellow; - } } } From 10d0e2fef11ed5cc0568dbe0559683f38b4aed7e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 3 Oct 2018 14:35:32 +0900 Subject: [PATCH 126/333] Fix up testcase --- osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs index 5df371dd09..55dc0c4eb0 100644 --- a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs +++ b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs @@ -49,7 +49,7 @@ namespace osu.Game.Tests.Visual Vector2.Zero, new Vector2(216, 0), }, - Distance = 400, + Distance = 216, Velocity = 1, TickDistance = 100, Scale = 0.5f, From 540a010fbb52b327c010d4dd34946e9713b2a439 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 3 Oct 2018 15:36:14 +0900 Subject: [PATCH 127/333] Implement an intermediary EditRulesetContainer --- .../UI/CatchRulesetContainer.cs | 2 +- .../Edit/ManiaEditRulesetContainer.cs | 31 ++++++--- .../Edit/ManiaHitObjectComposer.cs | 3 +- .../UI/ManiaRulesetContainer.cs | 2 +- .../Edit/OsuEditRulesetContainer.cs | 24 +++++-- .../Edit/OsuHitObjectComposer.cs | 3 +- .../UI/OsuRulesetContainer.cs | 2 +- .../UI/TaikoRulesetContainer.cs | 2 +- .../Rulesets/Edit/EditRulesetContainer.cs | 67 +++++++++++++++++++ osu.Game/Rulesets/Edit/HitObjectComposer.cs | 4 +- osu.Game/Rulesets/UI/RulesetContainer.cs | 31 +++++---- 11 files changed, 136 insertions(+), 35 deletions(-) create mode 100644 osu.Game/Rulesets/Edit/EditRulesetContainer.cs diff --git a/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs b/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs index 1ac052de4d..9bec270468 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs @@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Catch.UI protected override Vector2 PlayfieldArea => new Vector2(0.86f); // matches stable's vertical offset for catcher plate - protected override DrawableHitObject GetVisualRepresentation(CatchHitObject h) + public override DrawableHitObject GetVisualRepresentation(CatchHitObject h) { switch (h) { diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaEditRulesetContainer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaEditRulesetContainer.cs index a01947a60b..ca844220cf 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaEditRulesetContainer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaEditRulesetContainer.cs @@ -4,24 +4,37 @@ using osu.Framework.Graphics; using OpenTK; using osu.Game.Beatmaps; +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Mania.Edit { - public class ManiaEditRulesetContainer : ManiaRulesetContainer + public class ManiaEditRulesetContainer : EditRulesetContainer { - public ManiaEditRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) - : base(ruleset, beatmap) + public ManiaEditRulesetContainer(Ruleset ruleset, WorkingBeatmap workingBeatmap) + : base(ruleset, workingBeatmap) { } - protected override Playfield CreatePlayfield() => new ManiaEditPlayfield(Beatmap.Stages) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }; + protected override RulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap workingBeatmap) + => new RulesetContainer(ruleset, workingBeatmap); - protected override Vector2 PlayfieldArea => Vector2.One; + private new class RulesetContainer : ManiaRulesetContainer + { + public RulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) + : base(ruleset, beatmap) + { + } + + protected override Playfield CreatePlayfield() => new ManiaEditPlayfield(Beatmap.Stages) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }; + + protected override Vector2 PlayfieldArea => Vector2.One; + } } } diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs index 1053e998be..75dc475d52 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs @@ -7,7 +7,6 @@ using osu.Game.Rulesets.Edit.Tools; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables; -using osu.Game.Rulesets.UI; using System.Collections.Generic; using osu.Framework.Allocation; using osu.Game.Rulesets.Mania.Configuration; @@ -32,7 +31,7 @@ namespace osu.Game.Rulesets.Mania.Edit return dependencies; } - protected override RulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) => new ManiaEditRulesetContainer(ruleset, beatmap); + protected override EditRulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) => new ManiaEditRulesetContainer(ruleset, beatmap); protected override IReadOnlyList CompositionTools => new ICompositionTool[] { diff --git a/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs b/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs index 09ebde2799..425e0db237 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs @@ -97,7 +97,7 @@ namespace osu.Game.Rulesets.Mania.UI public override PassThroughInputManager CreateInputManager() => new ManiaInputManager(Ruleset.RulesetInfo, Variant); - protected override DrawableHitObject GetVisualRepresentation(ManiaHitObject h) + public override DrawableHitObject GetVisualRepresentation(ManiaHitObject h) { switch (h) { diff --git a/osu.Game.Rulesets.Osu/Edit/OsuEditRulesetContainer.cs b/osu.Game.Rulesets.Osu/Edit/OsuEditRulesetContainer.cs index 6efa16bf56..8d3a0c25f0 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuEditRulesetContainer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuEditRulesetContainer.cs @@ -3,20 +3,34 @@ using osu.Framework.Graphics.Cursor; using osu.Game.Beatmaps; +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.UI; +using osu.Game.Rulesets.UI; using OpenTK; namespace osu.Game.Rulesets.Osu.Edit { - public class OsuEditRulesetContainer : OsuRulesetContainer + public class OsuEditRulesetContainer : EditRulesetContainer { - public OsuEditRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) - : base(ruleset, beatmap) + public OsuEditRulesetContainer(Ruleset ruleset, WorkingBeatmap workingBeatmap) + : base(ruleset, workingBeatmap) { } - protected override Vector2 PlayfieldArea => Vector2.One; + protected override RulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap workingBeatmap) + => new RulesetContainer(ruleset, workingBeatmap); - protected override CursorContainer CreateCursor() => null; + private new class RulesetContainer : OsuRulesetContainer + { + public RulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) + : base(ruleset, beatmap) + { + } + + protected override Vector2 PlayfieldArea => Vector2.One; + + protected override CursorContainer CreateCursor() => null; + } } } diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index 3e88004e6e..de8c39b0b2 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using osu.Framework.Graphics; +using osu.Framework.Input.Events; using osu.Game.Beatmaps; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Tools; @@ -22,7 +23,7 @@ namespace osu.Game.Rulesets.Osu.Edit { } - protected override RulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) => new OsuEditRulesetContainer(ruleset, beatmap); + protected override EditRulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) => new OsuEditRulesetContainer(ruleset, beatmap); protected override IReadOnlyList CompositionTools => new ICompositionTool[] { diff --git a/osu.Game.Rulesets.Osu/UI/OsuRulesetContainer.cs b/osu.Game.Rulesets.Osu/UI/OsuRulesetContainer.cs index 4bc6992445..10f6a824f8 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuRulesetContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuRulesetContainer.cs @@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Osu.UI public override PassThroughInputManager CreateInputManager() => new OsuInputManager(Ruleset.RulesetInfo); - protected override DrawableHitObject GetVisualRepresentation(OsuHitObject h) + public override DrawableHitObject GetVisualRepresentation(OsuHitObject h) { switch (h) { diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs b/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs index 229ab69ceb..eb14aa74f1 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs @@ -96,7 +96,7 @@ namespace osu.Game.Rulesets.Taiko.UI Origin = Anchor.CentreLeft }; - protected override DrawableHitObject GetVisualRepresentation(TaikoHitObject h) + public override DrawableHitObject GetVisualRepresentation(TaikoHitObject h) { switch (h) { diff --git a/osu.Game/Rulesets/Edit/EditRulesetContainer.cs b/osu.Game/Rulesets/Edit/EditRulesetContainer.cs new file mode 100644 index 0000000000..98783b366e --- /dev/null +++ b/osu.Game/Rulesets/Edit/EditRulesetContainer.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 osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.UI; + +namespace osu.Game.Rulesets.Edit +{ + public abstract class EditRulesetContainer : CompositeDrawable + { + public Playfield Playfield => RulesetContainer.Playfield; + + protected abstract RulesetContainer RulesetContainer { get; } + + internal EditRulesetContainer() + { + RelativeSizeAxes = Axes.Both; + } + + public abstract void AddHitObject(HitObject hitObject); + } + + public abstract class EditRulesetContainer : EditRulesetContainer + where TObject : HitObject + { + private readonly Ruleset ruleset; + + private readonly RulesetContainer rulesetContainer; + protected override RulesetContainer RulesetContainer => rulesetContainer; + + private Beatmap beatmap => rulesetContainer.Beatmap; + + protected EditRulesetContainer(Ruleset ruleset, WorkingBeatmap workingBeatmap) + { + this.ruleset = ruleset; + + InternalChild = rulesetContainer = CreateRulesetContainer(ruleset, workingBeatmap); + } + + public override void AddHitObject(HitObject hitObject) + { + var tObject = (TObject)hitObject; + + // Insert into beatmap while maintaining sorting order + var insertionIndex = beatmap.HitObjects.FindLastIndex(h => h.StartTime <= hitObject.StartTime); + beatmap.HitObjects.Insert(insertionIndex + 1, tObject); + + var processor = ruleset.CreateBeatmapProcessor(beatmap); + + processor.PreProcess(); + tObject.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BaseDifficulty); + processor.PostProcess(); + + rulesetContainer.Playfield.Add(rulesetContainer.GetVisualRepresentation(tObject)); + rulesetContainer.Playfield.PostProcess(); + } + + /// + /// Creates the underlying . + /// + /// + protected abstract RulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap workingBeatmap); + } +} diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 8e8bc7edb8..a3f5cb80a3 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Edit private readonly List layerContainers = new List(); private readonly IBindable beatmap = new Bindable(); - private RulesetContainer rulesetContainer; + private EditRulesetContainer rulesetContainer; protected HitObjectComposer(Ruleset ruleset) { @@ -146,7 +146,7 @@ namespace osu.Game.Rulesets.Edit private void setCompositionTool(ICompositionTool tool) => CurrentTool = tool; - protected virtual RulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) => ruleset.CreateRulesetContainerWith(beatmap); + protected abstract EditRulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap); protected abstract IReadOnlyList CompositionTools { get; } diff --git a/osu.Game/Rulesets/UI/RulesetContainer.cs b/osu.Game/Rulesets/UI/RulesetContainer.cs index a830803fb1..340ae7077d 100644 --- a/osu.Game/Rulesets/UI/RulesetContainer.cs +++ b/osu.Game/Rulesets/UI/RulesetContainer.cs @@ -291,17 +291,7 @@ namespace osu.Game.Rulesets.UI private void loadObjects() { foreach (TObject h in Beatmap.HitObjects) - { - var drawableObject = GetVisualRepresentation(h); - - if (drawableObject == null) - continue; - - drawableObject.OnNewResult += (_, r) => OnNewResult?.Invoke(r); - drawableObject.OnRevertResult += (_, r) => OnRevertResult?.Invoke(r); - - Playfield.Add(drawableObject); - } + AddRepresentation(h); Playfield.PostProcess(); @@ -309,6 +299,23 @@ namespace osu.Game.Rulesets.UI mod.ApplyToDrawableHitObjects(Playfield.HitObjectContainer.Objects); } + /// + /// Creates and adds the visual representation of a to this . + /// + /// The to add the visual representation for. + internal void AddRepresentation(TObject hitObject) + { + var drawableObject = GetVisualRepresentation(hitObject); + + if (drawableObject == null) + return; + + drawableObject.OnNewResult += (_, r) => OnNewResult?.Invoke(r); + drawableObject.OnRevertResult += (_, r) => OnRevertResult?.Invoke(r); + + Playfield.Add(drawableObject); + } + protected override void Update() { base.Update(); @@ -334,7 +341,7 @@ namespace osu.Game.Rulesets.UI /// /// The HitObject to make drawable. /// The DrawableHitObject. - protected abstract DrawableHitObject GetVisualRepresentation(TObject h); + public abstract DrawableHitObject GetVisualRepresentation(TObject h); } /// From 3420e0c7ebae674755821cc7e5d970b2187f0309 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 3 Oct 2018 16:27:26 +0900 Subject: [PATCH 128/333] Re-implement composition tools + implement placement masks --- .../Edit/ManiaHitObjectComposer.cs | 8 +-- .../Edit/HitCircleCompositionTool.cs | 20 ++++++ .../Edit/Masks/HitCircleMask.cs | 11 ++- .../Edit/Masks/HitCirclePlacementMask.cs | 36 ++++++++++ .../Edit/OsuHitObjectComposer.cs | 8 +-- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 29 ++++++-- osu.Game/Rulesets/Edit/PlacementMask.cs | 71 +++++++++++++++++++ .../Edit/Tools/HitObjectCompositionTool.cs | 16 ++--- .../Rulesets/Edit/Tools/ICompositionTool.cs | 10 --- 9 files changed, 171 insertions(+), 38 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Edit/HitCircleCompositionTool.cs create mode 100644 osu.Game.Rulesets.Osu/Edit/Masks/HitCirclePlacementMask.cs create mode 100644 osu.Game/Rulesets/Edit/PlacementMask.cs delete mode 100644 osu.Game/Rulesets/Edit/Tools/ICompositionTool.cs diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs index 75dc475d52..8363d1dc44 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.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 System; using osu.Game.Beatmaps; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Tools; -using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables; using System.Collections.Generic; @@ -33,11 +33,7 @@ namespace osu.Game.Rulesets.Mania.Edit protected override EditRulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) => new ManiaEditRulesetContainer(ruleset, beatmap); - protected override IReadOnlyList CompositionTools => new ICompositionTool[] - { - new HitObjectCompositionTool("Note"), - new HitObjectCompositionTool("Hold"), - }; + protected override IReadOnlyList CompositionTools => Array.Empty(); public override SelectionMask CreateMaskFor(DrawableHitObject hitObject) { diff --git a/osu.Game.Rulesets.Osu/Edit/HitCircleCompositionTool.cs b/osu.Game.Rulesets.Osu/Edit/HitCircleCompositionTool.cs new file mode 100644 index 0000000000..fdf791d2d1 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/HitCircleCompositionTool.cs @@ -0,0 +1,20 @@ +// 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.Edit.Tools; +using osu.Game.Rulesets.Osu.Edit.Masks; +using osu.Game.Rulesets.Osu.Objects; + +namespace osu.Game.Rulesets.Osu.Edit +{ + public class HitCircleCompositionTool : HitObjectCompositionTool + { + public HitCircleCompositionTool() + : base(nameof(HitCircle)) + { + } + + public override PlacementMask CreatePlacementMask() => new HitCirclePlacementMask(); + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMask.cs index 76f876fb42..9576e0fa91 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMask.cs @@ -13,13 +13,15 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks { public class HitCircleMask : CompositeDrawable { + private readonly HitCircle hitCircle; + public HitCircleMask(HitCircle hitCircle) { + this.hitCircle = hitCircle; Anchor = Anchor.Centre; Origin = Anchor.Centre; Size = new Vector2((float)OsuHitObject.OBJECT_RADIUS * 2); - Scale = new Vector2(hitCircle.Scale); CornerRadius = Size.X / 2; @@ -31,5 +33,12 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks { Colour = colours.Yellow; } + + protected override void Update() + { + base.Update(); + + Scale = new Vector2(hitCircle.Scale); + } } } diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/HitCirclePlacementMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/HitCirclePlacementMask.cs new file mode 100644 index 0000000000..33de02af05 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/Masks/HitCirclePlacementMask.cs @@ -0,0 +1,36 @@ +// 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.Osu.Objects; + +namespace osu.Game.Rulesets.Osu.Edit.Masks +{ + public class HitCirclePlacementMask : PlacementMask + { + public new HitCircle HitObject => (HitCircle)base.HitObject; + + public HitCirclePlacementMask() + : base(new HitCircle()) + { + Origin = Anchor.Centre; + AutoSizeAxes = Axes.Both; + + InternalChild = new HitCircleMask(HitObject); + } + + protected override bool OnClick(ClickEvent e) + { + Finish(); + return true; + } + + protected override bool OnMouseMove(MouseMoveEvent e) + { + HitObject.Position = e.MousePosition; + return base.OnMouseMove(e); + } + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index de8c39b0b2..5472cf3890 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -3,13 +3,11 @@ using System.Collections.Generic; using osu.Framework.Graphics; -using osu.Framework.Input.Events; 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; -using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.UI; using osu.Game.Rulesets.UI; @@ -25,11 +23,9 @@ namespace osu.Game.Rulesets.Osu.Edit protected override EditRulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) => new OsuEditRulesetContainer(ruleset, beatmap); - protected override IReadOnlyList CompositionTools => new ICompositionTool[] + protected override IReadOnlyList CompositionTools => new[] { - new HitObjectCompositionTool(), - new HitObjectCompositionTool(), - new HitObjectCompositionTool() + new HitCircleCompositionTool(), }; protected override ScalableContainer CreateLayerContainer() => new ScalableContainer(OsuPlayfield.BASE_SIZE.X) { RelativeSizeAxes = Axes.Both }; diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index a3f5cb80a3..5f84006a1e 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -26,12 +26,12 @@ namespace osu.Game.Rulesets.Edit public IEnumerable HitObjects => rulesetContainer.Playfield.AllHitObjects; - protected ICompositionTool CurrentTool { get; private set; } protected IRulesetConfigManager Config { get; private set; } private readonly List layerContainers = new List(); private readonly IBindable beatmap = new Bindable(); + private Container placementContainer; private EditRulesetContainer rulesetContainer; protected HitObjectComposer(Ruleset ruleset) @@ -64,7 +64,11 @@ namespace osu.Game.Rulesets.Edit }; var layerAboveRuleset = CreateLayerContainer(); - layerAboveRuleset.Child = new HitObjectMaskLayer(); + layerAboveRuleset.Children = new Drawable[] + { + new HitObjectMaskLayer(), + placementContainer = new Container { RelativeSizeAxes = Axes.Both } + }; layerContainers.Add(layerBelowRuleset); layerContainers.Add(layerAboveRuleset); @@ -144,11 +148,28 @@ namespace osu.Game.Rulesets.Edit }); } - private void setCompositionTool(ICompositionTool tool) => CurrentTool = tool; + private void setCompositionTool(HitObjectCompositionTool tool) + { + placementContainer.Clear(true); + + if (tool != null) + { + var mask = tool.CreatePlacementMask(); + mask.PlacementFinished += h => + { + rulesetContainer.AddHitObject(h); + + // Re-construct the mask + setCompositionTool(tool); + }; + + placementContainer.Child = mask; + } + } protected abstract EditRulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap); - protected abstract IReadOnlyList CompositionTools { get; } + protected abstract IReadOnlyList CompositionTools { get; } /// /// Creates a for a specific . diff --git a/osu.Game/Rulesets/Edit/PlacementMask.cs b/osu.Game/Rulesets/Edit/PlacementMask.cs new file mode 100644 index 0000000000..7742448b1d --- /dev/null +++ b/osu.Game/Rulesets/Edit/PlacementMask.cs @@ -0,0 +1,71 @@ +// 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.Graphics.Containers; +using osu.Framework.Input; +using osu.Framework.Input.Events; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Objects; +using OpenTK; + +namespace osu.Game.Rulesets.Edit +{ + public class PlacementMask : CompositeDrawable, IRequireHighFrequencyMousePosition + { + /// + /// Invoked when the placement of has finished. + /// + public event Action PlacementFinished; + + /// + /// The that is being placed. + /// + protected readonly HitObject HitObject; + + public PlacementMask(HitObject hitObject) + { + HitObject = hitObject; + } + + [BackgroundDependencyLoader] + private void load(IBindableBeatmap workingBeatmap) + { + HitObject.ApplyDefaults(workingBeatmap.Value.Beatmap.ControlPointInfo, workingBeatmap.Value.Beatmap.BeatmapInfo.BaseDifficulty); + } + + /// + /// Finishes the placement of . + /// + public void Finish() => PlacementFinished?.Invoke(HitObject); + + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Parent?.ReceivePositionalInputAt(screenSpacePos) ?? false; + + protected override bool Handle(UIEvent e) + { + base.Handle(e); + + switch (e) + { + case MouseEvent _: + return true; + default: + return false; + } + } + + protected override bool OnMouseMove(MouseMoveEvent e) + { + Position = e.MousePosition; + return true; + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + PlacementFinished = null; + } + } +} diff --git a/osu.Game/Rulesets/Edit/Tools/HitObjectCompositionTool.cs b/osu.Game/Rulesets/Edit/Tools/HitObjectCompositionTool.cs index 78ad236e74..c5d64e3d4d 100644 --- a/osu.Game/Rulesets/Edit/Tools/HitObjectCompositionTool.cs +++ b/osu.Game/Rulesets/Edit/Tools/HitObjectCompositionTool.cs @@ -1,23 +1,17 @@ // 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; - namespace osu.Game.Rulesets.Edit.Tools { - public class HitObjectCompositionTool : ICompositionTool - where T : HitObject + public abstract class HitObjectCompositionTool { - public string Name { get; } + public readonly string Name; - public HitObjectCompositionTool() - : this(typeof(T).Name) - { - } - - public HitObjectCompositionTool(string name) + protected HitObjectCompositionTool(string name) { Name = name; } + + public abstract PlacementMask CreatePlacementMask(); } } diff --git a/osu.Game/Rulesets/Edit/Tools/ICompositionTool.cs b/osu.Game/Rulesets/Edit/Tools/ICompositionTool.cs deleted file mode 100644 index ce8b139b43..0000000000 --- a/osu.Game/Rulesets/Edit/Tools/ICompositionTool.cs +++ /dev/null @@ -1,10 +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.Rulesets.Edit.Tools -{ - public interface ICompositionTool - { - string Name { get; } - } -} From 34ed60830c6bf7f4538797237fcf5e361be1132e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 3 Oct 2018 16:44:37 +0900 Subject: [PATCH 129/333] Keep the placement hitobject time up-to-date --- osu.Game/Rulesets/Edit/PlacementMask.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Edit/PlacementMask.cs b/osu.Game/Rulesets/Edit/PlacementMask.cs index 7742448b1d..f68e5a829c 100644 --- a/osu.Game/Rulesets/Edit/PlacementMask.cs +++ b/osu.Game/Rulesets/Edit/PlacementMask.cs @@ -6,6 +6,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics.Containers; using osu.Framework.Input; using osu.Framework.Input.Events; +using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Rulesets.Objects; using OpenTK; @@ -24,14 +25,18 @@ namespace osu.Game.Rulesets.Edit /// protected readonly HitObject HitObject; + private IAdjustableClock clock; + public PlacementMask(HitObject hitObject) { HitObject = hitObject; } [BackgroundDependencyLoader] - private void load(IBindableBeatmap workingBeatmap) + private void load(IBindableBeatmap workingBeatmap, IAdjustableClock clock) { + this.clock = clock; + HitObject.ApplyDefaults(workingBeatmap.Value.Beatmap.ControlPointInfo, workingBeatmap.Value.Beatmap.BeatmapInfo.BaseDifficulty); } @@ -40,6 +45,13 @@ namespace osu.Game.Rulesets.Edit /// public void Finish() => PlacementFinished?.Invoke(HitObject); + protected override void Update() + { + base.Update(); + + HitObject.StartTime = clock.CurrentTime; + } + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Parent?.ReceivePositionalInputAt(screenSpacePos) ?? false; protected override bool Handle(UIEvent e) From 934b687965d966107bf2aa20658f7ffda4d16ea6 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 3 Oct 2018 16:49:59 +0900 Subject: [PATCH 130/333] Fix selection masks not being added for new objects --- osu.Game/Rulesets/Edit/EditRulesetContainer.cs | 11 ++++++++--- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 7 +++++-- .../Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs | 4 ++-- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/osu.Game/Rulesets/Edit/EditRulesetContainer.cs b/osu.Game/Rulesets/Edit/EditRulesetContainer.cs index 98783b366e..41f17337de 100644 --- a/osu.Game/Rulesets/Edit/EditRulesetContainer.cs +++ b/osu.Game/Rulesets/Edit/EditRulesetContainer.cs @@ -5,6 +5,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Edit @@ -20,7 +21,7 @@ namespace osu.Game.Rulesets.Edit RelativeSizeAxes = Axes.Both; } - public abstract void AddHitObject(HitObject hitObject); + public abstract DrawableHitObject AddHitObject(HitObject hitObject); } public abstract class EditRulesetContainer : EditRulesetContainer @@ -40,7 +41,7 @@ namespace osu.Game.Rulesets.Edit InternalChild = rulesetContainer = CreateRulesetContainer(ruleset, workingBeatmap); } - public override void AddHitObject(HitObject hitObject) + public override DrawableHitObject AddHitObject(HitObject hitObject) { var tObject = (TObject)hitObject; @@ -54,8 +55,12 @@ namespace osu.Game.Rulesets.Edit tObject.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BaseDifficulty); processor.PostProcess(); - rulesetContainer.Playfield.Add(rulesetContainer.GetVisualRepresentation(tObject)); + var drawableObject = rulesetContainer.GetVisualRepresentation(tObject); + + rulesetContainer.Playfield.Add(drawableObject); rulesetContainer.Playfield.PostProcess(); + + return drawableObject; } /// diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 5f84006a1e..5bb3299038 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -31,6 +31,7 @@ namespace osu.Game.Rulesets.Edit private readonly List layerContainers = new List(); private readonly IBindable beatmap = new Bindable(); + private HitObjectMaskLayer maskLayer; private Container placementContainer; private EditRulesetContainer rulesetContainer; @@ -66,7 +67,7 @@ namespace osu.Game.Rulesets.Edit var layerAboveRuleset = CreateLayerContainer(); layerAboveRuleset.Children = new Drawable[] { - new HitObjectMaskLayer(), + maskLayer = new HitObjectMaskLayer(), placementContainer = new Container { RelativeSizeAxes = Axes.Both } }; @@ -157,7 +158,9 @@ namespace osu.Game.Rulesets.Edit var mask = tool.CreatePlacementMask(); mask.PlacementFinished += h => { - rulesetContainer.AddHitObject(h); + var drawableObject = rulesetContainer.AddHitObject(h); + + maskLayer.AddMask(drawableObject); // Re-construct the mask setCompositionTool(tool); diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs index 65f31dd56d..7a1ad32140 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs @@ -48,7 +48,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers }; foreach (var obj in composer.HitObjects) - addMask(obj); + AddMask(obj); } protected override bool OnMouseDown(MouseDownEvent e) @@ -61,7 +61,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers /// Adds a mask for a which adds movement support. /// /// The to create a mask for. - private void addMask(DrawableHitObject hitObject) + public void AddMask(DrawableHitObject hitObject) { var mask = composer.CreateMaskFor(hitObject); if (mask == null) From 7809ce9361ed0f8c59c5ed3bce8d6046429da642 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 3 Oct 2018 17:05:22 +0900 Subject: [PATCH 131/333] Fix 1-frame position discrepancy --- osu.Game/Rulesets/Edit/PlacementMask.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/osu.Game/Rulesets/Edit/PlacementMask.cs b/osu.Game/Rulesets/Edit/PlacementMask.cs index f68e5a829c..bfeb0c17fd 100644 --- a/osu.Game/Rulesets/Edit/PlacementMask.cs +++ b/osu.Game/Rulesets/Edit/PlacementMask.cs @@ -40,6 +40,14 @@ namespace osu.Game.Rulesets.Edit HitObject.ApplyDefaults(workingBeatmap.Value.Beatmap.ControlPointInfo, workingBeatmap.Value.Beatmap.BeatmapInfo.BaseDifficulty); } + protected override void LoadComplete() + { + base.LoadComplete(); + + // Fixes a 1-frame position discrpancy due to the first mouse move event happening in the next frame + Position = GetContainingInputManager().CurrentState.Mouse.Position; + } + /// /// Finishes the placement of . /// From 1cd11a6e5b78d8891e16d6cd98da290de3608239 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 3 Oct 2018 17:06:18 +0900 Subject: [PATCH 132/333] Fix StackHeight changes not causing position updates --- .../Objects/Drawables/DrawableHitCircle.cs | 1 + osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs index 4bdddcef11..8b0973e3d3 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -61,6 +61,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Size = circle.DrawSize; HitObject.PositionChanged += _ => Position = HitObject.StackedPosition; + HitObject.StackHeightChanged += _ => Position = HitObject.StackedPosition; } public override Color4 AccentColour diff --git a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs index fdf5aaffa8..ab8f01f5d3 100644 --- a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs @@ -16,6 +16,7 @@ namespace osu.Game.Rulesets.Osu.Objects public const double OBJECT_RADIUS = 64; public event Action PositionChanged; + public event Action StackHeightChanged; public double TimePreempt = 600; public double TimeFadeIn = 400; @@ -44,7 +45,20 @@ namespace osu.Game.Rulesets.Osu.Objects public Vector2 StackedEndPosition => EndPosition + StackOffset; - public virtual int StackHeight { get; set; } + private int stackHeight; + + public int StackHeight + { + get => stackHeight; + set + { + if (stackHeight == value) + return; + stackHeight = value; + + StackHeightChanged?.Invoke(value); + } + } public Vector2 StackOffset => new Vector2(StackHeight * Scale * -6.4f); From 6a658025282aa4d52360ec75858fa966b5e46a23 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 4 Oct 2018 12:19:11 +0900 Subject: [PATCH 133/333] Fix hitcircle selections not responding to stacking changes --- osu.Game.Rulesets.Osu/Edit/Masks/HitCircleSelectionMask.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleSelectionMask.cs index b9ca95b837..f4e4bb2145 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleSelectionMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleSelectionMask.cs @@ -19,7 +19,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks InternalChild = new HitCircleMask((HitCircle)hitCircle.HitObject); - hitCircle.HitObject.PositionChanged += _ => Position = hitCircle.Position; + hitCircle.HitObject.PositionChanged += _ => Position = hitCircle.HitObject.StackedPosition; + hitCircle.HitObject.StackHeightChanged += _ => Position = hitCircle.HitObject.StackedPosition; } } } From e931aa3d9e0ee346e87f62715a199980e6c02401 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 4 Oct 2018 13:43:50 +0900 Subject: [PATCH 134/333] Move positional modifications to HitCirclePlacementMask --- .../Edit/Masks/HitCirclePlacementMask.cs | 13 +++++++++++-- osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs | 6 +++++- osu.Game/Rulesets/Edit/PlacementMask.cs | 14 -------------- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/HitCirclePlacementMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/HitCirclePlacementMask.cs index 33de02af05..9082f40445 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/HitCirclePlacementMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/HitCirclePlacementMask.cs @@ -21,16 +21,25 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks InternalChild = new HitCircleMask(HitObject); } + protected override void LoadComplete() + { + base.LoadComplete(); + + // Fixes a 1-frame position discrpancy due to the first mouse move event happening in the next frame + Position = GetContainingInputManager().CurrentState.Mouse.Position; + } + protected override bool OnClick(ClickEvent e) { + HitObject.Position = e.MousePosition; Finish(); return true; } protected override bool OnMouseMove(MouseMoveEvent e) { - HitObject.Position = e.MousePosition; - return base.OnMouseMove(e); + Position = e.MousePosition; + return true; } } } diff --git a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs index 55dc0c4eb0..d6e59587a4 100644 --- a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs +++ b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs @@ -13,6 +13,7 @@ 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; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Screens.Edit.Screens.Compose.Layers; using osu.Game.Tests.Beatmaps; @@ -29,7 +30,10 @@ namespace osu.Game.Tests.Visual typeof(HitObjectComposer), typeof(OsuHitObjectComposer), typeof(HitObjectMaskLayer), - typeof(NotNullAttribute) + typeof(NotNullAttribute), + typeof(HitCircleMask), + typeof(HitCircleSelectionMask), + typeof(HitCirclePlacementMask), }; [BackgroundDependencyLoader] diff --git a/osu.Game/Rulesets/Edit/PlacementMask.cs b/osu.Game/Rulesets/Edit/PlacementMask.cs index bfeb0c17fd..3cee09a8ee 100644 --- a/osu.Game/Rulesets/Edit/PlacementMask.cs +++ b/osu.Game/Rulesets/Edit/PlacementMask.cs @@ -40,14 +40,6 @@ namespace osu.Game.Rulesets.Edit HitObject.ApplyDefaults(workingBeatmap.Value.Beatmap.ControlPointInfo, workingBeatmap.Value.Beatmap.BeatmapInfo.BaseDifficulty); } - protected override void LoadComplete() - { - base.LoadComplete(); - - // Fixes a 1-frame position discrpancy due to the first mouse move event happening in the next frame - Position = GetContainingInputManager().CurrentState.Mouse.Position; - } - /// /// Finishes the placement of . /// @@ -75,12 +67,6 @@ namespace osu.Game.Rulesets.Edit } } - protected override bool OnMouseMove(MouseMoveEvent e) - { - Position = e.MousePosition; - return true; - } - protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); From 0724b47334e2e51558b23fbcb3f65cbee13e5243 Mon Sep 17 00:00:00 2001 From: miterosan Date: Thu, 4 Oct 2018 18:57:14 +0200 Subject: [PATCH 135/333] Minify the buildscript and update to cake.0.30.0 Also remove the dependency on Cake.CoreCLR cake.tool does not use the packages.config. --- .gitignore | 3 +-- build.ps1 | 17 +++++++++-------- tools/cake.csproj | 9 --------- tools/cakebuild.csproj | 11 +++++++++++ tools/packages.config | 4 ---- 5 files changed, 21 insertions(+), 23 deletions(-) delete mode 100644 tools/cake.csproj create mode 100644 tools/cakebuild.csproj delete mode 100644 tools/packages.config diff --git a/.gitignore b/.gitignore index c75c19f9f5..8f011deabe 100644 --- a/.gitignore +++ b/.gitignore @@ -12,8 +12,7 @@ ### Cake ### tools/* -!tools/packages.config -!tools/cake.csproj +!tools/cakebuild.csproj # Build results bin/[Dd]ebug/ diff --git a/build.ps1 b/build.ps1 index e923331793..64303e67d5 100644 --- a/build.ps1 +++ b/build.ps1 @@ -1,7 +1,5 @@ ########################################################################## -# This is the Cake bootstrapper script for PowerShell. -# This file was downloaded from https://github.com/cake-build/resources -# Feel free to change this file to fit your needs. +# This is a customized Cake bootstrapper script for PowerShell. ########################################################################## <# @@ -10,7 +8,7 @@ This is a Powershell script to bootstrap a Cake build. .DESCRIPTION -This Powershell script will download NuGet if missing, restore NuGet tools (including Cake) +This Powershell script restores NuGet tools (including Cake) and execute your Cake build script with the parameters you provide. .PARAMETER Script @@ -49,17 +47,21 @@ Param( Write-Host "Preparing to run build script..." +# Determine the script root for resolving other paths. if(!$PSScriptRoot){ $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent } +# Resolve the paths for resources used for debugging. $TOOLS_DIR = Join-Path $PSScriptRoot "tools" -$CAKE_CSPROJ = Join-Path $TOOLS_DIR "cake.csproj" +$CAKE_CSPROJ = Join-Path $TOOLS_DIR "cakebootstrap.csproj" -Invoke-Expression "dotnet restore `"$CAKE_CSPROJ`" --packages `"$TOOLS_DIR`"" +# Install the required tools locally. +Write-Host "Restoring cake tools..." +Invoke-Expression "dotnet restore `"$CAKE_CSPROJ`" --packages `"$TOOLS_DIR`"" | Out-Null # Find the Cake executable -$CAKE_EXECUTABLE = (Get-ChildItem -Path ./tools/cake.coreclr/ -Filter Cake.dll -Recurse).FullName +$CAKE_EXECUTABLE = (Get-ChildItem -Path ./tools/cake.tool/ -Filter Cake.dll -Recurse).FullName # Build Cake arguments $cakeArguments = @("$Script"); @@ -69,7 +71,6 @@ if ($Verbosity) { $cakeArguments += "-verbosity=$Verbosity" } if ($ShowDescription) { $cakeArguments += "-showdescription" } if ($DryRun) { $cakeArguments += "-dryrun" } if ($Experimental) { $cakeArguments += "-experimental" } -if ($Mono) { $cakeArguments += "-mono" } $cakeArguments += $ScriptArgs # Start Cake diff --git a/tools/cake.csproj b/tools/cake.csproj deleted file mode 100644 index 06692627d2..0000000000 --- a/tools/cake.csproj +++ /dev/null @@ -1,9 +0,0 @@ - - - Exe - netcoreapp2.0 - - - - - \ No newline at end of file diff --git a/tools/cakebuild.csproj b/tools/cakebuild.csproj new file mode 100644 index 0000000000..eaa25ccb24 --- /dev/null +++ b/tools/cakebuild.csproj @@ -0,0 +1,11 @@ + + + Exe + true + netcoreapp2.0 + + + + + + \ No newline at end of file diff --git a/tools/packages.config b/tools/packages.config deleted file mode 100644 index e37e9304d5..0000000000 --- a/tools/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - From 5abe3a0233a7cb1c84ddd03f8a3f73db2b1bd207 Mon Sep 17 00:00:00 2001 From: miterosan Date: Thu, 4 Oct 2018 19:02:59 +0200 Subject: [PATCH 136/333] Also rename the cake project in the bootstrap script --- build.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.ps1 b/build.ps1 index 64303e67d5..624a6e5de4 100644 --- a/build.ps1 +++ b/build.ps1 @@ -54,7 +54,7 @@ if(!$PSScriptRoot){ # Resolve the paths for resources used for debugging. $TOOLS_DIR = Join-Path $PSScriptRoot "tools" -$CAKE_CSPROJ = Join-Path $TOOLS_DIR "cakebootstrap.csproj" +$CAKE_CSPROJ = Join-Path $TOOLS_DIR "cakebuild.csproj" # Install the required tools locally. Write-Host "Restoring cake tools..." From 74e89fd9452069fb293d6fab34d0c5aeded179a3 Mon Sep 17 00:00:00 2001 From: miterosan Date: Fri, 5 Oct 2018 14:54:11 +0200 Subject: [PATCH 137/333] Add config file --- cake.config | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 cake.config diff --git a/cake.config b/cake.config new file mode 100644 index 0000000000..187d825591 --- /dev/null +++ b/cake.config @@ -0,0 +1,5 @@ + +[Nuget] +Source=https://api.nuget.org/v3/index.json +UseInProcessClient=true +LoadDependencies=true From 6977b2825f46e1a02bc62c073fc23208825813cf Mon Sep 17 00:00:00 2001 From: miterosan Date: Fri, 5 Oct 2018 14:57:09 +0200 Subject: [PATCH 138/333] Use the coreclr instead of caketool, hoping that the version fixes running it on linux --- build.ps1 | 2 +- tools/cakebuild.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.ps1 b/build.ps1 index 624a6e5de4..9968673c90 100644 --- a/build.ps1 +++ b/build.ps1 @@ -61,7 +61,7 @@ Write-Host "Restoring cake tools..." Invoke-Expression "dotnet restore `"$CAKE_CSPROJ`" --packages `"$TOOLS_DIR`"" | Out-Null # Find the Cake executable -$CAKE_EXECUTABLE = (Get-ChildItem -Path ./tools/cake.tool/ -Filter Cake.dll -Recurse).FullName +$CAKE_EXECUTABLE = (Get-ChildItem -Path ./tools/cake.coreclr/ -Filter Cake.dll -Recurse).FullName # Build Cake arguments $cakeArguments = @("$Script"); diff --git a/tools/cakebuild.csproj b/tools/cakebuild.csproj index eaa25ccb24..8ccce35e26 100644 --- a/tools/cakebuild.csproj +++ b/tools/cakebuild.csproj @@ -6,6 +6,6 @@ - + \ No newline at end of file From b56d09c83b918a8c209d08802cd550f1078f6bdb Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 10 Oct 2018 15:32:55 +0900 Subject: [PATCH 139/333] Set hitobject placement time manually --- .../Edit/Masks/HitCirclePlacementMask.cs | 1 + osu.Game/Rulesets/Edit/PlacementMask.cs | 11 ++--------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/HitCirclePlacementMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/HitCirclePlacementMask.cs index 9082f40445..0b248e20fe 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/HitCirclePlacementMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/HitCirclePlacementMask.cs @@ -31,6 +31,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks protected override bool OnClick(ClickEvent e) { + HitObject.StartTime = EditorClock.CurrentTime; HitObject.Position = e.MousePosition; Finish(); return true; diff --git a/osu.Game/Rulesets/Edit/PlacementMask.cs b/osu.Game/Rulesets/Edit/PlacementMask.cs index 3cee09a8ee..fd1b670274 100644 --- a/osu.Game/Rulesets/Edit/PlacementMask.cs +++ b/osu.Game/Rulesets/Edit/PlacementMask.cs @@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Edit /// protected readonly HitObject HitObject; - private IAdjustableClock clock; + protected IClock EditorClock { get; private set; } public PlacementMask(HitObject hitObject) { @@ -35,7 +35,7 @@ namespace osu.Game.Rulesets.Edit [BackgroundDependencyLoader] private void load(IBindableBeatmap workingBeatmap, IAdjustableClock clock) { - this.clock = clock; + EditorClock = clock; HitObject.ApplyDefaults(workingBeatmap.Value.Beatmap.ControlPointInfo, workingBeatmap.Value.Beatmap.BeatmapInfo.BaseDifficulty); } @@ -45,13 +45,6 @@ namespace osu.Game.Rulesets.Edit /// public void Finish() => PlacementFinished?.Invoke(HitObject); - protected override void Update() - { - base.Update(); - - HitObject.StartTime = clock.CurrentTime; - } - public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Parent?.ReceivePositionalInputAt(screenSpacePos) ?? false; protected override bool Handle(UIEvent e) From 47be95ce0baa351e0f3a8de03906e61fec9b1b80 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 16 Oct 2018 17:10:24 +0900 Subject: [PATCH 140/333] Fix slider nodes using the wrong samples --- .../Beatmaps/CatchBeatmapConverter.cs | 2 +- .../Objects/JuiceStream.cs | 2 +- .../Beatmaps/ManiaBeatmapConverter.cs | 2 +- .../Legacy/DistanceObjectPatternGenerator.cs | 2 +- osu.Game.Rulesets.Osu.Tests/TestCaseSlider.cs | 14 +++--- .../Beatmaps/OsuBeatmapConverter.cs | 2 +- osu.Game.Rulesets.Osu/Objects/Slider.cs | 7 +-- .../Beatmaps/TaikoBeatmapConverter.cs | 2 +- .../Formats/LegacyBeatmapDecoderTest.cs | 44 +++++++++++++++++++ osu.Game.Tests/Resources/slider-samples.osu | 23 ++++++++++ .../Legacy/Catch/ConvertHitObjectParser.cs | 4 +- .../Objects/Legacy/ConvertHitObjectParser.cs | 11 +++-- .../Rulesets/Objects/Legacy/ConvertSlider.cs | 2 +- .../Legacy/Mania/ConvertHitObjectParser.cs | 4 +- .../Legacy/Osu/ConvertHitObjectParser.cs | 4 +- .../Legacy/Taiko/ConvertHitObjectParser.cs | 4 +- .../Rulesets/Objects/Types/IHasRepeats.cs | 10 ++++- 17 files changed, 109 insertions(+), 30 deletions(-) create mode 100644 osu.Game.Tests/Resources/slider-samples.osu diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs index 15d4edc411..88686ac243 100644 --- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs +++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs @@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps ControlPoints = curveData.ControlPoints, CurveType = curveData.CurveType, Distance = curveData.Distance, - RepeatSamples = curveData.RepeatSamples, + NodeSamples = curveData.NodeSamples, RepeatCount = curveData.RepeatCount, X = (positionData?.X ?? 0) / CatchPlayfield.BASE_WIDTH, NewCombo = comboData?.NewCombo ?? false, diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index 0344189af5..d7eed72563 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -152,7 +152,7 @@ namespace osu.Game.Rulesets.Catch.Objects set { Curve.ControlPoints = value; } } - public List> RepeatSamples { get; set; } = new List>(); + public List> NodeSamples { get; set; } = new List>(); public CurveType CurveType { diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs index c15b303048..835c4474d7 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs @@ -247,7 +247,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps double segmentTime = (curveData.EndTime - HitObject.StartTime) / curveData.SpanCount(); int index = (int)(segmentTime == 0 ? 0 : (time - HitObject.StartTime) / segmentTime); - return curveData.RepeatSamples[index]; + return curveData.NodeSamples[index]; } } } diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs index 37a8062d75..635004d2f6 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs @@ -470,7 +470,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy double segmentTime = (EndTime - HitObject.StartTime) / spanCount; int index = (int)(segmentTime == 0 ? 0 : (time - HitObject.StartTime) / segmentTime); - return curveData.RepeatSamples[index]; + return curveData.NodeSamples[index]; } /// diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSlider.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSlider.cs index 3f9464a98f..f3d3fb6e7f 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseSlider.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSlider.cs @@ -116,7 +116,7 @@ namespace osu.Game.Rulesets.Osu.Tests }, Distance = 700, RepeatCount = repeats, - RepeatSamples = createEmptySamples(repeats), + NodeSamples = createEmptySamples(repeats), StackHeight = 10 }; @@ -148,7 +148,7 @@ namespace osu.Game.Rulesets.Osu.Tests }, Distance = distance, RepeatCount = repeats, - RepeatSamples = createEmptySamples(repeats), + NodeSamples = createEmptySamples(repeats), StackHeight = stackHeight }; @@ -169,7 +169,7 @@ namespace osu.Game.Rulesets.Osu.Tests }, Distance = 600, RepeatCount = repeats, - RepeatSamples = createEmptySamples(repeats) + NodeSamples = createEmptySamples(repeats) }; addSlider(slider, 2, 3); @@ -195,7 +195,7 @@ namespace osu.Game.Rulesets.Osu.Tests }, Distance = 793.4417, RepeatCount = repeats, - RepeatSamples = createEmptySamples(repeats) + NodeSamples = createEmptySamples(repeats) }; addSlider(slider, 2, 3); @@ -220,7 +220,7 @@ namespace osu.Game.Rulesets.Osu.Tests }, Distance = 480, RepeatCount = repeats, - RepeatSamples = createEmptySamples(repeats) + NodeSamples = createEmptySamples(repeats) }; addSlider(slider, 2, 3); @@ -246,7 +246,7 @@ namespace osu.Game.Rulesets.Osu.Tests }, Distance = 1000, RepeatCount = repeats, - RepeatSamples = createEmptySamples(repeats) + NodeSamples = createEmptySamples(repeats) }; addSlider(slider, 2, 3); @@ -274,7 +274,7 @@ namespace osu.Game.Rulesets.Osu.Tests }, Distance = 300, RepeatCount = repeats, - RepeatSamples = repeatSamples + NodeSamples = repeatSamples }; addSlider(slider, 3, 1); diff --git a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs index 9e0e649eb2..8130d25890 100644 --- a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs +++ b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs @@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps ControlPoints = curveData.ControlPoints, CurveType = curveData.CurveType, Distance = curveData.Distance, - RepeatSamples = curveData.RepeatSamples, + NodeSamples = curveData.NodeSamples, RepeatCount = curveData.RepeatCount, Position = positionData?.Position ?? Vector2.Zero, NewCombo = comboData?.NewCombo ?? false, diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 7a0dcc77a6..844dcfb933 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -84,7 +84,8 @@ namespace osu.Game.Rulesets.Osu.Objects /// internal float LazyTravelDistance; - public List> RepeatSamples { get; set; } = new List>(); + public List> NodeSamples { get; set; } = new List>(); + public int RepeatCount { get; set; } /// @@ -129,7 +130,7 @@ namespace osu.Game.Rulesets.Osu.Objects { StartTime = StartTime, Position = Position, - Samples = Samples, + Samples = NodeSamples[0], SampleControlPoint = SampleControlPoint, IndexInCurrentCombo = IndexInCurrentCombo, ComboIndex = ComboIndex, @@ -209,7 +210,7 @@ namespace osu.Game.Rulesets.Osu.Objects Position = Position + Curve.PositionAt(repeat % 2), StackHeight = StackHeight, Scale = Scale, - Samples = new List(RepeatSamples[repeatIndex]) + Samples = new List(NodeSamples[1 + repeatIndex]) }); } } diff --git a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs index c2cde332e8..c4a84f416e 100644 --- a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs +++ b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs @@ -117,7 +117,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps if (!isForCurrentRuleset && tickSpacing > 0 && osuDuration < 2 * speedAdjustedBeatLength) { - List> allSamples = curveData != null ? curveData.RepeatSamples : new List>(new[] { samples }); + List> allSamples = curveData != null ? curveData.NodeSamples : new List>(new[] { samples }); int i = 0; for (double j = obj.StartTime; j <= obj.StartTime + taikoDuration + tickSpacing / 8; j += tickSpacing) diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index af63a39662..60bd87dda7 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -13,6 +13,7 @@ using osu.Game.Beatmaps.Formats; using osu.Game.Beatmaps.Timing; using osu.Game.Rulesets.Catch.Beatmaps; using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Legacy; using osu.Game.Rulesets.Osu.Beatmaps; using osu.Game.Skinning; @@ -312,5 +313,48 @@ namespace osu.Game.Tests.Beatmaps.Formats SampleInfo getTestableSampleInfo(HitObject hitObject) => hitObject.SampleControlPoint.ApplyTo(hitObject.Samples[0]); } + + [Test] + public void TestDecodeSliderSamples() + { + var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false }; + using (var resStream = Resource.OpenResource("slider-samples.osu")) + using (var stream = new StreamReader(resStream)) + { + var hitObjects = decoder.Decode(stream).HitObjects; + + var slider1 = (ConvertSlider)hitObjects[0]; + + Assert.AreEqual(1, slider1.NodeSamples[0].Count); + Assert.AreEqual(SampleInfo.HIT_NORMAL, slider1.NodeSamples[0][0].Name); + Assert.AreEqual(1, slider1.NodeSamples[1].Count); + Assert.AreEqual(SampleInfo.HIT_NORMAL, slider1.NodeSamples[1][0].Name); + Assert.AreEqual(1, slider1.NodeSamples[2].Count); + Assert.AreEqual(SampleInfo.HIT_NORMAL, slider1.NodeSamples[2][0].Name); + + var slider2 = (ConvertSlider)hitObjects[1]; + + Assert.AreEqual(2, slider2.NodeSamples[0].Count); + Assert.AreEqual(SampleInfo.HIT_NORMAL, slider2.NodeSamples[0][0].Name); + Assert.AreEqual(SampleInfo.HIT_CLAP, slider2.NodeSamples[0][1].Name); + Assert.AreEqual(2, slider2.NodeSamples[1].Count); + Assert.AreEqual(SampleInfo.HIT_NORMAL, slider2.NodeSamples[1][0].Name); + Assert.AreEqual(SampleInfo.HIT_CLAP, slider2.NodeSamples[1][1].Name); + Assert.AreEqual(2, slider2.NodeSamples[2].Count); + Assert.AreEqual(SampleInfo.HIT_NORMAL, slider2.NodeSamples[2][0].Name); + Assert.AreEqual(SampleInfo.HIT_CLAP, slider2.NodeSamples[2][1].Name); + + var slider3 = (ConvertSlider)hitObjects[2]; + + Assert.AreEqual(2, slider3.NodeSamples[0].Count); + Assert.AreEqual(SampleInfo.HIT_NORMAL, slider3.NodeSamples[0][0].Name); + Assert.AreEqual(SampleInfo.HIT_WHISTLE, slider3.NodeSamples[0][1].Name); + Assert.AreEqual(1, slider3.NodeSamples[1].Count); + Assert.AreEqual(SampleInfo.HIT_NORMAL, slider3.NodeSamples[1][0].Name); + Assert.AreEqual(2, slider3.NodeSamples[2].Count); + Assert.AreEqual(SampleInfo.HIT_NORMAL, slider3.NodeSamples[2][0].Name); + Assert.AreEqual(SampleInfo.HIT_CLAP, slider3.NodeSamples[2][1].Name); + } + } } } diff --git a/osu.Game.Tests/Resources/slider-samples.osu b/osu.Game.Tests/Resources/slider-samples.osu new file mode 100644 index 0000000000..7759a2e35f --- /dev/null +++ b/osu.Game.Tests/Resources/slider-samples.osu @@ -0,0 +1,23 @@ +osu file format v14 + +[General] +SampleSet: Normal + +[Difficulty] + +SliderMultiplier:1.6 +SliderTickRate:2 + +[TimingPoints] +24735,389.61038961039,4,1,1,25,1,0 + +[HitObjects] +// Unified: Normal, Normal, Normal +168,256,30579,6,0,B|248:320|320:248,2,160 + +// Unified: Normal+Clap, Normal+Clap, Normal+Clap +168,256,32137,6,8,B|248:320|320:248,2,160 + +// Nodal: Normal+Whistle, Normal, Normal+Clap +// Nodal sounds should override the unified clap sound +168,256,33696,6,8,B|248:320|320:248,2,160,2|0|8 \ No newline at end of file diff --git a/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs index 802080aedb..6050e87841 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs @@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch }; } - protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, List controlPoints, double length, CurveType curveType, int repeatCount, List> repeatSamples) + protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, List controlPoints, double length, CurveType curveType, int repeatCount, List> nodeSamples) { newCombo |= forceNewCombo; comboOffset += extraComboOffset; @@ -53,7 +53,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch ControlPoints = controlPoints, Distance = length, CurveType = curveType, - RepeatSamples = repeatSamples, + NodeSamples = nodeSamples, RepeatCount = repeatCount }; } diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs index 72168a4cd2..7cd15543ca 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs @@ -169,6 +169,9 @@ namespace osu.Game.Rulesets.Objects.Legacy nodeSamples.Add(convertSoundType(nodeSoundTypes[i], nodeBankInfos[i])); result = CreateSlider(pos, combo, comboOffset, points, length, curveType, repeatCount, nodeSamples); + + // The samples are played when the slider ends, which is the last node + result.Samples = nodeSamples[nodeSamples.Count - 1]; } else if (type.HasFlag(ConvertHitObjectType.Spinner)) { @@ -200,7 +203,9 @@ namespace osu.Game.Rulesets.Objects.Legacy } result.StartTime = Convert.ToDouble(split[2], CultureInfo.InvariantCulture) + Offset; - result.Samples = convertSoundType(soundType, bankInfo); + + if (result.Samples.Count == 0) + result.Samples = convertSoundType(soundType, bankInfo); FirstObject = false; @@ -260,9 +265,9 @@ namespace osu.Game.Rulesets.Objects.Legacy /// The slider length. /// The slider curve type. /// The slider repeat count. - /// The samples to be played when the repeat nodes are hit. This includes the head and tail of the slider. + /// The samples to be played when the slider nodes are hit. This includes the head and tail of the slider. /// The hit object. - protected abstract HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, List controlPoints, double length, CurveType curveType, int repeatCount, List> repeatSamples); + protected abstract HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, List controlPoints, double length, CurveType curveType, int repeatCount, List> nodeSamples); /// /// Creates a legacy Spinner-type hit object. diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs index ef1eecec3d..997418b5cd 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs @@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Objects.Legacy public double Distance { get; set; } - public List> RepeatSamples { get; set; } + public List> NodeSamples { get; set; } public int RepeatCount { get; set; } public double EndTime => StartTime + this.SpanCount() * Distance / Velocity; diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs index 6f59965e18..eda37cc152 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs @@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania }; } - protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, List controlPoints, double length, CurveType curveType, int repeatCount, List> repeatSamples) + protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, List controlPoints, double length, CurveType curveType, int repeatCount, List> nodeSamples) { return new ConvertSlider { @@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania ControlPoints = controlPoints, Distance = length, CurveType = curveType, - RepeatSamples = repeatSamples, + 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 acd0de8688..9269746f2b 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs @@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu }; } - protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, List controlPoints, double length, CurveType curveType, int repeatCount, List> repeatSamples) + protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, List controlPoints, double length, CurveType curveType, int repeatCount, List> nodeSamples) { newCombo |= forceNewCombo; comboOffset += extraComboOffset; @@ -54,7 +54,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu ControlPoints = controlPoints, Distance = Math.Max(0, length), CurveType = curveType, - RepeatSamples = repeatSamples, + 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 e5904825c2..35c66e18a7 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs @@ -23,14 +23,14 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko return new ConvertHit(); } - protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, List controlPoints, double length, CurveType curveType, int repeatCount, List> repeatSamples) + protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, List controlPoints, double length, CurveType curveType, int repeatCount, List> nodeSamples) { return new ConvertSlider { ControlPoints = controlPoints, Distance = length, CurveType = curveType, - RepeatSamples = repeatSamples, + NodeSamples = nodeSamples, RepeatCount = repeatCount }; } diff --git a/osu.Game/Rulesets/Objects/Types/IHasRepeats.cs b/osu.Game/Rulesets/Objects/Types/IHasRepeats.cs index 7d918ff160..ea8784db47 100644 --- a/osu.Game/Rulesets/Objects/Types/IHasRepeats.cs +++ b/osu.Game/Rulesets/Objects/Types/IHasRepeats.cs @@ -17,9 +17,15 @@ namespace osu.Game.Rulesets.Objects.Types int RepeatCount { get; } /// - /// The samples to be played when each repeat node is hit (0 -> first repeat node, 1 -> second repeat node, etc). + /// The samples to be played when each node of the is hit.
+ /// 0: The first node.
+ /// 1: The first repeat.
+ /// 2: The second repeat.
+ /// ...
+ /// n-1: The last repeat.
+ /// n: The last node. ///
- List> RepeatSamples { get; } + List> NodeSamples { get; } } public static class HasRepeatsExtensions From f384c7228e7a0dc81f4c140318f805386e972bf0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 16 Oct 2018 17:28:23 +0900 Subject: [PATCH 141/333] Fix post-merge issues --- osu.Game.Rulesets.Mania/Edit/ManiaEditRulesetContainer.cs | 2 +- osu.Game.Rulesets.Osu/Edit/OsuEditRulesetContainer.cs | 3 ++- osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs | 1 - 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaEditRulesetContainer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaEditRulesetContainer.cs index 1ddec9681f..dbe6ebb02a 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaEditRulesetContainer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaEditRulesetContainer.cs @@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Mania.Edit { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Size = Vector2.One + Size = Vector2.One }; } } diff --git a/osu.Game.Rulesets.Osu/Edit/OsuEditRulesetContainer.cs b/osu.Game.Rulesets.Osu/Edit/OsuEditRulesetContainer.cs index 7b02682688..5da6c2535d 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuEditRulesetContainer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuEditRulesetContainer.cs @@ -29,7 +29,8 @@ namespace osu.Game.Rulesets.Osu.Edit } protected override CursorContainer CreateCursor() => null; + + protected override Playfield CreatePlayfield() => new OsuPlayfield { Size = Vector2.One }; } - protected override Playfield CreatePlayfield() => new OsuPlayfield { Size = Vector2.One }; } } diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index 5fb71505eb..8bf14e3730 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -11,7 +11,6 @@ using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Edit.Masks; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.UI; -using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Osu.Edit { From e8ce5a7e6c60eec3ec0a5cad9fd77384216aa95f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 16 Oct 2018 18:27:09 +0900 Subject: [PATCH 142/333] Fix crashes when manually creating sliders --- osu.Game.Rulesets.Osu/Objects/Slider.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 844dcfb933..c33e089178 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -130,7 +130,7 @@ namespace osu.Game.Rulesets.Osu.Objects { StartTime = StartTime, Position = Position, - Samples = NodeSamples[0], + Samples = getNodeSamples(0), SampleControlPoint = SampleControlPoint, IndexInCurrentCombo = IndexInCurrentCombo, ComboIndex = ComboIndex, @@ -210,11 +210,18 @@ namespace osu.Game.Rulesets.Osu.Objects Position = Position + Curve.PositionAt(repeat % 2), StackHeight = StackHeight, Scale = Scale, - Samples = new List(NodeSamples[1 + repeatIndex]) + Samples = getNodeSamples(1 + repeatIndex) }); } } + private List getNodeSamples(int nodeIndex) + { + if (nodeIndex < NodeSamples.Count) + return NodeSamples[nodeIndex]; + return Samples; + } + public override Judgement CreateJudgement() => new OsuJudgement(); } } From 08e3fe1def87187fe297fbfbf29441ce5500618e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 17 Oct 2018 14:37:39 +0900 Subject: [PATCH 143/333] Add PlacementStarted event, rename placement methods --- .../Edit/Masks/HitCirclePlacementMask.cs | 3 ++- osu.Game/Rulesets/Edit/PlacementMask.cs | 27 +++++++++++++++++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/HitCirclePlacementMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/HitCirclePlacementMask.cs index 0b248e20fe..08e417cf1a 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/HitCirclePlacementMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/HitCirclePlacementMask.cs @@ -33,7 +33,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks { HitObject.StartTime = EditorClock.CurrentTime; HitObject.Position = e.MousePosition; - Finish(); + + EndPlacement(); return true; } diff --git a/osu.Game/Rulesets/Edit/PlacementMask.cs b/osu.Game/Rulesets/Edit/PlacementMask.cs index fd1b670274..109244c34f 100644 --- a/osu.Game/Rulesets/Edit/PlacementMask.cs +++ b/osu.Game/Rulesets/Edit/PlacementMask.cs @@ -15,6 +15,11 @@ namespace osu.Game.Rulesets.Edit { public class PlacementMask : CompositeDrawable, IRequireHighFrequencyMousePosition { + /// + /// Invoked when the placement of has started. + /// + public event Action PlacementStarted; + /// /// Invoked when the placement of has finished. /// @@ -40,10 +45,27 @@ namespace osu.Game.Rulesets.Edit HitObject.ApplyDefaults(workingBeatmap.Value.Beatmap.ControlPointInfo, workingBeatmap.Value.Beatmap.BeatmapInfo.BaseDifficulty); } + private bool placementBegun; + /// - /// Finishes the placement of . + /// Signals that the placement of has started. /// - public void Finish() => PlacementFinished?.Invoke(HitObject); + protected void BeginPlacement() + { + PlacementStarted?.Invoke(HitObject); + placementBegun = true; + } + + /// + /// Signals that the placement of has finished. + /// This will destroy this , and add the to the . + /// + protected void EndPlacement() + { + if (!placementBegun) + BeginPlacement(); + PlacementFinished?.Invoke(HitObject); + } public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Parent?.ReceivePositionalInputAt(screenSpacePos) ?? false; @@ -64,6 +86,7 @@ namespace osu.Game.Rulesets.Edit { base.Dispose(isDisposing); + PlacementStarted = null; PlacementFinished = null; } } From 4ea4ec0d2527374eccfb04f451cd8c1043ede796 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 17 Oct 2018 15:46:30 +0900 Subject: [PATCH 144/333] Move placement handling events to a higher level --- .../Visual/TestCaseHitObjectComposer.cs | 11 ++++++- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 33 +++++++++++-------- osu.Game/Rulesets/Edit/PlacementMask.cs | 27 ++++----------- .../Screens/Edit/Screens/Compose/Compose.cs | 19 ++++++++++- .../Edit/Screens/Compose/IPlacementHandler.cs | 17 ++++++++++ 5 files changed, 70 insertions(+), 37 deletions(-) create mode 100644 osu.Game/Screens/Edit/Screens/Compose/IPlacementHandler.cs diff --git a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs index d6e59587a4..042b60b66b 100644 --- a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs +++ b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs @@ -15,13 +15,15 @@ using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Edit; using osu.Game.Rulesets.Osu.Edit.Masks; using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Screens.Edit.Screens.Compose; using osu.Game.Screens.Edit.Screens.Compose.Layers; using osu.Game.Tests.Beatmaps; namespace osu.Game.Tests.Visual { [TestFixture] - public class TestCaseHitObjectComposer : OsuTestCase + [Cached(Type = typeof(IPlacementHandler))] + public class TestCaseHitObjectComposer : OsuTestCase, IPlacementHandler { public override IReadOnlyList RequiredTypes => new[] { @@ -36,6 +38,9 @@ namespace osu.Game.Tests.Visual typeof(HitCirclePlacementMask), }; + public event Action PlacementStarted; + public event Action PlacementFinished; + [BackgroundDependencyLoader] private void load() { @@ -67,5 +72,9 @@ namespace osu.Game.Tests.Visual Child = new OsuHitObjectComposer(new OsuRuleset()); } + + public void BeginPlacement(HitObject hitObject) => PlacementStarted?.Invoke(hitObject); + + public void EndPlacement(HitObject hitObject) => PlacementFinished?.Invoke(hitObject); } } diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index b5b7e6fe99..8cd26da166 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -15,6 +15,7 @@ using osu.Game.Rulesets.Configuration; using osu.Game.Rulesets.Edit.Tools; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.UI; +using osu.Game.Screens.Edit.Screens.Compose; using osu.Game.Screens.Edit.Screens.Compose.Layers; using osu.Game.Screens.Edit.Screens.Compose.RadioButtons; @@ -31,10 +32,15 @@ namespace osu.Game.Rulesets.Edit private readonly List layerContainers = new List(); private readonly IBindable beatmap = new Bindable(); + [Resolved] + private IPlacementHandler placementHandler { get; set; } + private HitObjectMaskLayer maskLayer; private Container placementContainer; private EditRulesetContainer rulesetContainer; + private HitObjectCompositionTool compositionTool; + protected HitObjectComposer(Ruleset ruleset) { this.ruleset = ruleset; @@ -117,6 +123,16 @@ namespace osu.Game.Rulesets.Edit .ToList(); toolboxCollection.Items[0].Select(); + + placementHandler.PlacementFinished += h => + { + var drawableObject = rulesetContainer.AddHitObject(h); + + maskLayer.AddMask(drawableObject); + + // Re-construct the mask + setCompositionTool(compositionTool); + }; } protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) @@ -151,23 +167,12 @@ namespace osu.Game.Rulesets.Edit private void setCompositionTool(HitObjectCompositionTool tool) { + compositionTool = tool; + placementContainer.Clear(true); if (tool != null) - { - var mask = tool.CreatePlacementMask(); - mask.PlacementFinished += h => - { - var drawableObject = rulesetContainer.AddHitObject(h); - - maskLayer.AddMask(drawableObject); - - // Re-construct the mask - setCompositionTool(tool); - }; - - placementContainer.Child = mask; - } + placementContainer.Child = tool.CreatePlacementMask(); } protected abstract EditRulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap); diff --git a/osu.Game/Rulesets/Edit/PlacementMask.cs b/osu.Game/Rulesets/Edit/PlacementMask.cs index 109244c34f..d253638374 100644 --- a/osu.Game/Rulesets/Edit/PlacementMask.cs +++ b/osu.Game/Rulesets/Edit/PlacementMask.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; using osu.Framework.Allocation; using osu.Framework.Graphics.Containers; using osu.Framework.Input; @@ -9,22 +8,13 @@ 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 OpenTK; namespace osu.Game.Rulesets.Edit { public class PlacementMask : CompositeDrawable, IRequireHighFrequencyMousePosition { - /// - /// Invoked when the placement of has started. - /// - public event Action PlacementStarted; - - /// - /// Invoked when the placement of has finished. - /// - public event Action PlacementFinished; - /// /// The that is being placed. /// @@ -32,6 +22,9 @@ namespace osu.Game.Rulesets.Edit protected IClock EditorClock { get; private set; } + [Resolved] + private IPlacementHandler placementHandler { get; set; } + public PlacementMask(HitObject hitObject) { HitObject = hitObject; @@ -52,7 +45,7 @@ namespace osu.Game.Rulesets.Edit ///
protected void BeginPlacement() { - PlacementStarted?.Invoke(HitObject); + placementHandler.BeginPlacement(HitObject); placementBegun = true; } @@ -64,7 +57,7 @@ namespace osu.Game.Rulesets.Edit { if (!placementBegun) BeginPlacement(); - PlacementFinished?.Invoke(HitObject); + placementHandler.EndPlacement(HitObject); } public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Parent?.ReceivePositionalInputAt(screenSpacePos) ?? false; @@ -81,13 +74,5 @@ namespace osu.Game.Rulesets.Edit return false; } } - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - - PlacementStarted = null; - PlacementFinished = null; - } } } diff --git a/osu.Game/Screens/Edit/Screens/Compose/Compose.cs b/osu.Game/Screens/Edit/Screens/Compose/Compose.cs index a862485fd6..7f720705e1 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Compose.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Compose.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 JetBrains.Annotations; using osu.Framework.Allocation; using OpenTK.Graphics; @@ -9,15 +10,27 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Logging; +using osu.Game.Rulesets.Objects; using osu.Game.Screens.Edit.Screens.Compose.Timeline; namespace osu.Game.Screens.Edit.Screens.Compose { - public class Compose : EditorScreen + [Cached(Type = typeof(IPlacementHandler))] + public class Compose : EditorScreen, IPlacementHandler { private const float vertical_margins = 10; private const float horizontal_margins = 20; + /// + /// Invoked when the placement of a has started. + /// + public event Action PlacementStarted; + + /// + /// Invoked when the placement of a has finished. + /// + public event Action PlacementFinished; + private readonly BindableBeatDivisor beatDivisor = new BindableBeatDivisor(); private Container composerContainer; @@ -111,5 +124,9 @@ namespace osu.Game.Screens.Edit.Screens.Compose composerContainer.Child = composer; } + + public void BeginPlacement(HitObject hitObject) => PlacementStarted?.Invoke(hitObject); + + public void EndPlacement(HitObject hitObject) => PlacementFinished?.Invoke(hitObject); } } diff --git a/osu.Game/Screens/Edit/Screens/Compose/IPlacementHandler.cs b/osu.Game/Screens/Edit/Screens/Compose/IPlacementHandler.cs new file mode 100644 index 0000000000..2bab9334a2 --- /dev/null +++ b/osu.Game/Screens/Edit/Screens/Compose/IPlacementHandler.cs @@ -0,0 +1,17 @@ +// 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.Rulesets.Objects; + +namespace osu.Game.Screens.Edit.Screens.Compose +{ + public interface IPlacementHandler + { + event Action PlacementStarted; + event Action PlacementFinished; + + void BeginPlacement(HitObject hitObject); + void EndPlacement(HitObject hitObject); + } +} From 62635c5ab8fa6134c872de7e91e1e004e361344f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 17 Oct 2018 16:17:12 +0900 Subject: [PATCH 145/333] Add container to handle placement mask --- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 30 +++--------- .../Compose/Layers/HitObjectMaskLayer.cs | 3 ++ .../Compose/Layers/PlacementContainer.cs | 47 +++++++++++++++++++ 3 files changed, 56 insertions(+), 24 deletions(-) create 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 8cd26da166..bea638c0fb 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -36,10 +36,9 @@ namespace osu.Game.Rulesets.Edit private IPlacementHandler placementHandler { get; set; } private HitObjectMaskLayer maskLayer; - private Container placementContainer; private EditRulesetContainer rulesetContainer; - private HitObjectCompositionTool compositionTool; + private readonly Bindable compositionTool = new Bindable(); protected HitObjectComposer(Ruleset ruleset) { @@ -74,7 +73,7 @@ namespace osu.Game.Rulesets.Edit layerAboveRuleset.Children = new Drawable[] { maskLayer = new HitObjectMaskLayer(), - placementContainer = new Container { RelativeSizeAxes = Axes.Both } + new PlacementContainer(compositionTool), }; layerContainers.Add(layerBelowRuleset); @@ -118,21 +117,14 @@ namespace osu.Game.Rulesets.Edit }; toolboxCollection.Items = - CompositionTools.Select(t => new RadioButton(t.Name, () => setCompositionTool(t))) - .Prepend(new RadioButton("Select", () => setCompositionTool(null))) + CompositionTools.Select(t => new RadioButton(t.Name, () => compositionTool.Value = t)) + .Prepend(new RadioButton("Select", () => compositionTool.Value = null)) .ToList(); toolboxCollection.Items[0].Select(); - placementHandler.PlacementFinished += h => - { - var drawableObject = rulesetContainer.AddHitObject(h); - - maskLayer.AddMask(drawableObject); - - // Re-construct the mask - setCompositionTool(compositionTool); - }; + // Todo: no + placementHandler.PlacementFinished += h => maskLayer.AddMask(rulesetContainer.AddHitObject(h)); } protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) @@ -165,16 +157,6 @@ namespace osu.Game.Rulesets.Edit }); } - private void setCompositionTool(HitObjectCompositionTool tool) - { - compositionTool = tool; - - placementContainer.Clear(true); - - if (tool != null) - placementContainer.Child = tool.CreatePlacementMask(); - } - protected abstract EditRulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap); protected abstract IReadOnlyList CompositionTools { get; } diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs index 7a1ad32140..63fcf09d2a 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs @@ -15,6 +15,9 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers private MaskContainer maskContainer; private HitObjectComposer composer; + [Resolved] + private IPlacementHandler placementHandler { get; set; } + public HitObjectMaskLayer() { RelativeSizeAxes = Axes.Both; diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/PlacementContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/PlacementContainer.cs new file mode 100644 index 0000000000..41635565dd --- /dev/null +++ b/osu.Game/Screens/Edit/Screens/Compose/Layers/PlacementContainer.cs @@ -0,0 +1,47 @@ +// 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; +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; + + private readonly IBindable compositionTool = new Bindable(); + + [Resolved] + private IPlacementHandler placementHandler { get; set; } + + public PlacementContainer(IBindable compositionTool) + { + this.compositionTool.BindTo(compositionTool); + + RelativeSizeAxes = Axes.Both; + + this.compositionTool.BindValueChanged(onToolChanged); + } + + [BackgroundDependencyLoader] + private void load() + { + // Refresh the mask after each placement + placementHandler.PlacementFinished += _ => onToolChanged(compositionTool.Value); + } + + private void onToolChanged(HitObjectCompositionTool tool) + { + ClearInternal(); + + var mask = tool?.CreatePlacementMask(); + if (mask != null) + InternalChild = mask; + } + } +} From 969477dadd247badf77303f1fb013bfb7172a924 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 17 Oct 2018 17:41:17 +0900 Subject: [PATCH 146/333] Remove placement events, make everything pass top-down --- .../Visual/TestCaseHitObjectComposer.cs | 11 +++--- .../Rulesets/Edit/EditRulesetContainer.cs | 13 +++++-- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 24 ++++++------ .../Screens/Edit/Screens/Compose/Compose.cs | 24 +++++------- .../Edit/Screens/Compose/IPlacementHandler.cs | 4 -- .../Compose/Layers/HitObjectMaskLayer.cs | 11 ++---- .../Compose/Layers/PlacementContainer.cs | 39 ++++++++++--------- 7 files changed, 62 insertions(+), 64 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs index 042b60b66b..73df413699 100644 --- a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs +++ b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs @@ -38,8 +38,7 @@ namespace osu.Game.Tests.Visual typeof(HitCirclePlacementMask), }; - public event Action PlacementStarted; - public event Action PlacementFinished; + private HitObjectComposer composer; [BackgroundDependencyLoader] private void load() @@ -70,11 +69,13 @@ namespace osu.Game.Tests.Visual Dependencies.CacheAs(clock); Dependencies.CacheAs(clock); - Child = new OsuHitObjectComposer(new OsuRuleset()); + Child = composer = new OsuHitObjectComposer(new OsuRuleset()); } - public void BeginPlacement(HitObject hitObject) => PlacementStarted?.Invoke(hitObject); + public void BeginPlacement(HitObject hitObject) + { + } - public void EndPlacement(HitObject hitObject) => PlacementFinished?.Invoke(hitObject); + public void EndPlacement(HitObject hitObject) => composer.Add(hitObject); } } diff --git a/osu.Game/Rulesets/Edit/EditRulesetContainer.cs b/osu.Game/Rulesets/Edit/EditRulesetContainer.cs index 41f17337de..8a2d4431b2 100644 --- a/osu.Game/Rulesets/Edit/EditRulesetContainer.cs +++ b/osu.Game/Rulesets/Edit/EditRulesetContainer.cs @@ -21,7 +21,12 @@ namespace osu.Game.Rulesets.Edit RelativeSizeAxes = Axes.Both; } - public abstract DrawableHitObject AddHitObject(HitObject hitObject); + /// + /// Adds a to the and displays a visual representation of it. + /// + /// The to add. + /// The visual representation of . + internal abstract DrawableHitObject Add(HitObject hitObject); } public abstract class EditRulesetContainer : EditRulesetContainer @@ -41,20 +46,22 @@ namespace osu.Game.Rulesets.Edit InternalChild = rulesetContainer = CreateRulesetContainer(ruleset, workingBeatmap); } - public override DrawableHitObject AddHitObject(HitObject hitObject) + internal override DrawableHitObject Add(HitObject hitObject) { var tObject = (TObject)hitObject; - // Insert into beatmap while maintaining sorting order + // Add to beatmap, preserving sorting order var insertionIndex = beatmap.HitObjects.FindLastIndex(h => h.StartTime <= hitObject.StartTime); beatmap.HitObjects.Insert(insertionIndex + 1, tObject); + // Process object var processor = ruleset.CreateBeatmapProcessor(beatmap); processor.PreProcess(); tObject.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BaseDifficulty); processor.PostProcess(); + // Add visual representation var drawableObject = rulesetContainer.GetVisualRepresentation(tObject); rulesetContainer.Playfield.Add(drawableObject); diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index bea638c0fb..6212f8adcf 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -13,9 +13,9 @@ using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Rulesets.Configuration; 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; using osu.Game.Screens.Edit.Screens.Compose.Layers; using osu.Game.Screens.Edit.Screens.Compose.RadioButtons; @@ -32,13 +32,10 @@ namespace osu.Game.Rulesets.Edit private readonly List layerContainers = new List(); private readonly IBindable beatmap = new Bindable(); - [Resolved] - private IPlacementHandler placementHandler { get; set; } - - private HitObjectMaskLayer maskLayer; private EditRulesetContainer rulesetContainer; - private readonly Bindable compositionTool = new Bindable(); + private HitObjectMaskLayer maskLayer; + private PlacementContainer placementContainer; protected HitObjectComposer(Ruleset ruleset) { @@ -73,7 +70,7 @@ namespace osu.Game.Rulesets.Edit layerAboveRuleset.Children = new Drawable[] { maskLayer = new HitObjectMaskLayer(), - new PlacementContainer(compositionTool), + placementContainer = new PlacementContainer(), }; layerContainers.Add(layerBelowRuleset); @@ -117,14 +114,11 @@ namespace osu.Game.Rulesets.Edit }; toolboxCollection.Items = - CompositionTools.Select(t => new RadioButton(t.Name, () => compositionTool.Value = t)) - .Prepend(new RadioButton("Select", () => compositionTool.Value = null)) + CompositionTools.Select(t => new RadioButton(t.Name, () => placementContainer.CurrentTool = t)) + .Prepend(new RadioButton("Select", () => placementContainer.CurrentTool = null)) .ToList(); toolboxCollection.Items[0].Select(); - - // Todo: no - placementHandler.PlacementFinished += h => maskLayer.AddMask(rulesetContainer.AddHitObject(h)); } protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) @@ -157,6 +151,12 @@ namespace osu.Game.Rulesets.Edit }); } + /// + /// Adds a to the and visualises it. + /// + /// The to add. + public void Add(HitObject hitObject) => maskLayer.AddMaskFor(rulesetContainer.Add(hitObject)); + protected abstract EditRulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap); protected abstract IReadOnlyList CompositionTools { get; } diff --git a/osu.Game/Screens/Edit/Screens/Compose/Compose.cs b/osu.Game/Screens/Edit/Screens/Compose/Compose.cs index 7f720705e1..1617313ecd 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Compose.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Compose.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; using JetBrains.Annotations; using osu.Framework.Allocation; using OpenTK.Graphics; @@ -10,6 +9,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; 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; @@ -21,19 +21,9 @@ namespace osu.Game.Screens.Edit.Screens.Compose private const float vertical_margins = 10; private const float horizontal_margins = 20; - /// - /// Invoked when the placement of a has started. - /// - public event Action PlacementStarted; - - /// - /// Invoked when the placement of a has finished. - /// - public event Action PlacementFinished; - private readonly BindableBeatDivisor beatDivisor = new BindableBeatDivisor(); - private Container composerContainer; + private HitObjectComposer composer; [BackgroundDependencyLoader(true)] private void load([CanBeNull] BindableBeatDivisor beatDivisor) @@ -41,6 +31,8 @@ namespace osu.Game.Screens.Edit.Screens.Compose if (beatDivisor != null) this.beatDivisor.BindTo(beatDivisor); + Container composerContainer; + Children = new Drawable[] { new GridContainer @@ -114,7 +106,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose return; } - var composer = ruleset.CreateHitObjectComposer(); + composer = ruleset.CreateHitObjectComposer(); if (composer == null) { Logger.Log($"Ruleset {ruleset.Description} doesn't support hitobject composition."); @@ -125,8 +117,10 @@ namespace osu.Game.Screens.Edit.Screens.Compose composerContainer.Child = composer; } - public void BeginPlacement(HitObject hitObject) => PlacementStarted?.Invoke(hitObject); + public void BeginPlacement(HitObject hitObject) + { + } - public void EndPlacement(HitObject hitObject) => PlacementFinished?.Invoke(hitObject); + public void EndPlacement(HitObject hitObject) => composer.Add(hitObject); } } diff --git a/osu.Game/Screens/Edit/Screens/Compose/IPlacementHandler.cs b/osu.Game/Screens/Edit/Screens/Compose/IPlacementHandler.cs index 2bab9334a2..894d23b90e 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/IPlacementHandler.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/IPlacementHandler.cs @@ -1,16 +1,12 @@ // 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.Rulesets.Objects; namespace osu.Game.Screens.Edit.Screens.Compose { public interface IPlacementHandler { - event Action PlacementStarted; - event Action PlacementFinished; - void BeginPlacement(HitObject hitObject); void EndPlacement(HitObject hitObject); } diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs index 63fcf09d2a..c6a4c3de13 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs @@ -13,10 +13,9 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers public class HitObjectMaskLayer : CompositeDrawable { private MaskContainer maskContainer; - private HitObjectComposer composer; [Resolved] - private IPlacementHandler placementHandler { get; set; } + private HitObjectComposer composer { get; set; } public HitObjectMaskLayer() { @@ -24,10 +23,8 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers } [BackgroundDependencyLoader] - private void load(HitObjectComposer composer) + private void load() { - this.composer = composer; - maskContainer = new MaskContainer(); var maskSelection = composer.CreateMaskSelection(); @@ -51,7 +48,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers }; foreach (var obj in composer.HitObjects) - AddMask(obj); + AddMaskFor(obj); } protected override bool OnMouseDown(MouseDownEvent e) @@ -64,7 +61,7 @@ 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 AddMask(DrawableHitObject hitObject) + public void AddMaskFor(DrawableHitObject hitObject) { var mask = composer.CreateMaskFor(hitObject); if (mask == null) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/PlacementContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/PlacementContainer.cs index 41635565dd..ea167a5c6b 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/PlacementContainer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Layers/PlacementContainer.cs @@ -1,8 +1,6 @@ // 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; using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Edit.Tools; @@ -14,32 +12,37 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers { private readonly Container maskContainer; - private readonly IBindable compositionTool = new Bindable(); - - [Resolved] - private IPlacementHandler placementHandler { get; set; } - - public PlacementContainer(IBindable compositionTool) + public PlacementContainer() { - this.compositionTool.BindTo(compositionTool); - RelativeSizeAxes = Axes.Both; - - this.compositionTool.BindValueChanged(onToolChanged); } - [BackgroundDependencyLoader] - private void load() + private HitObjectCompositionTool currentTool; + + /// + /// The current placement tool. + /// + public HitObjectCompositionTool CurrentTool { - // Refresh the mask after each placement - placementHandler.PlacementFinished += _ => onToolChanged(compositionTool.Value); + get => currentTool; + set + { + if (currentTool == value) + return; + currentTool = value; + + Refresh(); + } } - private void onToolChanged(HitObjectCompositionTool tool) + /// + /// Refreshes the current placement tool. + /// + public void Refresh() { ClearInternal(); - var mask = tool?.CreatePlacementMask(); + var mask = CurrentTool?.CreatePlacementMask(); if (mask != null) InternalChild = mask; } From d36ac59ca278018e9e9df41de0665c3a0bb5af8d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 17 Oct 2018 18:01:38 +0900 Subject: [PATCH 147/333] Reduce complexity of creating edit ruleset containers --- .../Edit/ManiaEditRulesetContainer.cs | 29 ++++--------- .../Edit/ManiaHitObjectComposer.cs | 7 +++- .../Edit/OsuEditRulesetContainer.cs | 23 +++------- .../Edit/OsuHitObjectComposer.cs | 7 +++- .../Rulesets/Edit/EditRulesetContainer.cs | 33 +++++++-------- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 42 +++++++++++-------- osu.Game/Rulesets/UI/RulesetContainer.cs | 2 +- 7 files changed, 64 insertions(+), 79 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaEditRulesetContainer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaEditRulesetContainer.cs index dbe6ebb02a..138a2c0273 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaEditRulesetContainer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaEditRulesetContainer.cs @@ -4,36 +4,23 @@ using osu.Framework.Graphics; using OpenTK; using osu.Game.Beatmaps; -using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Mania.Edit { - public class ManiaEditRulesetContainer : EditRulesetContainer + public class ManiaEditRulesetContainer : ManiaRulesetContainer { - public ManiaEditRulesetContainer(Ruleset ruleset, WorkingBeatmap workingBeatmap) - : base(ruleset, workingBeatmap) + public ManiaEditRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) + : base(ruleset, beatmap) { } - protected override RulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap workingBeatmap) - => new RulesetContainer(ruleset, workingBeatmap); - - private new class RulesetContainer : ManiaRulesetContainer + protected override Playfield CreatePlayfield() => new ManiaEditPlayfield(Beatmap.Stages) { - public RulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) - : base(ruleset, beatmap) - { - } - - protected override Playfield CreatePlayfield() => new ManiaEditPlayfield(Beatmap.Stages) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Size = Vector2.One - }; - } + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = Vector2.One + }; } } diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs index 8363d1dc44..fe97f9bc8e 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs @@ -11,11 +11,13 @@ 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.Objects; using osu.Game.Rulesets.Mania.UI; +using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Mania.Edit { - public class ManiaHitObjectComposer : HitObjectComposer + public class ManiaHitObjectComposer : HitObjectComposer { protected new ManiaConfigManager Config => (ManiaConfigManager)base.Config; @@ -31,7 +33,8 @@ namespace osu.Game.Rulesets.Mania.Edit return dependencies; } - protected override EditRulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) => new ManiaEditRulesetContainer(ruleset, beatmap); + protected override RulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) + => new ManiaEditRulesetContainer(ruleset, beatmap); protected override IReadOnlyList CompositionTools => Array.Empty(); diff --git a/osu.Game.Rulesets.Osu/Edit/OsuEditRulesetContainer.cs b/osu.Game.Rulesets.Osu/Edit/OsuEditRulesetContainer.cs index 5da6c2535d..8571de39f4 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuEditRulesetContainer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuEditRulesetContainer.cs @@ -3,34 +3,21 @@ using osu.Framework.Graphics.Cursor; using osu.Game.Beatmaps; -using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.UI; using osu.Game.Rulesets.UI; using OpenTK; namespace osu.Game.Rulesets.Osu.Edit { - public class OsuEditRulesetContainer : EditRulesetContainer + public class OsuEditRulesetContainer : OsuRulesetContainer { - public OsuEditRulesetContainer(Ruleset ruleset, WorkingBeatmap workingBeatmap) - : base(ruleset, workingBeatmap) + public OsuEditRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) + : base(ruleset, beatmap) { } - protected override RulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap workingBeatmap) - => new RulesetContainer(ruleset, workingBeatmap); + protected override CursorContainer CreateCursor() => null; - private new class RulesetContainer : OsuRulesetContainer - { - public RulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) - : base(ruleset, beatmap) - { - } - - protected override CursorContainer CreateCursor() => null; - - protected override Playfield CreatePlayfield() => new OsuPlayfield { Size = Vector2.One }; - } + protected override Playfield CreatePlayfield() => new OsuPlayfield { Size = Vector2.One }; } } diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index 8bf14e3730..2dbd15fdc0 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -9,19 +9,22 @@ using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Tools; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Edit.Masks; +using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.UI; +using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Osu.Edit { - public class OsuHitObjectComposer : HitObjectComposer + public class OsuHitObjectComposer : HitObjectComposer { public OsuHitObjectComposer(Ruleset ruleset) : base(ruleset) { } - protected override EditRulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) => new OsuEditRulesetContainer(ruleset, beatmap); + protected override RulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) + => new OsuEditRulesetContainer(ruleset, beatmap); protected override IReadOnlyList CompositionTools => new[] { diff --git a/osu.Game/Rulesets/Edit/EditRulesetContainer.cs b/osu.Game/Rulesets/Edit/EditRulesetContainer.cs index 8a2d4431b2..d993a7cca2 100644 --- a/osu.Game/Rulesets/Edit/EditRulesetContainer.cs +++ b/osu.Game/Rulesets/Edit/EditRulesetContainer.cs @@ -12,9 +12,10 @@ namespace osu.Game.Rulesets.Edit { public abstract class EditRulesetContainer : CompositeDrawable { - public Playfield Playfield => RulesetContainer.Playfield; - - protected abstract RulesetContainer RulesetContainer { get; } + /// + /// The contained by this . + /// + public abstract Playfield Playfield { get; } internal EditRulesetContainer() { @@ -29,21 +30,23 @@ namespace osu.Game.Rulesets.Edit internal abstract DrawableHitObject Add(HitObject hitObject); } - public abstract class EditRulesetContainer : EditRulesetContainer + public class EditRulesetContainer : EditRulesetContainer where TObject : HitObject { - private readonly Ruleset ruleset; - - private readonly RulesetContainer rulesetContainer; - protected override RulesetContainer RulesetContainer => rulesetContainer; + public override Playfield Playfield => rulesetContainer.Playfield; + private Ruleset ruleset => rulesetContainer.Ruleset; private Beatmap beatmap => rulesetContainer.Beatmap; - protected EditRulesetContainer(Ruleset ruleset, WorkingBeatmap workingBeatmap) - { - this.ruleset = ruleset; + private readonly RulesetContainer rulesetContainer; - InternalChild = rulesetContainer = CreateRulesetContainer(ruleset, workingBeatmap); + public EditRulesetContainer(RulesetContainer rulesetContainer) + { + this.rulesetContainer = rulesetContainer; + + InternalChild = rulesetContainer; + + Playfield.DisplayJudgements.Value = false; } internal override DrawableHitObject Add(HitObject hitObject) @@ -69,11 +72,5 @@ namespace osu.Game.Rulesets.Edit return drawableObject; } - - /// - /// Creates the underlying . - /// - /// - protected abstract RulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap workingBeatmap); } } diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 6212f8adcf..90a3fcd933 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -23,23 +23,24 @@ namespace osu.Game.Rulesets.Edit { public abstract class HitObjectComposer : CompositeDrawable { - private readonly Ruleset ruleset; - public IEnumerable HitObjects => rulesetContainer.Playfield.AllHitObjects; + protected readonly Ruleset Ruleset; + + protected readonly IBindable Beatmap = new Bindable(); + protected IRulesetConfigManager Config { get; private set; } private readonly List layerContainers = new List(); - private readonly IBindable beatmap = new Bindable(); private EditRulesetContainer rulesetContainer; private HitObjectMaskLayer maskLayer; private PlacementContainer placementContainer; - protected HitObjectComposer(Ruleset ruleset) + internal HitObjectComposer(Ruleset ruleset) { - this.ruleset = ruleset; + Ruleset = ruleset; RelativeSizeAxes = Axes.Both; } @@ -47,11 +48,11 @@ namespace osu.Game.Rulesets.Edit [BackgroundDependencyLoader] private void load(IBindableBeatmap beatmap, IFrameBasedClock framedClock) { - this.beatmap.BindTo(beatmap); + Beatmap.BindTo(beatmap); try { - rulesetContainer = CreateRulesetContainer(ruleset, beatmap.Value); + rulesetContainer = CreateRulesetContainer(); rulesetContainer.Clock = framedClock; } catch (Exception e) @@ -126,18 +127,11 @@ namespace osu.Game.Rulesets.Edit var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); dependencies.CacheAs(this); - Config = dependencies.Get().GetConfigFor(ruleset); + Config = dependencies.Get().GetConfigFor(Ruleset); return dependencies; } - protected override void LoadComplete() - { - base.LoadComplete(); - - rulesetContainer.Playfield.DisplayJudgements.Value = false; - } - protected override void UpdateAfterChildren() { base.UpdateAfterChildren(); @@ -152,12 +146,12 @@ namespace osu.Game.Rulesets.Edit } /// - /// Adds a to the and visualises it. + /// Adds a to the and visualises it. /// /// The to add. public void Add(HitObject hitObject) => maskLayer.AddMaskFor(rulesetContainer.Add(hitObject)); - protected abstract EditRulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap); + internal abstract EditRulesetContainer CreateRulesetContainer(); protected abstract IReadOnlyList CompositionTools { get; } @@ -178,4 +172,18 @@ namespace osu.Game.Rulesets.Edit /// protected virtual Container CreateLayerContainer() => new Container { RelativeSizeAxes = Axes.Both }; } + + public abstract class HitObjectComposer : HitObjectComposer + where TObject : HitObject + { + protected HitObjectComposer(Ruleset ruleset) + : base(ruleset) + { + } + + internal override EditRulesetContainer CreateRulesetContainer() + => new EditRulesetContainer(CreateRulesetContainer(Ruleset, Beatmap.Value)); + + protected abstract RulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap); + } } diff --git a/osu.Game/Rulesets/UI/RulesetContainer.cs b/osu.Game/Rulesets/UI/RulesetContainer.cs index e2b5754b9e..3484018fc0 100644 --- a/osu.Game/Rulesets/UI/RulesetContainer.cs +++ b/osu.Game/Rulesets/UI/RulesetContainer.cs @@ -73,7 +73,7 @@ namespace osu.Game.Rulesets.UI /// public readonly CursorContainer Cursor; - protected readonly Ruleset Ruleset; + public readonly Ruleset Ruleset; protected IRulesetConfigManager Config { get; private set; } From 6eb7a030d0aa71dd3e0e1d6771fcf832026c2015 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 17 Oct 2018 18:11:44 +0900 Subject: [PATCH 148/333] Fix placement container not being refreshed upon placement --- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 90a3fcd933..4010218c8c 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -149,7 +149,11 @@ namespace osu.Game.Rulesets.Edit /// Adds a to the and visualises it. /// /// The to add. - public void Add(HitObject hitObject) => maskLayer.AddMaskFor(rulesetContainer.Add(hitObject)); + public void Add(HitObject hitObject) + { + maskLayer.AddMaskFor(rulesetContainer.Add(hitObject)); + placementContainer.Refresh(); + } internal abstract EditRulesetContainer CreateRulesetContainer(); From f42f9cffe34a57b516c298feb9e5a52ee548f96d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 17 Oct 2018 18:12:29 +0900 Subject: [PATCH 149/333] Make HitCirclePlacementMask directly modify hitcircle position --- .../Edit/Masks/HitCirclePlacementMask.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/HitCirclePlacementMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/HitCirclePlacementMask.cs index 08e417cf1a..ca250e25e6 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/HitCirclePlacementMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/HitCirclePlacementMask.cs @@ -19,6 +19,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks AutoSizeAxes = Axes.Both; InternalChild = new HitCircleMask(HitObject); + + HitObject.PositionChanged += _ => Position = HitObject.StackedPosition; } protected override void LoadComplete() @@ -26,21 +28,19 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks base.LoadComplete(); // Fixes a 1-frame position discrpancy due to the first mouse move event happening in the next frame - Position = GetContainingInputManager().CurrentState.Mouse.Position; + HitObject.Position = GetContainingInputManager().CurrentState.Mouse.Position; } protected override bool OnClick(ClickEvent e) { HitObject.StartTime = EditorClock.CurrentTime; - HitObject.Position = e.MousePosition; - EndPlacement(); return true; } protected override bool OnMouseMove(MouseMoveEvent e) { - Position = e.MousePosition; + HitObject.Position = e.MousePosition; return true; } } From b7435c0c5ffb6054ecd49c42c791d14d2b4e67a8 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 17 Oct 2018 18:29:30 +0900 Subject: [PATCH 150/333] Fix border layer not working --- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 4010218c8c..38aad42081 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -61,11 +61,8 @@ namespace osu.Game.Rulesets.Edit return; } - var layerBelowRuleset = new BorderLayer - { - RelativeSizeAxes = Axes.Both, - Child = CreateLayerContainer() - }; + var layerBelowRuleset = CreateLayerContainer(); + layerBelowRuleset.Child = new BorderLayer { RelativeSizeAxes = Axes.Both }; var layerAboveRuleset = CreateLayerContainer(); layerAboveRuleset.Children = new Drawable[] From 5a5e91eaed0eacaaae467e2daaf963d5c9a04c23 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 17 Oct 2018 18:36:47 +0900 Subject: [PATCH 151/333] Add a way to re-invoke ApplyDefaults on placement object --- osu.Game/Rulesets/Edit/PlacementMask.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Edit/PlacementMask.cs b/osu.Game/Rulesets/Edit/PlacementMask.cs index d253638374..36c706db37 100644 --- a/osu.Game/Rulesets/Edit/PlacementMask.cs +++ b/osu.Game/Rulesets/Edit/PlacementMask.cs @@ -2,6 +2,7 @@ // 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.Input; using osu.Framework.Input.Events; @@ -22,6 +23,8 @@ namespace osu.Game.Rulesets.Edit protected IClock EditorClock { get; private set; } + private readonly IBindable beatmap = new Bindable(); + [Resolved] private IPlacementHandler placementHandler { get; set; } @@ -31,11 +34,13 @@ namespace osu.Game.Rulesets.Edit } [BackgroundDependencyLoader] - private void load(IBindableBeatmap workingBeatmap, IAdjustableClock clock) + private void load(IBindableBeatmap beatmap, IAdjustableClock clock) { + this.beatmap.BindTo(beatmap); + EditorClock = clock; - HitObject.ApplyDefaults(workingBeatmap.Value.Beatmap.ControlPointInfo, workingBeatmap.Value.Beatmap.BeatmapInfo.BaseDifficulty); + ApplyDefaultsToHitObject(); } private bool placementBegun; @@ -60,6 +65,11 @@ namespace osu.Game.Rulesets.Edit placementHandler.EndPlacement(HitObject); } + /// + /// Invokes , refreshing and parameters for the . + /// + protected void ApplyDefaultsToHitObject() => HitObject.ApplyDefaults(beatmap.Value.Beatmap.ControlPointInfo, beatmap.Value.Beatmap.BeatmapInfo.BaseDifficulty); + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Parent?.ReceivePositionalInputAt(screenSpacePos) ?? false; protected override bool Handle(UIEvent e) From 0e841628b64d44cbef02ba1bffa6e26f8dfd8bfe Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 18 Oct 2018 16:36:06 +0900 Subject: [PATCH 152/333] Implement hitobject deletion --- .../Visual/TestCaseHitObjectComposer.cs | 2 ++ .../Rulesets/Edit/EditRulesetContainer.cs | 30 +++++++++++++++++++ osu.Game/Rulesets/Edit/HitObjectComposer.cs | 2 ++ .../Screens/Edit/Screens/Compose/Compose.cs | 2 ++ .../Edit/Screens/Compose/IPlacementHandler.cs | 2 ++ .../Compose/Layers/HitObjectMaskLayer.cs | 15 ++++++++++ .../Screens/Compose/Layers/MaskSelection.cs | 21 +++++++++++++ 7 files changed, 74 insertions(+) diff --git a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs index 73df413699..9e1ec7feb2 100644 --- a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs +++ b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs @@ -77,5 +77,7 @@ namespace osu.Game.Tests.Visual } public void EndPlacement(HitObject hitObject) => composer.Add(hitObject); + + public void Delete(HitObject hitObject) => composer.Remove(hitObject); } } diff --git a/osu.Game/Rulesets/Edit/EditRulesetContainer.cs b/osu.Game/Rulesets/Edit/EditRulesetContainer.cs index d993a7cca2..bc54c907ab 100644 --- a/osu.Game/Rulesets/Edit/EditRulesetContainer.cs +++ b/osu.Game/Rulesets/Edit/EditRulesetContainer.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.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; @@ -28,6 +29,13 @@ namespace osu.Game.Rulesets.Edit /// The to add. /// The visual representation of . internal abstract DrawableHitObject Add(HitObject hitObject); + + /// + /// Removes a from the and the display. + /// + /// The to remove. + /// The visual representation of the removed . + internal abstract DrawableHitObject Remove(HitObject hitObject); } public class EditRulesetContainer : EditRulesetContainer @@ -72,5 +80,27 @@ namespace osu.Game.Rulesets.Edit return drawableObject; } + + internal override DrawableHitObject Remove(HitObject hitObject) + { + var tObject = (TObject)hitObject; + + // Remove from beatmap + beatmap.HitObjects.Remove(tObject); + + // Process the beatmap + var processor = ruleset.CreateBeatmapProcessor(beatmap); + + processor.PreProcess(); + processor.PostProcess(); + + // Remove visual representation + var drawableObject = Playfield.AllHitObjects.Single(d => d.HitObject == hitObject); + + rulesetContainer.Playfield.Remove(drawableObject); + rulesetContainer.Playfield.PostProcess(); + + return drawableObject; + } } } diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 38aad42081..13571bda84 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -152,6 +152,8 @@ namespace osu.Game.Rulesets.Edit placementContainer.Refresh(); } + public void Remove(HitObject hitObject) => maskLayer.RemoveMaskFor(rulesetContainer.Remove(hitObject)); + internal abstract EditRulesetContainer CreateRulesetContainer(); protected abstract IReadOnlyList CompositionTools { get; } diff --git a/osu.Game/Screens/Edit/Screens/Compose/Compose.cs b/osu.Game/Screens/Edit/Screens/Compose/Compose.cs index 1617313ecd..ae42942d24 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Compose.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Compose.cs @@ -122,5 +122,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose } public void EndPlacement(HitObject hitObject) => composer.Add(hitObject); + + public void Delete(HitObject hitObject) => composer.Remove(hitObject); } } diff --git a/osu.Game/Screens/Edit/Screens/Compose/IPlacementHandler.cs b/osu.Game/Screens/Edit/Screens/Compose/IPlacementHandler.cs index 894d23b90e..7c788cc7e0 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/IPlacementHandler.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/IPlacementHandler.cs @@ -9,5 +9,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose { void BeginPlacement(HitObject hitObject); void EndPlacement(HitObject hitObject); + + void Delete(HitObject hitObject); } } diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs index c6a4c3de13..3e33ceefcd 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.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; @@ -69,5 +70,19 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers maskContainer.Add(mask); } + + /// + /// Removes a mask for a . + /// + /// The for which to remove the mask. + public void RemoveMaskFor(DrawableHitObject hitObject) + { + var maskToRemove = maskContainer.Single(m => m.HitObject == hitObject); + if (maskToRemove == null) + return; + + maskToRemove.Deselect(); + maskContainer.Remove(maskToRemove); + } } } diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskSelection.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskSelection.cs index 1231737122..4946b35abb 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskSelection.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskSelection.cs @@ -3,15 +3,18 @@ using System; using System.Collections.Generic; +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +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; namespace osu.Game.Screens.Edit.Screens.Compose.Layers { @@ -26,6 +29,9 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers private Drawable outline; + [Resolved] + private IPlacementHandler placementHandler { get; set; } + public MaskSelection() { selectedMasks = new List(); @@ -69,6 +75,21 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers } } + protected override bool OnKeyDown(KeyDownEvent e) + { + if (e.Repeat) + return base.OnKeyDown(e); + + switch (e.Key) + { + case Key.Delete: + foreach (var h in selectedMasks.ToList()) + placementHandler.Delete(h.HitObject.HitObject); + return true; + } + return base.OnKeyDown(e); + } + #endregion #region Selection Handling From 72d48aa7f5b40cc542ce60b5050d2abe7f4ff0e1 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 18 Oct 2018 16:46:30 +0900 Subject: [PATCH 153/333] Add xmldocs to IPlacementHandler --- .../Edit/Screens/Compose/IPlacementHandler.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/osu.Game/Screens/Edit/Screens/Compose/IPlacementHandler.cs b/osu.Game/Screens/Edit/Screens/Compose/IPlacementHandler.cs index 7c788cc7e0..cd213c2885 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/IPlacementHandler.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/IPlacementHandler.cs @@ -7,9 +7,22 @@ namespace osu.Game.Screens.Edit.Screens.Compose { public interface IPlacementHandler { + /// + /// Notifies that a placement has begun. + /// + /// The being placed. void BeginPlacement(HitObject hitObject); + + /// + /// Notifies that a placement has finished. + /// + /// The that has been placed. void EndPlacement(HitObject hitObject); + /// + /// Deletes a . + /// + /// The to delete. void Delete(HitObject hitObject); } } From b351aae93fe5d27810e1561228de9d8cc786a6e5 Mon Sep 17 00:00:00 2001 From: Paul Teng Date: Thu, 18 Oct 2018 07:02:18 -0400 Subject: [PATCH 154/333] Reduce height of song progress handle --- osu.Game/Screens/Play/SongProgress.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/SongProgress.cs b/osu.Game/Screens/Play/SongProgress.cs index 2e2c77c1c8..e921cd602b 100644 --- a/osu.Game/Screens/Play/SongProgress.cs +++ b/osu.Game/Screens/Play/SongProgress.cs @@ -21,7 +21,7 @@ namespace osu.Game.Screens.Play { private const int bottom_bar_height = 5; - private static readonly Vector2 handle_size = new Vector2(14, 25); + private static readonly Vector2 handle_size = new Vector2(14, 18); private const float transition_duration = 200; From 93a3e9fe1168407faa737fbe2389c69d452e511a Mon Sep 17 00:00:00 2001 From: TPGPL Date: Fri, 19 Oct 2018 19:27:24 +0200 Subject: [PATCH 155/333] Add bug issue template --- .github/ISSUE_TEMPLATE/bug-issues.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug-issues.md diff --git a/.github/ISSUE_TEMPLATE/bug-issues.md b/.github/ISSUE_TEMPLATE/bug-issues.md new file mode 100644 index 0000000000..1f3c8e4450 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-issues.md @@ -0,0 +1,16 @@ +--- +name: Bug Report +about: For issues regarding encountered game bugs +--- + + + +**What is your problem:** + +**Describe your problem:** + +**Screenshots or videos showing encountered issue:** + +**osu!lazer version:** + +**Logs:** \ No newline at end of file From 294569f96622b48b83067e31daa86c4ef8e7c560 Mon Sep 17 00:00:00 2001 From: TPGPL Date: Fri, 19 Oct 2018 19:29:56 +0200 Subject: [PATCH 156/333] Add crash issue template --- .github/ISSUE_TEMPLATE/crash-issues.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/crash-issues.md diff --git a/.github/ISSUE_TEMPLATE/crash-issues.md b/.github/ISSUE_TEMPLATE/crash-issues.md new file mode 100644 index 0000000000..4d60c684ab --- /dev/null +++ b/.github/ISSUE_TEMPLATE/crash-issues.md @@ -0,0 +1,18 @@ +--- +name: Crash Report +about: For issues regarding game crashes or permanent freezes +--- + + + +**What is your problem:** + +**Describe your problem:** + +**Screenshots or videos showing encountered issue:** + +**osu!lazer version:** + +**Logs:** + +**Computer Specifications:** \ No newline at end of file From fc95a0a2d592a732cd84b0414a21226243480b68 Mon Sep 17 00:00:00 2001 From: TPGPL Date: Fri, 19 Oct 2018 19:36:02 +0200 Subject: [PATCH 157/333] Add feature issue request --- .github/ISSUE_TEMPLATE/feature-issues.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/feature-issues.md diff --git a/.github/ISSUE_TEMPLATE/feature-issues.md b/.github/ISSUE_TEMPLATE/feature-issues.md new file mode 100644 index 0000000000..ea17bf0e5b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-issues.md @@ -0,0 +1,12 @@ +--- +name: Feature Request +about: Let us know what you would like to see in the game! +--- + + + +**Feature Request:** + +**Describe the feature:** + +**Proposal designs of the feature:** + +**Feature Request:** + +**Describe the feature:** + +**Designs:** From 1682090cd54cac05ca6341da8da5705cea14fcd1 Mon Sep 17 00:00:00 2001 From: TPGPL Date: Fri, 19 Oct 2018 19:40:55 +0200 Subject: [PATCH 159/333] Fix minor issues --- .github/ISSUE_TEMPLATE/bug-issues.md | 10 +++++----- .github/ISSUE_TEMPLATE/crash-issues.md | 12 ++++++------ .github/ISSUE_TEMPLATE/feature-issues.md | 8 ++++---- .github/ISSUE_TEMPLATE/gamefeatures-issues.md | 6 +++--- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug-issues.md b/.github/ISSUE_TEMPLATE/bug-issues.md index 1f3c8e4450..3021a2079d 100644 --- a/.github/ISSUE_TEMPLATE/bug-issues.md +++ b/.github/ISSUE_TEMPLATE/bug-issues.md @@ -3,14 +3,14 @@ name: Bug Report about: For issues regarding encountered game bugs --- - + -**What is your problem:** +**What is your problem:** -**Describe your problem:** +**Describe your problem:** **Screenshots or videos showing encountered issue:** -**osu!lazer version:** +**osu!lazer version:** -**Logs:** \ No newline at end of file +**Logs:** \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/crash-issues.md b/.github/ISSUE_TEMPLATE/crash-issues.md index 4d60c684ab..d5598145c8 100644 --- a/.github/ISSUE_TEMPLATE/crash-issues.md +++ b/.github/ISSUE_TEMPLATE/crash-issues.md @@ -3,16 +3,16 @@ name: Crash Report about: For issues regarding game crashes or permanent freezes --- - + -**What is your problem:** +**What is your problem:** -**Describe your problem:** +**Describe your problem:** **Screenshots or videos showing encountered issue:** -**osu!lazer version:** +**osu!lazer version:** -**Logs:** +**Logs:** -**Computer Specifications:** \ No newline at end of file +**Computer Specifications:** \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature-issues.md b/.github/ISSUE_TEMPLATE/feature-issues.md index ea17bf0e5b..fbc44c5a03 100644 --- a/.github/ISSUE_TEMPLATE/feature-issues.md +++ b/.github/ISSUE_TEMPLATE/feature-issues.md @@ -3,10 +3,10 @@ name: Feature Request about: Let us know what you would like to see in the game! --- - + -**Feature Request:** +**Feature Request:** -**Describe the feature:** +**Describe the feature:** -**Proposal designs of the feature:** diff --git a/.github/ISSUE_TEMPLATE/gamefeatures-issues.md b/.github/ISSUE_TEMPLATE/gamefeatures-issues.md index 0ec4ae3f5a..a94efed32f 100644 --- a/.github/ISSUE_TEMPLATE/gamefeatures-issues.md +++ b/.github/ISSUE_TEMPLATE/gamefeatures-issues.md @@ -3,10 +3,10 @@ name: Game Feature about: For issues regarding features to be found in the game --- - + -**Feature Request:** +**Feature Request:** -**Describe the feature:** +**Describe the feature:** **Designs:** From 6882735d6f9054537e4c3093018faa35b801ea95 Mon Sep 17 00:00:00 2001 From: TPGPL Date: Fri, 19 Oct 2018 20:02:08 +0200 Subject: [PATCH 160/333] Add local storages for macOS and Linux --- .github/ISSUE_TEMPLATE/bug-issues.md | 2 +- .github/ISSUE_TEMPLATE/crash-issues.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug-issues.md b/.github/ISSUE_TEMPLATE/bug-issues.md index 3021a2079d..ea29402902 100644 --- a/.github/ISSUE_TEMPLATE/bug-issues.md +++ b/.github/ISSUE_TEMPLATE/bug-issues.md @@ -13,4 +13,4 @@ about: For issues regarding encountered game bugs **osu!lazer version:** -**Logs:** \ No newline at end of file +**Logs:** \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/crash-issues.md b/.github/ISSUE_TEMPLATE/crash-issues.md index d5598145c8..7cf6acd549 100644 --- a/.github/ISSUE_TEMPLATE/crash-issues.md +++ b/.github/ISSUE_TEMPLATE/crash-issues.md @@ -13,6 +13,6 @@ about: For issues regarding game crashes or permanent freezes **osu!lazer version:** -**Logs:** +**Logs:** **Computer Specifications:** \ No newline at end of file From 8a2a6a3ecbf7cc9507c66b601a17a917a1d6fe58 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 23 Oct 2018 14:38:27 +0900 Subject: [PATCH 161/333] Preserve the beatmap's version --- .../Formats/LegacyBeatmapDecoderTest.cs | 21 +++++++++++++++++++ osu.Game.Tests/Resources/beatmap-version.osu | 1 + osu.Game/Beatmaps/BeatmapInfo.cs | 1 - osu.Game/Beatmaps/WorkingBeatmap.cs | 7 ++++++- 4 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 osu.Game.Tests/Resources/beatmap-version.osu diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index af63a39662..f1ae366ee1 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -8,11 +8,13 @@ using OpenTK.Graphics; using osu.Game.Tests.Resources; using System.Linq; using osu.Game.Audio; +using osu.Game.Beatmaps; using osu.Game.Rulesets.Objects.Types; using osu.Game.Beatmaps.Formats; using osu.Game.Beatmaps.Timing; using osu.Game.Rulesets.Catch.Beatmaps; using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Beatmaps; using osu.Game.Skinning; @@ -21,6 +23,25 @@ namespace osu.Game.Tests.Beatmaps.Formats [TestFixture] public class LegacyBeatmapDecoderTest { + [Test] + public void TestDecodeBeatmapVersion() + { + using (var resStream = Resource.OpenResource("beatmap-version.osu")) + using (var stream = new StreamReader(resStream)) + { + var decoder = Decoder.GetDecoder(stream); + + stream.BaseStream.Position = 0; + stream.DiscardBufferedData(); + + var working = new TestWorkingBeatmap(decoder.Decode(stream)); + + Assert.AreEqual(6, working.BeatmapInfo.BeatmapVersion); + Assert.AreEqual(6, working.Beatmap.BeatmapInfo.BeatmapVersion); + Assert.AreEqual(6, working.GetPlayableBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo.BeatmapVersion); + } + } + [Test] public void TestDecodeBeatmapGeneral() { diff --git a/osu.Game.Tests/Resources/beatmap-version.osu b/osu.Game.Tests/Resources/beatmap-version.osu new file mode 100644 index 0000000000..5749054ac4 --- /dev/null +++ b/osu.Game.Tests/Resources/beatmap-version.osu @@ -0,0 +1 @@ +osu file format v6 \ No newline at end of file diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs index 1aa4818393..3e1f3bdf54 100644 --- a/osu.Game/Beatmaps/BeatmapInfo.cs +++ b/osu.Game/Beatmaps/BeatmapInfo.cs @@ -19,7 +19,6 @@ namespace osu.Game.Beatmaps [JsonIgnore] public int ID { get; set; } - //TODO: should be in database public int BeatmapVersion; private int? onlineBeatmapID; diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index e0a22460ef..5b76122616 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -41,8 +41,13 @@ namespace osu.Game.Beatmaps beatmap = new RecyclableLazy(() => { var b = GetBeatmap() ?? new Beatmap(); - // use the database-backed info. + + // The original beatmap version needs to be preserved as the database doesn't contain it + BeatmapInfo.BeatmapVersion = b.BeatmapInfo.BeatmapVersion; + + // Use the database-backed info for more up-to-date values (beatmap id, ranked status, etc) b.BeatmapInfo = BeatmapInfo; + return b; }); From 94093ac9488c5065737cd20f731a458dd16ef722 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 23 Oct 2018 18:04:38 +0900 Subject: [PATCH 162/333] Update beatmap search API to match latest osu-web structure --- .../API/Requests/SearchBeatmapSetsRequest.cs | 6 +++--- .../API/Requests/SearchBeatmapSetsResponse.cs | 20 +++++++++++++++++++ osu.Game/Overlays/DirectOverlay.cs | 2 +- 3 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 osu.Game/Online/API/Requests/SearchBeatmapSetsResponse.cs diff --git a/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs b/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs index 3c808d1bee..ffea7b83e1 100644 --- a/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs +++ b/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs @@ -1,16 +1,14 @@ // 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.ComponentModel; -using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; using osu.Game.Overlays.Direct; using osu.Game.Rulesets; namespace osu.Game.Online.API.Requests { - public class SearchBeatmapSetsRequest : APIRequest> + public class SearchBeatmapSetsRequest : APIRequest { private readonly string query; private readonly RulesetInfo ruleset; @@ -35,6 +33,7 @@ namespace osu.Game.Online.API.Requests public enum BeatmapSearchCategory { Any = 7, + [Description("Ranked & Approved")] RankedApproved = 0, Approved = 1, @@ -43,6 +42,7 @@ namespace osu.Game.Online.API.Requests Qualified = 3, Pending = 4, Graveyard = 5, + [Description("My Maps")] MyMaps = 6, } diff --git a/osu.Game/Online/API/Requests/SearchBeatmapSetsResponse.cs b/osu.Game/Online/API/Requests/SearchBeatmapSetsResponse.cs new file mode 100644 index 0000000000..cf8b40d068 --- /dev/null +++ b/osu.Game/Online/API/Requests/SearchBeatmapSetsResponse.cs @@ -0,0 +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 Newtonsoft.Json; +using osu.Game.Online.API.Requests.Responses; + +namespace osu.Game.Online.API.Requests +{ + public class SearchBeatmapSetsResponse + { + public IEnumerable BeatmapSets; + + /// + /// A collection of parameters which should be passed to the search endpoint to fetch the next page. + /// + [JsonProperty("cursor")] + public dynamic CursorJson; + } +} diff --git a/osu.Game/Overlays/DirectOverlay.cs b/osu.Game/Overlays/DirectOverlay.cs index f63d314053..641f57d25f 100644 --- a/osu.Game/Overlays/DirectOverlay.cs +++ b/osu.Game/Overlays/DirectOverlay.cs @@ -288,7 +288,7 @@ namespace osu.Game.Overlays { Task.Run(() => { - var sets = response.Select(r => r.ToBeatmapSet(rulesets)).ToList(); + var sets = response.BeatmapSets.Select(r => r.ToBeatmapSet(rulesets)).ToList(); // may not need scheduling; loads async internally. Schedule(() => From 88aca465006312db05761539387e3e67605f0e8d Mon Sep 17 00:00:00 2001 From: HoLLy Date: Wed, 24 Oct 2018 18:53:22 +0200 Subject: [PATCH 163/333] Fade MetadataSection back in if non-null Text is set --- osu.Game/Screens/Select/BeatmapDetails.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index f7b955941d..9a16c76c44 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.cs @@ -341,6 +341,7 @@ namespace osu.Game.Screens.Select return; } + this.FadeIn(transition_duration); setTextAsync(value); } } From ea6db8b79376c56f4d9b2a8f81f8fe35ae54645b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 25 Oct 2018 18:16:25 +0900 Subject: [PATCH 164/333] Make the hitobject masks move within their placement/selection --- .../Edit/Masks/HitCircleMask.cs | 12 +++-- .../Edit/Masks/HitCirclePlacementMask.cs | 6 --- .../Edit/Masks/HitCircleSelectionMask.cs | 8 --- .../Edit/Masks/SliderBodyMask.cs | 51 +++++++++++++++++++ .../Edit/Masks/SliderCircleMask.cs | 33 ++++++++++++ .../Edit/Masks/SliderCircleSelectionMask.cs | 42 +-------------- .../Edit/Masks/SliderPosition.cs | 11 ++++ .../Edit/Masks/SliderSelectionMask.cs | 46 ++--------------- osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs | 2 +- osu.Game.Rulesets.Osu/Objects/Slider.cs | 15 ++++++ osu.Game/Rulesets/Edit/PlacementMask.cs | 3 ++ osu.Game/Rulesets/Edit/SelectionMask.cs | 9 +++- 12 files changed, 137 insertions(+), 101 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Edit/Masks/SliderBodyMask.cs create mode 100644 osu.Game.Rulesets.Osu/Edit/Masks/SliderCircleMask.cs create mode 100644 osu.Game.Rulesets.Osu/Edit/Masks/SliderPosition.cs diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMask.cs index 9576e0fa91..696726e8bf 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMask.cs @@ -18,22 +18,28 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks public HitCircleMask(HitCircle hitCircle) { this.hitCircle = hitCircle; - Anchor = Anchor.Centre; + Origin = Anchor.Centre; Size = new Vector2((float)OsuHitObject.OBJECT_RADIUS * 2); - CornerRadius = Size.X / 2; - AddInternal(new RingPiece()); + InternalChild = new RingPiece(); + + hitCircle.PositionChanged += _ => UpdatePosition(); + hitCircle.StackHeightChanged += _ => UpdatePosition(); } [BackgroundDependencyLoader] private void load(OsuColour colours) { Colour = colours.Yellow; + + UpdatePosition(); } + protected virtual void UpdatePosition() => Position = hitCircle.StackedPosition; + protected override void Update() { base.Update(); diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/HitCirclePlacementMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/HitCirclePlacementMask.cs index ca250e25e6..2c259f562d 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/HitCirclePlacementMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/HitCirclePlacementMask.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 osu.Framework.Graphics; using osu.Framework.Input.Events; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Osu.Objects; @@ -15,12 +14,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks public HitCirclePlacementMask() : base(new HitCircle()) { - Origin = Anchor.Centre; - AutoSizeAxes = Axes.Both; - InternalChild = new HitCircleMask(HitObject); - - HitObject.PositionChanged += _ => Position = HitObject.StackedPosition; } protected override void LoadComplete() diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleSelectionMask.cs index f4e4bb2145..49ff955896 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleSelectionMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleSelectionMask.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 osu.Framework.Graphics; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; @@ -13,14 +12,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks public HitCircleSelectionMask(DrawableHitCircle hitCircle) : base(hitCircle) { - Origin = Anchor.Centre; - AutoSizeAxes = Axes.Both; - Position = hitCircle.Position; - InternalChild = new HitCircleMask((HitCircle)hitCircle.HitObject); - - hitCircle.HitObject.PositionChanged += _ => Position = hitCircle.HitObject.StackedPosition; - hitCircle.HitObject.StackHeightChanged += _ => Position = hitCircle.HitObject.StackedPosition; } } } diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderBodyMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderBodyMask.cs new file mode 100644 index 0000000000..c95b2d7722 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderBodyMask.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 osu.Framework.Allocation; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; +using OpenTK.Graphics; + +namespace osu.Game.Rulesets.Osu.Edit.Masks +{ + public class SliderBodyMask : CompositeDrawable + { + private readonly Slider slider; + private readonly SliderBody body; + + public SliderBodyMask(Slider slider) + { + this.slider = slider; + InternalChild = body = new SliderBody(slider) + { + AccentColour = Color4.Transparent, + PathWidth = slider.Scale * 64 + }; + + slider.PositionChanged += _ => updatePosition(); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + body.BorderColour = colours.Yellow; + + updatePosition(); + } + + private void updatePosition() => Position = slider.StackedPosition; + + protected override void Update() + { + base.Update(); + + Size = body.Size; + OriginPosition = body.PathOffset; + + // Need to cause one update + body.UpdateProgress(0); + } + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderCircleMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderCircleMask.cs new file mode 100644 index 0000000000..de128552c6 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderCircleMask.cs @@ -0,0 +1,33 @@ +// 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.Objects; + +namespace osu.Game.Rulesets.Osu.Edit.Masks +{ + public class SliderCircleMask : HitCircleMask + { + private readonly Slider slider; + private readonly SliderPosition position; + + public SliderCircleMask(Slider slider, SliderPosition position) + : base(slider.HeadCircle) + { + this.slider = slider; + this.position = position; + } + + protected override void UpdatePosition() + { + switch (position) + { + case SliderPosition.Start: + Position = slider.StackedPosition + slider.Curve.PositionAt(0); + break; + case SliderPosition.End: + Position = slider.StackedPosition + slider.Curve.PositionAt(1); + break; + } + } + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderCircleSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderCircleSelectionMask.cs index 1ed22c2ac1..ebbb050c18 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderCircleSelectionMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderCircleSelectionMask.cs @@ -1,60 +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.Allocation; -using osu.Framework.Graphics; -using osu.Game.Graphics; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; -using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; -using OpenTK; namespace osu.Game.Rulesets.Osu.Edit.Masks { public class SliderCircleSelectionMask : SelectionMask { - public SliderCircleSelectionMask(DrawableHitCircle sliderHead, DrawableSlider slider) - : this(sliderHead, Vector2.Zero, slider) - { - } - - public SliderCircleSelectionMask(DrawableSliderTail sliderTail, DrawableSlider slider) - : this(sliderTail, ((Slider)slider.HitObject).Curve.PositionAt(1), slider) - { - } - - private readonly DrawableOsuHitObject hitObject; - - private SliderCircleSelectionMask(DrawableOsuHitObject hitObject, Vector2 position, DrawableSlider slider) + public SliderCircleSelectionMask(DrawableOsuHitObject hitObject, Slider slider, SliderPosition position) : base(hitObject) { - this.hitObject = hitObject; - - Origin = Anchor.Centre; - - Position = position; - Size = slider.HeadCircle.Size; - Scale = slider.HeadCircle.Scale; - - AddInternal(new RingPiece()); + InternalChild = new SliderCircleMask(slider, position); Select(); } - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - Colour = colours.Yellow; - } - - protected override void Update() - { - base.Update(); - - RelativeAnchorPosition = hitObject.RelativeAnchorPosition; - } - // 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; } diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderPosition.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderPosition.cs new file mode 100644 index 0000000000..dc5f670d48 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderPosition.cs @@ -0,0 +1,11 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +namespace osu.Game.Rulesets.Osu.Edit.Masks +{ + public enum SliderPosition + { + Start, + End + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderSelectionMask.cs index b775854038..c330641bcf 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderSelectionMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderSelectionMask.cs @@ -1,67 +1,31 @@ // 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.Primitives; -using osu.Game.Graphics; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; -using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; using OpenTK; -using OpenTK.Graphics; namespace osu.Game.Rulesets.Osu.Edit.Masks { public class SliderSelectionMask : SelectionMask { - private readonly SliderBody body; - private readonly DrawableSlider slider; + private readonly SliderCircleSelectionMask headMask; public SliderSelectionMask(DrawableSlider slider) : base(slider) { - this.slider = slider; - - Position = slider.Position; - var sliderObject = (Slider)slider.HitObject; InternalChildren = new Drawable[] { - body = new SliderBody(sliderObject) - { - AccentColour = Color4.Transparent, - PathWidth = sliderObject.Scale * 64 - }, - new SliderCircleSelectionMask(slider.HeadCircle, slider), - new SliderCircleSelectionMask(slider.TailCircle, slider), + new SliderBodyMask(sliderObject), + headMask = new SliderCircleSelectionMask(slider.HeadCircle, sliderObject, SliderPosition.Start), + new SliderCircleSelectionMask(slider.TailCircle, sliderObject, SliderPosition.End), }; - - sliderObject.PositionChanged += _ => Position = slider.Position; } - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - body.BorderColour = colours.Yellow; - } - - protected override void Update() - { - base.Update(); - - Size = slider.Size; - OriginPosition = slider.OriginPosition; - - // Need to cause one update - body.UpdateProgress(0); - } - - public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => body.ReceivePositionalInputAt(screenSpacePos); - - public override Vector2 SelectionPoint => ToScreenSpace(OriginPosition); - public override Quad SelectionQuad => body.PathDrawQuad; + public override Vector2 SelectionPoint => headMask.SelectionPoint; } } diff --git a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs index ab8f01f5d3..140f875a6f 100644 --- a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Osu.Objects private Vector2 position; - public Vector2 Position + public virtual Vector2 Position { get => position; set diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 7a0dcc77a6..9a3bae96b0 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -70,6 +70,21 @@ namespace osu.Game.Rulesets.Osu.Objects set { Curve.Distance = value; } } + public override Vector2 Position + { + get => base.Position; + set + { + base.Position = value; + + if (HeadCircle != null) + HeadCircle.Position = value; + + if (TailCircle != null) + TailCircle.Position = EndPosition; + } + } + public double? LegacyLastTickOffset { get; set; } /// diff --git a/osu.Game/Rulesets/Edit/PlacementMask.cs b/osu.Game/Rulesets/Edit/PlacementMask.cs index 36c706db37..381dc5f7f0 100644 --- a/osu.Game/Rulesets/Edit/PlacementMask.cs +++ b/osu.Game/Rulesets/Edit/PlacementMask.cs @@ -3,6 +3,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.Input.Events; @@ -31,6 +32,8 @@ namespace osu.Game.Rulesets.Edit public PlacementMask(HitObject hitObject) { HitObject = hitObject; + + RelativeSizeAxes = Axes.Both; } [BackgroundDependencyLoader] diff --git a/osu.Game/Rulesets/Edit/SelectionMask.cs b/osu.Game/Rulesets/Edit/SelectionMask.cs index 9582c30457..3b78d5aaf6 100644 --- a/osu.Game/Rulesets/Edit/SelectionMask.cs +++ b/osu.Game/Rulesets/Edit/SelectionMask.cs @@ -3,6 +3,7 @@ using System; using osu.Framework; +using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Primitives; using osu.Framework.Input.Events; @@ -52,6 +53,8 @@ namespace osu.Game.Rulesets.Edit { HitObject = hitObject; + RelativeSizeAxes = Axes.Both; + AlwaysPresent = true; Alpha = 0; } @@ -94,6 +97,8 @@ namespace osu.Game.Rulesets.Edit public bool IsSelected => State == SelectionState.Selected; + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => HitObject.ReceivePositionalInputAt(screenSpacePos); + private bool selectionRequested; protected override bool OnMouseDown(MouseDownEvent e) @@ -132,11 +137,11 @@ namespace osu.Game.Rulesets.Edit /// /// The screen-space point that causes this to be selected. /// - public virtual Vector2 SelectionPoint => ScreenSpaceDrawQuad.Centre; + public virtual Vector2 SelectionPoint => HitObject.ScreenSpaceDrawQuad.Centre; /// /// The screen-space quad that outlines this for selections. /// - public virtual Quad SelectionQuad => ScreenSpaceDrawQuad; + public virtual Quad SelectionQuad => HitObject.ScreenSpaceDrawQuad; } } From d19f80835bbb88f4cf41e5520eb9e34434b15323 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 25 Oct 2018 18:26:28 +0900 Subject: [PATCH 165/333] Adjust namespaces --- osu.Game.Rulesets.Osu/Edit/HitCircleCompositionTool.cs | 2 +- .../Masks/{ => HitCircle/Components}/HitCircleMask.cs | 6 +++--- .../Edit/Masks/{ => HitCircle}/HitCirclePlacementMask.cs | 8 ++++---- .../Edit/Masks/{ => HitCircle}/HitCircleSelectionMask.cs | 6 +++--- .../Edit/Masks/{ => Slider/Components}/SliderBodyMask.cs | 7 +++---- .../Masks/{ => Slider/Components}/SliderCircleMask.cs | 8 ++++---- .../Edit/Masks/{ => Slider}/SliderCircleSelectionMask.cs | 6 +++--- .../Edit/Masks/{ => Slider}/SliderPosition.cs | 2 +- .../Edit/Masks/{ => Slider}/SliderSelectionMask.cs | 6 +++--- osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs | 3 ++- osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs | 3 ++- 11 files changed, 29 insertions(+), 28 deletions(-) rename osu.Game.Rulesets.Osu/Edit/Masks/{ => HitCircle/Components}/HitCircleMask.cs (87%) rename osu.Game.Rulesets.Osu/Edit/Masks/{ => HitCircle}/HitCirclePlacementMask.cs (81%) rename osu.Game.Rulesets.Osu/Edit/Masks/{ => HitCircle}/HitCircleSelectionMask.cs (67%) rename osu.Game.Rulesets.Osu/Edit/Masks/{ => Slider/Components}/SliderBodyMask.cs (88%) rename osu.Game.Rulesets.Osu/Edit/Masks/{ => Slider/Components}/SliderCircleMask.cs (76%) rename osu.Game.Rulesets.Osu/Edit/Masks/{ => Slider}/SliderCircleSelectionMask.cs (81%) rename osu.Game.Rulesets.Osu/Edit/Masks/{ => Slider}/SliderPosition.cs (82%) rename osu.Game.Rulesets.Osu/Edit/Masks/{ => Slider}/SliderSelectionMask.cs (84%) diff --git a/osu.Game.Rulesets.Osu/Edit/HitCircleCompositionTool.cs b/osu.Game.Rulesets.Osu/Edit/HitCircleCompositionTool.cs index fdf791d2d1..7f53409a32 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; +using osu.Game.Rulesets.Osu.Edit.Masks.HitCircle; using osu.Game.Rulesets.Osu.Objects; namespace osu.Game.Rulesets.Osu.Edit diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircle/Components/HitCircleMask.cs similarity index 87% rename from osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMask.cs rename to osu.Game.Rulesets.Osu/Edit/Masks/HitCircle/Components/HitCircleMask.cs index 696726e8bf..b43399ff18 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircle/Components/HitCircleMask.cs @@ -9,13 +9,13 @@ using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; using OpenTK; -namespace osu.Game.Rulesets.Osu.Edit.Masks +namespace osu.Game.Rulesets.Osu.Edit.Masks.HitCircle.Components { public class HitCircleMask : CompositeDrawable { - private readonly HitCircle hitCircle; + private readonly Objects.HitCircle hitCircle; - public HitCircleMask(HitCircle hitCircle) + public HitCircleMask(Objects.HitCircle hitCircle) { this.hitCircle = hitCircle; diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/HitCirclePlacementMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircle/HitCirclePlacementMask.cs similarity index 81% rename from osu.Game.Rulesets.Osu/Edit/Masks/HitCirclePlacementMask.cs rename to osu.Game.Rulesets.Osu/Edit/Masks/HitCircle/HitCirclePlacementMask.cs index 2c259f562d..c7bc7decc4 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/HitCirclePlacementMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircle/HitCirclePlacementMask.cs @@ -3,16 +3,16 @@ using osu.Framework.Input.Events; using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Edit.Masks.HitCircle.Components; -namespace osu.Game.Rulesets.Osu.Edit.Masks +namespace osu.Game.Rulesets.Osu.Edit.Masks.HitCircle { public class HitCirclePlacementMask : PlacementMask { - public new HitCircle HitObject => (HitCircle)base.HitObject; + public new Objects.HitCircle HitObject => (Objects.HitCircle)base.HitObject; public HitCirclePlacementMask() - : base(new HitCircle()) + : base(new Objects.HitCircle()) { InternalChild = new HitCircleMask(HitObject); } diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircle/HitCircleSelectionMask.cs similarity index 67% rename from osu.Game.Rulesets.Osu/Edit/Masks/HitCircleSelectionMask.cs rename to osu.Game.Rulesets.Osu/Edit/Masks/HitCircle/HitCircleSelectionMask.cs index 49ff955896..dd6bcc6fad 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleSelectionMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircle/HitCircleSelectionMask.cs @@ -2,17 +2,17 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Edit.Masks.HitCircle.Components; using osu.Game.Rulesets.Osu.Objects.Drawables; -namespace osu.Game.Rulesets.Osu.Edit.Masks +namespace osu.Game.Rulesets.Osu.Edit.Masks.HitCircle { public class HitCircleSelectionMask : SelectionMask { public HitCircleSelectionMask(DrawableHitCircle hitCircle) : base(hitCircle) { - InternalChild = new HitCircleMask((HitCircle)hitCircle.HitObject); + InternalChild = new HitCircleMask((Objects.HitCircle)hitCircle.HitObject); } } } diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderBodyMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/Slider/Components/SliderBodyMask.cs similarity index 88% rename from osu.Game.Rulesets.Osu/Edit/Masks/SliderBodyMask.cs rename to osu.Game.Rulesets.Osu/Edit/Masks/Slider/Components/SliderBodyMask.cs index c95b2d7722..733a777dff 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderBodyMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/Slider/Components/SliderBodyMask.cs @@ -4,18 +4,17 @@ using osu.Framework.Allocation; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; -using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; using OpenTK.Graphics; -namespace osu.Game.Rulesets.Osu.Edit.Masks +namespace osu.Game.Rulesets.Osu.Edit.Masks.Slider.Components { public class SliderBodyMask : CompositeDrawable { - private readonly Slider slider; + private readonly Objects.Slider slider; private readonly SliderBody body; - public SliderBodyMask(Slider slider) + public SliderBodyMask(Objects.Slider slider) { this.slider = slider; InternalChild = body = new SliderBody(slider) diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderCircleMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/Slider/Components/SliderCircleMask.cs similarity index 76% rename from osu.Game.Rulesets.Osu/Edit/Masks/SliderCircleMask.cs rename to osu.Game.Rulesets.Osu/Edit/Masks/Slider/Components/SliderCircleMask.cs index de128552c6..37c0846285 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderCircleMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/Slider/Components/SliderCircleMask.cs @@ -1,16 +1,16 @@ // 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.Objects; +using osu.Game.Rulesets.Osu.Edit.Masks.HitCircle.Components; -namespace osu.Game.Rulesets.Osu.Edit.Masks +namespace osu.Game.Rulesets.Osu.Edit.Masks.Slider.Components { public class SliderCircleMask : HitCircleMask { - private readonly Slider slider; + private readonly Objects.Slider slider; private readonly SliderPosition position; - public SliderCircleMask(Slider slider, SliderPosition position) + public SliderCircleMask(Objects.Slider slider, SliderPosition position) : base(slider.HeadCircle) { this.slider = slider; diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderCircleSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/Slider/SliderCircleSelectionMask.cs similarity index 81% rename from osu.Game.Rulesets.Osu/Edit/Masks/SliderCircleSelectionMask.cs rename to osu.Game.Rulesets.Osu/Edit/Masks/Slider/SliderCircleSelectionMask.cs index ebbb050c18..22aadba478 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderCircleSelectionMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/Slider/SliderCircleSelectionMask.cs @@ -2,14 +2,14 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Edit.Masks.Slider.Components; using osu.Game.Rulesets.Osu.Objects.Drawables; -namespace osu.Game.Rulesets.Osu.Edit.Masks +namespace osu.Game.Rulesets.Osu.Edit.Masks.Slider { public class SliderCircleSelectionMask : SelectionMask { - public SliderCircleSelectionMask(DrawableOsuHitObject hitObject, Slider slider, SliderPosition position) + public SliderCircleSelectionMask(DrawableOsuHitObject hitObject, Objects.Slider slider, SliderPosition position) : base(hitObject) { InternalChild = new SliderCircleMask(slider, position); diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderPosition.cs b/osu.Game.Rulesets.Osu/Edit/Masks/Slider/SliderPosition.cs similarity index 82% rename from osu.Game.Rulesets.Osu/Edit/Masks/SliderPosition.cs rename to osu.Game.Rulesets.Osu/Edit/Masks/Slider/SliderPosition.cs index dc5f670d48..07f45af3ef 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderPosition.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/Slider/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 +namespace osu.Game.Rulesets.Osu.Edit.Masks.Slider { public enum SliderPosition { diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/Slider/SliderSelectionMask.cs similarity index 84% rename from osu.Game.Rulesets.Osu/Edit/Masks/SliderSelectionMask.cs rename to osu.Game.Rulesets.Osu/Edit/Masks/Slider/SliderSelectionMask.cs index c330641bcf..e22a8119f9 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderSelectionMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/Slider/SliderSelectionMask.cs @@ -3,11 +3,11 @@ using osu.Framework.Graphics; using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Edit.Masks.Slider.Components; using osu.Game.Rulesets.Osu.Objects.Drawables; using OpenTK; -namespace osu.Game.Rulesets.Osu.Edit.Masks +namespace osu.Game.Rulesets.Osu.Edit.Masks.Slider { public class SliderSelectionMask : SelectionMask { @@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks public SliderSelectionMask(DrawableSlider slider) : base(slider) { - var sliderObject = (Slider)slider.HitObject; + var sliderObject = (Objects.Slider)slider.HitObject; InternalChildren = new Drawable[] { diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index 2dbd15fdc0..df72d2acca 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -8,7 +8,8 @@ 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; +using osu.Game.Rulesets.Osu.Edit.Masks.HitCircle; +using osu.Game.Rulesets.Osu.Edit.Masks.Slider; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.UI; diff --git a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs index 9e1ec7feb2..8b7355e456 100644 --- a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs +++ b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs @@ -13,7 +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; +using osu.Game.Rulesets.Osu.Edit.Masks.HitCircle; +using osu.Game.Rulesets.Osu.Edit.Masks.HitCircle.Components; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Screens.Edit.Screens.Compose; using osu.Game.Screens.Edit.Screens.Compose.Layers; From e14719e44086c4556d80d52c57d8e28465745193 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 25 Oct 2018 18:28:04 +0900 Subject: [PATCH 166/333] Mask -> Piece for non-mask components --- .../Components/{HitCircleMask.cs => HitCirclePiece.cs} | 4 ++-- .../Edit/Masks/HitCircle/HitCirclePlacementMask.cs | 2 +- .../Edit/Masks/HitCircle/HitCircleSelectionMask.cs | 2 +- .../Slider/Components/{SliderBodyMask.cs => BodyPiece.cs} | 4 ++-- .../Components/{SliderCircleMask.cs => SliderCirclePiece.cs} | 4 ++-- .../Edit/Masks/Slider/SliderCircleSelectionMask.cs | 2 +- .../Edit/Masks/Slider/SliderSelectionMask.cs | 2 +- osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs | 2 +- 8 files changed, 11 insertions(+), 11 deletions(-) rename osu.Game.Rulesets.Osu/Edit/Masks/HitCircle/Components/{HitCircleMask.cs => HitCirclePiece.cs} (92%) rename osu.Game.Rulesets.Osu/Edit/Masks/Slider/Components/{SliderBodyMask.cs => BodyPiece.cs} (92%) rename osu.Game.Rulesets.Osu/Edit/Masks/Slider/Components/{SliderCircleMask.cs => SliderCirclePiece.cs} (87%) diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircle/Components/HitCircleMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircle/Components/HitCirclePiece.cs similarity index 92% rename from osu.Game.Rulesets.Osu/Edit/Masks/HitCircle/Components/HitCircleMask.cs rename to osu.Game.Rulesets.Osu/Edit/Masks/HitCircle/Components/HitCirclePiece.cs index b43399ff18..7f6ee32427 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircle/Components/HitCircleMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircle/Components/HitCirclePiece.cs @@ -11,11 +11,11 @@ using OpenTK; namespace osu.Game.Rulesets.Osu.Edit.Masks.HitCircle.Components { - public class HitCircleMask : CompositeDrawable + public class HitCirclePiece : CompositeDrawable { private readonly Objects.HitCircle hitCircle; - public HitCircleMask(Objects.HitCircle hitCircle) + public HitCirclePiece(Objects.HitCircle hitCircle) { this.hitCircle = hitCircle; diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircle/HitCirclePlacementMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircle/HitCirclePlacementMask.cs index c7bc7decc4..d172b87b44 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircle/HitCirclePlacementMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircle/HitCirclePlacementMask.cs @@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.HitCircle public HitCirclePlacementMask() : base(new Objects.HitCircle()) { - InternalChild = new HitCircleMask(HitObject); + InternalChild = new HitCirclePiece(HitObject); } protected override void LoadComplete() diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircle/HitCircleSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircle/HitCircleSelectionMask.cs index dd6bcc6fad..eb9696baa0 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircle/HitCircleSelectionMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircle/HitCircleSelectionMask.cs @@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.HitCircle public HitCircleSelectionMask(DrawableHitCircle hitCircle) : base(hitCircle) { - InternalChild = new HitCircleMask((Objects.HitCircle)hitCircle.HitObject); + InternalChild = new HitCirclePiece((Objects.HitCircle)hitCircle.HitObject); } } } diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/Slider/Components/SliderBodyMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/Slider/Components/BodyPiece.cs similarity index 92% rename from osu.Game.Rulesets.Osu/Edit/Masks/Slider/Components/SliderBodyMask.cs rename to osu.Game.Rulesets.Osu/Edit/Masks/Slider/Components/BodyPiece.cs index 733a777dff..ddf591b401 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/Slider/Components/SliderBodyMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/Slider/Components/BodyPiece.cs @@ -9,12 +9,12 @@ using OpenTK.Graphics; namespace osu.Game.Rulesets.Osu.Edit.Masks.Slider.Components { - public class SliderBodyMask : CompositeDrawable + public class BodyPiece : CompositeDrawable { private readonly Objects.Slider slider; private readonly SliderBody body; - public SliderBodyMask(Objects.Slider slider) + public BodyPiece(Objects.Slider slider) { this.slider = slider; InternalChild = body = new SliderBody(slider) diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/Slider/Components/SliderCircleMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/Slider/Components/SliderCirclePiece.cs similarity index 87% rename from osu.Game.Rulesets.Osu/Edit/Masks/Slider/Components/SliderCircleMask.cs rename to osu.Game.Rulesets.Osu/Edit/Masks/Slider/Components/SliderCirclePiece.cs index 37c0846285..b1c05574d4 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/Slider/Components/SliderCircleMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/Slider/Components/SliderCirclePiece.cs @@ -5,12 +5,12 @@ using osu.Game.Rulesets.Osu.Edit.Masks.HitCircle.Components; namespace osu.Game.Rulesets.Osu.Edit.Masks.Slider.Components { - public class SliderCircleMask : HitCircleMask + public class SliderCirclePiece : HitCirclePiece { private readonly Objects.Slider slider; private readonly SliderPosition position; - public SliderCircleMask(Objects.Slider slider, SliderPosition position) + public SliderCirclePiece(Objects.Slider slider, SliderPosition position) : base(slider.HeadCircle) { this.slider = slider; diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/Slider/SliderCircleSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/Slider/SliderCircleSelectionMask.cs index 22aadba478..e65a3f2665 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/Slider/SliderCircleSelectionMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/Slider/SliderCircleSelectionMask.cs @@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.Slider public SliderCircleSelectionMask(DrawableOsuHitObject hitObject, Objects.Slider slider, SliderPosition position) : base(hitObject) { - InternalChild = new SliderCircleMask(slider, position); + InternalChild = new SliderCirclePiece(slider, position); Select(); } diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/Slider/SliderSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/Slider/SliderSelectionMask.cs index e22a8119f9..e7a8652ed7 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/Slider/SliderSelectionMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/Slider/SliderSelectionMask.cs @@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.Slider InternalChildren = new Drawable[] { - new SliderBodyMask(sliderObject), + new BodyPiece(sliderObject), headMask = new SliderCircleSelectionMask(slider.HeadCircle, sliderObject, SliderPosition.Start), new SliderCircleSelectionMask(slider.TailCircle, sliderObject, SliderPosition.End), }; diff --git a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs index 8b7355e456..482e801563 100644 --- a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs +++ b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs @@ -34,7 +34,7 @@ namespace osu.Game.Tests.Visual typeof(OsuHitObjectComposer), typeof(HitObjectMaskLayer), typeof(NotNullAttribute), - typeof(HitCircleMask), + typeof(HitCirclePiece), typeof(HitCircleSelectionMask), typeof(HitCirclePlacementMask), }; From 4ecd4ca462725ee1f3d96d99f699423d8002048b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 25 Oct 2018 18:48:11 +0900 Subject: [PATCH 167/333] Add selection mask test cases --- .../TestCaseHitCircleSelectionMask.cs | 29 ++++++++++++ .../TestCaseSliderSelectionMask.cs | 43 +++++++++++++++++ .../Visual/HitObjectSelectionMaskTestCase.cs | 47 +++++++++++++++++++ 3 files changed, 119 insertions(+) create mode 100644 osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleSelectionMask.cs create mode 100644 osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionMask.cs create mode 100644 osu.Game/Tests/Visual/HitObjectSelectionMaskTestCase.cs diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleSelectionMask.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleSelectionMask.cs new file mode 100644 index 0000000000..bafd7fa8bf --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleSelectionMask.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.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Osu.Edit.Masks.HitCircle; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Tests.Visual; +using OpenTK; + +namespace osu.Game.Rulesets.Osu.Tests +{ + public class TestCaseHitCircleSelectionMask : HitObjectSelectionMaskTestCase + { + private readonly DrawableHitCircle drawableObject; + + public TestCaseHitCircleSelectionMask() + { + var hitCircle = new HitCircle { Position = new Vector2(256, 192) }; + hitCircle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 2 }); + + Add(drawableObject = new DrawableHitCircle(hitCircle)); + } + + protected override SelectionMask CreateMask() => new HitCircleSelectionMask(drawableObject); + } +} diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionMask.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionMask.cs new file mode 100644 index 0000000000..0478946cb7 --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionMask.cs @@ -0,0 +1,43 @@ +// 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.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Objects.Types; +using osu.Game.Rulesets.Osu.Edit.Masks.Slider; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Tests.Visual; +using OpenTK; + +namespace osu.Game.Rulesets.Osu.Tests +{ + public class TestCaseSliderSelectionMask : HitObjectSelectionMaskTestCase + { + private readonly DrawableSlider drawableObject; + + public TestCaseSliderSelectionMask() + { + var slider = new Slider + { + Position = new Vector2(256, 192), + ControlPoints = new List + { + Vector2.Zero, + new Vector2(150, 150), + new Vector2(300, 0) + }, + CurveType = CurveType.Bezier, + Distance = 350 + }; + + slider.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 2 }); + + Add(drawableObject = new DrawableSlider(slider)); + } + + protected override SelectionMask CreateMask() => new SliderSelectionMask(drawableObject); + } +} diff --git a/osu.Game/Tests/Visual/HitObjectSelectionMaskTestCase.cs b/osu.Game/Tests/Visual/HitObjectSelectionMaskTestCase.cs new file mode 100644 index 0000000000..3ba6841280 --- /dev/null +++ b/osu.Game/Tests/Visual/HitObjectSelectionMaskTestCase.cs @@ -0,0 +1,47 @@ +// 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 osu.Framework.Input.Events; +using osu.Framework.Timing; +using osu.Game.Rulesets.Edit; + +namespace osu.Game.Tests.Visual +{ + public abstract class HitObjectSelectionMaskTestCase : OsuTestCase + { + private SelectionMask mask; + + protected override Container Content => content ?? base.Content; + private readonly Container content; + + protected HitObjectSelectionMaskTestCase() + { + base.Content.Add(content = new Container + { + Clock = new FramedClock(new StopwatchClock()), + RelativeSizeAxes = Axes.Both + }); + } + + [BackgroundDependencyLoader] + private void load() + { + base.Content.Add(mask = CreateMask()); + mask.SelectionRequested += (_, __) => mask.Select(); + + AddStep("Select", () => mask.Select()); + AddStep("Deselect", () => mask.Deselect()); + } + + protected override bool OnClick(ClickEvent e) + { + mask.Deselect(); + return true; + } + + protected abstract SelectionMask CreateMask(); + } +} From 2b141a2bc1c824dec79b8b5cb20e31f3a14d7cc2 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 25 Oct 2018 19:10:59 +0900 Subject: [PATCH 168/333] Make PlacementMask abstract --- osu.Game/Rulesets/Edit/PlacementMask.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Edit/PlacementMask.cs b/osu.Game/Rulesets/Edit/PlacementMask.cs index 381dc5f7f0..a588a9e181 100644 --- a/osu.Game/Rulesets/Edit/PlacementMask.cs +++ b/osu.Game/Rulesets/Edit/PlacementMask.cs @@ -15,7 +15,7 @@ using OpenTK; namespace osu.Game.Rulesets.Edit { - public class PlacementMask : CompositeDrawable, IRequireHighFrequencyMousePosition + public abstract class PlacementMask : CompositeDrawable, IRequireHighFrequencyMousePosition { /// /// The that is being placed. @@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Edit [Resolved] private IPlacementHandler placementHandler { get; set; } - public PlacementMask(HitObject hitObject) + protected PlacementMask(HitObject hitObject) { HitObject = hitObject; From 2f42112d87cf935388af170041bbfb40606932d6 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 25 Oct 2018 19:11:57 +0900 Subject: [PATCH 169/333] Add placement mask testcase --- .../TestCaseHitCirclePlacementMask.cs | 19 ++++++ .../Visual/HitObjectPlacementMaskTestCase.cs | 63 +++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 osu.Game.Rulesets.Osu.Tests/TestCaseHitCirclePlacementMask.cs create mode 100644 osu.Game/Tests/Visual/HitObjectPlacementMaskTestCase.cs diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseHitCirclePlacementMask.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseHitCirclePlacementMask.cs new file mode 100644 index 0000000000..4f94f88490 --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseHitCirclePlacementMask.cs @@ -0,0 +1,19 @@ +// 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.Objects; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Osu.Edit.Masks.HitCircle; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Tests.Visual; + +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(); + } +} diff --git a/osu.Game/Tests/Visual/HitObjectPlacementMaskTestCase.cs b/osu.Game/Tests/Visual/HitObjectPlacementMaskTestCase.cs new file mode 100644 index 0000000000..bb9b8a33bc --- /dev/null +++ b/osu.Game/Tests/Visual/HitObjectPlacementMaskTestCase.cs @@ -0,0 +1,63 @@ +// 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 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; + +namespace osu.Game.Tests.Visual +{ + [Cached(Type = typeof(IPlacementHandler))] + public abstract class HitObjectPlacementMaskTestCase : OsuTestCase, IPlacementHandler + { + private readonly Container hitObjectContainer; + private PlacementMask currentMask; + + protected HitObjectPlacementMaskTestCase() + { + Add(hitObjectContainer = new Container + { + RelativeSizeAxes = Axes.Both, + Clock = new FramedClock(new StopwatchClock()) + }); + } + + [BackgroundDependencyLoader] + private void load() + { + Add(currentMask = CreateMask()); + } + + protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) + { + var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); + dependencies.CacheAs(new StopwatchClock()); + + return dependencies; + } + + public void BeginPlacement(HitObject hitObject) + { + } + + public void EndPlacement(HitObject hitObject) + { + hitObjectContainer.Add(CreateHitObject(hitObject)); + + Remove(currentMask); + Add(currentMask = CreateMask()); + } + + public void Delete(HitObject hitObject) + { + } + + protected abstract DrawableHitObject CreateHitObject(HitObject hitObject); + protected abstract PlacementMask CreateMask(); + } +} From 8703db5cc1acae8d7fe776a8c07131bdcc5311d1 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 3 Oct 2018 13:28:00 +0900 Subject: [PATCH 170/333] Rename HitObjectMask -> SelectionMask --- ...ldNoteMask.cs => HoldNoteSelectionMask.cs} | 12 +++--- .../{NoteMask.cs => NoteSelectionMask.cs} | 4 +- .../Edit/ManiaHitObjectComposer.cs | 6 +-- ...ircleMask.cs => HitCircleSelectionMask.cs} | 4 +- ...leMask.cs => SliderCircleSelectionMask.cs} | 8 ++-- .../{SliderMask.cs => SliderSelectionMask.cs} | 8 ++-- .../Edit/OsuHitObjectComposer.cs | 6 +-- osu.Game/Beatmaps/BeatmapManager.cs | 2 +- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 4 +- .../{HitObjectMask.cs => SelectionMask.cs} | 30 +++++++-------- .../Edit/Screens/Compose/Layers/DragLayer.cs | 4 +- .../Screens/Compose/Layers/MaskContainer.cs | 38 +++++++++---------- .../Screens/Compose/Layers/MaskSelection.cs | 14 +++---- 13 files changed, 70 insertions(+), 70 deletions(-) rename osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/{HoldNoteMask.cs => HoldNoteSelectionMask.cs} (87%) rename osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/{NoteMask.cs => NoteSelectionMask.cs} (90%) rename osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/{HitCircleMask.cs => HitCircleSelectionMask.cs} (88%) rename osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/{SliderCircleMask.cs => SliderCircleSelectionMask.cs} (81%) rename osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/{SliderMask.cs => SliderSelectionMask.cs} (87%) rename osu.Game/Rulesets/Edit/{HitObjectMask.cs => SelectionMask.cs} (80%) diff --git a/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/HoldNoteMask.cs b/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/HoldNoteSelectionMask.cs similarity index 87% rename from osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/HoldNoteMask.cs rename to osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/HoldNoteSelectionMask.cs index 03d2ba19cb..b4f62ea170 100644 --- a/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/HoldNoteMask.cs +++ b/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/HoldNoteSelectionMask.cs @@ -15,7 +15,7 @@ using OpenTK.Graphics; namespace osu.Game.Rulesets.Mania.Edit.Layers.Selection.Overlays { - public class HoldNoteMask : HitObjectMask + public class HoldNoteSelectionMask : SelectionMask { public new DrawableHoldNote HitObject => (DrawableHoldNote)base.HitObject; @@ -23,13 +23,13 @@ namespace osu.Game.Rulesets.Mania.Edit.Layers.Selection.Overlays private readonly BodyPiece body; - public HoldNoteMask(DrawableHoldNote hold) + public HoldNoteSelectionMask(DrawableHoldNote hold) : base(hold) { InternalChildren = new Drawable[] { - new HoldNoteNoteMask(hold.Head), - new HoldNoteNoteMask(hold.Tail), + new HoldNoteNoteSelectionMask(hold.Head), + new HoldNoteNoteSelectionMask(hold.Tail), body = new BodyPiece { AccentColour = Color4.Transparent @@ -59,9 +59,9 @@ namespace osu.Game.Rulesets.Mania.Edit.Layers.Selection.Overlays Y -= HitObject.Tail.DrawHeight; } - private class HoldNoteNoteMask : NoteMask + private class HoldNoteNoteSelectionMask : NoteSelectionMask { - public HoldNoteNoteMask(DrawableNote note) + public HoldNoteNoteSelectionMask(DrawableNote note) : base(note) { Select(); diff --git a/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/NoteMask.cs b/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/NoteSelectionMask.cs similarity index 90% rename from osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/NoteMask.cs rename to osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/NoteSelectionMask.cs index 78f876cb14..d976386d6e 100644 --- a/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/NoteMask.cs +++ b/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/NoteSelectionMask.cs @@ -9,9 +9,9 @@ using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; namespace osu.Game.Rulesets.Mania.Edit.Layers.Selection.Overlays { - public class NoteMask : HitObjectMask + public class NoteSelectionMask : SelectionMask { - public NoteMask(DrawableNote note) + public NoteSelectionMask(DrawableNote note) : base(note) { Scale = note.Scale; diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs index f37d8134ce..7cc473c712 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs @@ -40,14 +40,14 @@ namespace osu.Game.Rulesets.Mania.Edit new HitObjectCompositionTool("Hold"), }; - public override HitObjectMask CreateMaskFor(DrawableHitObject hitObject) + public override SelectionMask CreateMaskFor(DrawableHitObject hitObject) { switch (hitObject) { case DrawableNote note: - return new NoteMask(note); + return new NoteSelectionMask(note); case DrawableHoldNote holdNote: - return new HoldNoteMask(holdNote); + return new HoldNoteSelectionMask(holdNote); } return base.CreateMaskFor(hitObject); diff --git a/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/HitCircleMask.cs b/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/HitCircleSelectionMask.cs similarity index 88% rename from osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/HitCircleMask.cs rename to osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/HitCircleSelectionMask.cs index a2aa639004..aa8044af15 100644 --- a/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/HitCircleMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/HitCircleSelectionMask.cs @@ -10,9 +10,9 @@ using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; namespace osu.Game.Rulesets.Osu.Edit.Layers.Selection.Overlays { - public class HitCircleMask : HitObjectMask + public class HitCircleSelectionMask : SelectionMask { - public HitCircleMask(DrawableHitCircle hitCircle) + public HitCircleSelectionMask(DrawableHitCircle hitCircle) : base(hitCircle) { Origin = Anchor.Centre; diff --git a/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderCircleMask.cs b/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderCircleSelectionMask.cs similarity index 81% rename from osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderCircleMask.cs rename to osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderCircleSelectionMask.cs index 151564a2a8..4d6a530eda 100644 --- a/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderCircleMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderCircleSelectionMask.cs @@ -12,21 +12,21 @@ using OpenTK; namespace osu.Game.Rulesets.Osu.Edit.Layers.Selection.Overlays { - public class SliderCircleMask : HitObjectMask + public class SliderCircleSelectionMask : SelectionMask { - public SliderCircleMask(DrawableHitCircle sliderHead, DrawableSlider slider) + public SliderCircleSelectionMask(DrawableHitCircle sliderHead, DrawableSlider slider) : this(sliderHead, Vector2.Zero, slider) { } - public SliderCircleMask(DrawableSliderTail sliderTail, DrawableSlider slider) + public SliderCircleSelectionMask(DrawableSliderTail sliderTail, DrawableSlider slider) : this(sliderTail, ((Slider)slider.HitObject).Curve.PositionAt(1), slider) { } private readonly DrawableOsuHitObject hitObject; - private SliderCircleMask(DrawableOsuHitObject hitObject, Vector2 position, DrawableSlider slider) + private SliderCircleSelectionMask(DrawableOsuHitObject hitObject, Vector2 position, DrawableSlider slider) : base(hitObject) { this.hitObject = hitObject; diff --git a/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderMask.cs b/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderSelectionMask.cs similarity index 87% rename from osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderMask.cs rename to osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderSelectionMask.cs index aff42dd233..40c2026937 100644 --- a/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderSelectionMask.cs @@ -14,12 +14,12 @@ using OpenTK.Graphics; namespace osu.Game.Rulesets.Osu.Edit.Layers.Selection.Overlays { - public class SliderMask : HitObjectMask + public class SliderSelectionMask : SelectionMask { private readonly SliderBody body; private readonly DrawableSlider slider; - public SliderMask(DrawableSlider slider) + public SliderSelectionMask(DrawableSlider slider) : base(slider) { this.slider = slider; @@ -35,8 +35,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Layers.Selection.Overlays AccentColour = Color4.Transparent, PathWidth = sliderObject.Scale * 64 }, - new SliderCircleMask(slider.HeadCircle, slider), - new SliderCircleMask(slider.TailCircle, slider), + new SliderCircleSelectionMask(slider.HeadCircle, slider), + new SliderCircleSelectionMask(slider.TailCircle, slider), }; sliderObject.PositionChanged += _ => Position = slider.Position; diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index d6972d55d2..115513b60c 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -34,14 +34,14 @@ namespace osu.Game.Rulesets.Osu.Edit protected override Container CreateLayerContainer() => new PlayfieldAdjustmentContainer { RelativeSizeAxes = Axes.Both }; - public override HitObjectMask CreateMaskFor(DrawableHitObject hitObject) + public override SelectionMask CreateMaskFor(DrawableHitObject hitObject) { switch (hitObject) { case DrawableHitCircle circle: - return new HitCircleMask(circle); + return new HitCircleSelectionMask(circle); case DrawableSlider slider: - return new SliderMask(slider); + return new SliderSelectionMask(slider); } return base.CreateMaskFor(hitObject); diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index fad94dcdfd..24c68d392b 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -350,7 +350,7 @@ namespace osu.Game.Beatmaps OnlineBeatmapSetID = beatmap.BeatmapInfo.BeatmapSet?.OnlineBeatmapSetID, Beatmaps = new List(), Hash = computeBeatmapSetHash(reader), - Metadata = beatmap.Metadata + Metadata = beatmap.Metadata, }; } diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 8060ac742a..0188870313 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -151,10 +151,10 @@ namespace osu.Game.Rulesets.Edit protected abstract IReadOnlyList CompositionTools { get; } /// - /// Creates a for a specific . + /// Creates a for a specific . /// /// The to create the overlay for. - public virtual HitObjectMask CreateMaskFor(DrawableHitObject hitObject) => null; + public virtual SelectionMask CreateMaskFor(DrawableHitObject hitObject) => null; /// /// Creates a which outlines s diff --git a/osu.Game/Rulesets/Edit/HitObjectMask.cs b/osu.Game/Rulesets/Edit/SelectionMask.cs similarity index 80% rename from osu.Game/Rulesets/Edit/HitObjectMask.cs rename to osu.Game/Rulesets/Edit/SelectionMask.cs index 636ea418f3..9582c30457 100644 --- a/osu.Game/Rulesets/Edit/HitObjectMask.cs +++ b/osu.Game/Rulesets/Edit/SelectionMask.cs @@ -16,31 +16,31 @@ namespace osu.Game.Rulesets.Edit /// /// A mask placed above a adding editing functionality. /// - public class HitObjectMask : CompositeDrawable, IStateful + public class SelectionMask : 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; @@ -48,7 +48,7 @@ namespace osu.Game.Rulesets.Edit public override bool HandlePositionalInput => ShouldBeAlive; public override bool RemoveWhenNotAlive => false; - public HitObjectMask(DrawableHitObject hitObject) + public SelectionMask(DrawableHitObject hitObject) { HitObject = hitObject; @@ -83,12 +83,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; @@ -130,12 +130,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 => ScreenSpaceDrawQuad.Centre; /// - /// The screen-space quad that outlines this for selections. + /// The screen-space quad that outlines this for selections. /// public virtual Quad SelectionQuad => ScreenSpaceDrawQuad; } diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/DragLayer.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/DragLayer.cs index 981ddd989c..fdc0dee0ce 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/DragLayer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Layers/DragLayer.cs @@ -14,7 +14,7 @@ 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 layer that handles and displays drag selection for a collection of s. /// public class DragLayer : CompositeDrawable { @@ -30,7 +30,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers /// /// Creates a new . /// - /// The selectable s. + /// The selectable s. public DragLayer(Action performSelection) { this.performSelection = performSelection; diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskContainer.cs index 19258d669e..42a7757721 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskContainer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskContainer.cs @@ -13,36 +13,36 @@ using RectangleF = osu.Framework.Graphics.Primitives.RectangleF; namespace osu.Game.Screens.Edit.Screens.Compose.Layers { - public class MaskContainer : Container + public class MaskContainer : Container { /// - /// Invoked when any is selected. + /// Invoked when any is selected. /// - public event Action MaskSelected; + public event Action MaskSelected; /// - /// Invoked when any is deselected. + /// Invoked when any is deselected. /// - public event Action MaskDeselected; + public event Action MaskDeselected; /// - /// Invoked when any requests selection. + /// Invoked when any requests selection. /// - public event Action MaskSelectionRequested; + public event Action MaskSelectionRequested; /// - /// Invoked when any requests drag. + /// Invoked when any requests drag. /// - public event Action MaskDragRequested; + public event Action MaskDragRequested; - private IEnumerable aliveMasks => AliveInternalChildren.Cast(); + private IEnumerable aliveMasks => AliveInternalChildren.Cast(); public MaskContainer() { RelativeSizeAxes = Axes.Both; } - public override void Add(HitObjectMask drawable) + public override void Add(SelectionMask drawable) { if (drawable == null) throw new ArgumentNullException(nameof(drawable)); @@ -54,7 +54,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers drawable.DragRequested += onDragRequested; } - public override bool Remove(HitObjectMask drawable) + public override bool Remove(SelectionMask drawable) { if (drawable == null) throw new ArgumentNullException(nameof(drawable)); @@ -87,33 +87,33 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers } /// - /// Deselects all selected s. + /// Deselects all selected s. /// public void DeselectAll() => aliveMasks.ToList().ForEach(m => m.Deselect()); - private void onMaskSelected(HitObjectMask mask) + private void onMaskSelected(SelectionMask mask) { MaskSelected?.Invoke(mask); ChangeChildDepth(mask, 1); } - private void onMaskDeselected(HitObjectMask mask) + private void onMaskDeselected(SelectionMask mask) { MaskDeselected?.Invoke(mask); ChangeChildDepth(mask, 0); } - private void onSelectionRequested(HitObjectMask mask, InputState state) => MaskSelectionRequested?.Invoke(mask, state); - private void onDragRequested(HitObjectMask mask, Vector2 delta, InputState state) => MaskDragRequested?.Invoke(mask, delta, state); + 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 HitObjectMask xMask) || !(y is HitObjectMask yMask)) + if (!(x is SelectionMask xMask) || !(y is SelectionMask yMask)) return base.Compare(x, y); return Compare(xMask, yMask); } - public int Compare(HitObjectMask x, HitObjectMask y) + 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); diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskSelection.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskSelection.cs index 635edf82da..1231737122 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskSelection.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskSelection.cs @@ -16,19 +16,19 @@ using OpenTK; 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 MaskSelection : CompositeDrawable { public const float BORDER_RADIUS = 2; - private readonly List selectedMasks; + private readonly List selectedMasks; private Drawable outline; public MaskSelection() { - selectedMasks = new List(); + selectedMasks = new List(); RelativeSizeAxes = Axes.Both; AlwaysPresent = true; @@ -54,7 +54,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers #region User Input Handling - public void HandleDrag(HitObjectMask m, Vector2 delta, InputState state) + public void HandleDrag(SelectionMask m, Vector2 delta, InputState state) { // Todo: Various forms of snapping @@ -82,13 +82,13 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers /// Handle a mask becoming selected. /// /// The mask. - public void HandleSelected(HitObjectMask mask) => selectedMasks.Add(mask); + public void HandleSelected(SelectionMask mask) => selectedMasks.Add(mask); /// /// Handle a mask becoming deselected. /// /// The mask. - public void HandleDeselected(HitObjectMask mask) + public void HandleDeselected(SelectionMask mask) { selectedMasks.Remove(mask); @@ -101,7 +101,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers /// Handle a mask requesting selection. /// /// The mask. - public void HandleSelectionRequested(HitObjectMask mask, InputState state) + public void HandleSelectionRequested(SelectionMask mask, InputState state) { if (state.Keyboard.ControlPressed) { From 677d0d4a19cd5a51db2469018e570bf5f5e599c9 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 3 Oct 2018 13:45:41 +0900 Subject: [PATCH 171/333] Renamespace ruleset masks --- osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs | 2 +- .../Selection/Overlays => Masks}/HoldNoteSelectionMask.cs | 2 +- .../{Layers/Selection/Overlays => Masks}/NoteSelectionMask.cs | 2 +- .../Selection/Overlays => Masks}/HitCircleSelectionMask.cs | 4 ++-- .../Selection/Overlays => Masks}/SliderCircleSelectionMask.cs | 2 +- .../Selection/Overlays => Masks}/SliderSelectionMask.cs | 2 +- osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) rename osu.Game.Rulesets.Mania/Edit/{Layers/Selection/Overlays => Masks}/HoldNoteSelectionMask.cs (97%) rename osu.Game.Rulesets.Mania/Edit/{Layers/Selection/Overlays => Masks}/NoteSelectionMask.cs (93%) rename osu.Game.Rulesets.Osu/Edit/{Layers/Selection/Overlays => Masks}/HitCircleSelectionMask.cs (94%) rename osu.Game.Rulesets.Osu/Edit/{Layers/Selection/Overlays => Masks}/SliderCircleSelectionMask.cs (96%) rename osu.Game.Rulesets.Osu/Edit/{Layers/Selection/Overlays => Masks}/SliderSelectionMask.cs (97%) diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs index 7cc473c712..1053e998be 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs @@ -4,7 +4,6 @@ using osu.Game.Beatmaps; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Tools; -using osu.Game.Rulesets.Mania.Edit.Layers.Selection.Overlays; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables; @@ -12,6 +11,7 @@ using osu.Game.Rulesets.UI; 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.UI; namespace osu.Game.Rulesets.Mania.Edit diff --git a/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/HoldNoteSelectionMask.cs b/osu.Game.Rulesets.Mania/Edit/Masks/HoldNoteSelectionMask.cs similarity index 97% rename from osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/HoldNoteSelectionMask.cs rename to osu.Game.Rulesets.Mania/Edit/Masks/HoldNoteSelectionMask.cs index b4f62ea170..a2c01d7a0e 100644 --- a/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/HoldNoteSelectionMask.cs +++ b/osu.Game.Rulesets.Mania/Edit/Masks/HoldNoteSelectionMask.cs @@ -13,7 +13,7 @@ using osu.Game.Rulesets.UI.Scrolling; using OpenTK; using OpenTK.Graphics; -namespace osu.Game.Rulesets.Mania.Edit.Layers.Selection.Overlays +namespace osu.Game.Rulesets.Mania.Edit.Masks { public class HoldNoteSelectionMask : SelectionMask { diff --git a/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/NoteSelectionMask.cs b/osu.Game.Rulesets.Mania/Edit/Masks/NoteSelectionMask.cs similarity index 93% rename from osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/NoteSelectionMask.cs rename to osu.Game.Rulesets.Mania/Edit/Masks/NoteSelectionMask.cs index d976386d6e..18f042a483 100644 --- a/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/NoteSelectionMask.cs +++ b/osu.Game.Rulesets.Mania/Edit/Masks/NoteSelectionMask.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.Layers.Selection.Overlays +namespace osu.Game.Rulesets.Mania.Edit.Masks { public class NoteSelectionMask : SelectionMask { diff --git a/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/HitCircleSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleSelectionMask.cs similarity index 94% rename from osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/HitCircleSelectionMask.cs rename to osu.Game.Rulesets.Osu/Edit/Masks/HitCircleSelectionMask.cs index aa8044af15..6c96b40b33 100644 --- a/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/HitCircleSelectionMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleSelectionMask.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 osu.Framework.Graphics; using osu.Framework.Allocation; +using osu.Framework.Graphics; using osu.Game.Graphics; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; -namespace osu.Game.Rulesets.Osu.Edit.Layers.Selection.Overlays +namespace osu.Game.Rulesets.Osu.Edit.Masks { public class HitCircleSelectionMask : SelectionMask { diff --git a/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderCircleSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderCircleSelectionMask.cs similarity index 96% rename from osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderCircleSelectionMask.cs rename to osu.Game.Rulesets.Osu/Edit/Masks/SliderCircleSelectionMask.cs index 4d6a530eda..1ed22c2ac1 100644 --- a/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderCircleSelectionMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderCircleSelectionMask.cs @@ -10,7 +10,7 @@ using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; using OpenTK; -namespace osu.Game.Rulesets.Osu.Edit.Layers.Selection.Overlays +namespace osu.Game.Rulesets.Osu.Edit.Masks { public class SliderCircleSelectionMask : SelectionMask { diff --git a/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderSelectionMask.cs similarity index 97% rename from osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderSelectionMask.cs rename to osu.Game.Rulesets.Osu/Edit/Masks/SliderSelectionMask.cs index 40c2026937..b775854038 100644 --- a/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderSelectionMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderSelectionMask.cs @@ -12,7 +12,7 @@ using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; using OpenTK; using OpenTK.Graphics; -namespace osu.Game.Rulesets.Osu.Edit.Layers.Selection.Overlays +namespace osu.Game.Rulesets.Osu.Edit.Masks { public class SliderSelectionMask : SelectionMask { diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index 115513b60c..fa49aff650 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -8,7 +8,7 @@ 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.Layers.Selection.Overlays; +using osu.Game.Rulesets.Osu.Edit.Masks; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.UI; From e1db2bbc25d0777a4fab8224b882e65a16dfd4b6 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 3 Oct 2018 14:35:26 +0900 Subject: [PATCH 172/333] Split visuals of HitCircleSelectionMask into HitCircleMask --- .../Edit/Masks/HitCircleMask.cs | 35 +++++++++++++++++++ .../Edit/Masks/HitCircleSelectionMask.cs | 18 ++-------- 2 files changed, 38 insertions(+), 15 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMask.cs diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMask.cs new file mode 100644 index 0000000000..76f876fb42 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMask.cs @@ -0,0 +1,35 @@ +// 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 osu.Game.Graphics; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; +using OpenTK; + +namespace osu.Game.Rulesets.Osu.Edit.Masks +{ + public class HitCircleMask : CompositeDrawable + { + public HitCircleMask(HitCircle hitCircle) + { + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + + Size = new Vector2((float)OsuHitObject.OBJECT_RADIUS * 2); + Scale = new Vector2(hitCircle.Scale); + + CornerRadius = Size.X / 2; + + AddInternal(new RingPiece()); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + Colour = colours.Yellow; + } + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleSelectionMask.cs index 6c96b40b33..b9ca95b837 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleSelectionMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleSelectionMask.cs @@ -1,12 +1,10 @@ // 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.Game.Graphics; using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; -using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; namespace osu.Game.Rulesets.Osu.Edit.Masks { @@ -16,22 +14,12 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks : base(hitCircle) { Origin = Anchor.Centre; - + AutoSizeAxes = Axes.Both; Position = hitCircle.Position; - Size = hitCircle.Size; - Scale = hitCircle.Scale; - CornerRadius = Size.X / 2; - - AddInternal(new RingPiece()); + InternalChild = new HitCircleMask((HitCircle)hitCircle.HitObject); hitCircle.HitObject.PositionChanged += _ => Position = hitCircle.Position; } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - Colour = colours.Yellow; - } } } From 4051864bb43874d55b14fcaf9349cf9475395c68 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 26 Oct 2018 13:39:19 +0900 Subject: [PATCH 173/333] Re-namespace --- .../Masks/{ => HitCircleMasks/Components}/HitCircleMask.cs | 2 +- .../Edit/Masks/{ => HitCircleMasks}/HitCircleSelectionMask.cs | 3 ++- .../Edit/Masks/{ => SliderMasks}/SliderCircleSelectionMask.cs | 2 +- .../Edit/Masks/{ => SliderMasks}/SliderSelectionMask.cs | 2 +- osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs | 3 ++- 5 files changed, 7 insertions(+), 5 deletions(-) rename osu.Game.Rulesets.Osu/Edit/Masks/{ => HitCircleMasks/Components}/HitCircleMask.cs (93%) rename osu.Game.Rulesets.Osu/Edit/Masks/{ => HitCircleMasks}/HitCircleSelectionMask.cs (86%) rename osu.Game.Rulesets.Osu/Edit/Masks/{ => SliderMasks}/SliderCircleSelectionMask.cs (97%) rename osu.Game.Rulesets.Osu/Edit/Masks/{ => SliderMasks}/SliderSelectionMask.cs (97%) diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/Components/HitCircleMask.cs similarity index 93% rename from osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMask.cs rename to osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/Components/HitCircleMask.cs index 76f876fb42..65d9654181 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/Components/HitCircleMask.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 +namespace osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks.Components { public class HitCircleMask : CompositeDrawable { diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCircleSelectionMask.cs similarity index 86% rename from osu.Game.Rulesets.Osu/Edit/Masks/HitCircleSelectionMask.cs rename to osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCircleSelectionMask.cs index b9ca95b837..c76d1411ef 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleSelectionMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCircleSelectionMask.cs @@ -3,10 +3,11 @@ using osu.Framework.Graphics; using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks.Components; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; -namespace osu.Game.Rulesets.Osu.Edit.Masks +namespace osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks { public class HitCircleSelectionMask : SelectionMask { diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderCircleSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderCircleSelectionMask.cs similarity index 97% rename from osu.Game.Rulesets.Osu/Edit/Masks/SliderCircleSelectionMask.cs rename to osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderCircleSelectionMask.cs index 1ed22c2ac1..5513e1fd84 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderCircleSelectionMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderCircleSelectionMask.cs @@ -10,7 +10,7 @@ using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; using OpenTK; -namespace osu.Game.Rulesets.Osu.Edit.Masks +namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks { public class SliderCircleSelectionMask : SelectionMask { diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderSelectionMask.cs similarity index 97% rename from osu.Game.Rulesets.Osu/Edit/Masks/SliderSelectionMask.cs rename to osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderSelectionMask.cs index b775854038..0ff67a0777 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderSelectionMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderSelectionMask.cs @@ -12,7 +12,7 @@ using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; using OpenTK; using OpenTK.Graphics; -namespace osu.Game.Rulesets.Osu.Edit.Masks +namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks { public class SliderSelectionMask : SelectionMask { diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index fa49aff650..8314be45e0 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -8,7 +8,8 @@ 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; +using osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks; +using osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.UI; From 9656186b64f831377f1ec4e5d1c545eb7d84b561 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 25 Oct 2018 18:16:25 +0900 Subject: [PATCH 174/333] Make the hitobject masks move within their placement/selection # Conflicts: # osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/Components/HitCircleMask.cs # osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCircleSelectionMask.cs # osu.Game.Rulesets.Osu/Edit/Masks/HitCirclePlacementMask.cs # osu.Game/Rulesets/Edit/PlacementMask.cs --- .../Components/HitCircleMask.cs | 13 +++-- .../HitCircleMasks/HitCircleSelectionMask.cs | 7 --- .../SliderMasks/Components/SliderBodyMask.cs | 51 +++++++++++++++++++ .../Components/SliderCircleMask.cs | 34 +++++++++++++ .../SliderMasks/SliderCircleSelectionMask.cs | 43 ++-------------- .../Edit/Masks/SliderMasks/SliderPosition.cs | 11 ++++ .../Masks/SliderMasks/SliderSelectionMask.cs | 47 +++-------------- osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs | 2 +- osu.Game.Rulesets.Osu/Objects/Slider.cs | 15 ++++++ osu.Game/Rulesets/Edit/SelectionMask.cs | 9 +++- 10 files changed, 138 insertions(+), 94 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderBodyMask.cs create mode 100644 osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderCircleMask.cs create mode 100644 osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPosition.cs diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/Components/HitCircleMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/Components/HitCircleMask.cs index 65d9654181..713dedb84f 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/Components/HitCircleMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/Components/HitCircleMask.cs @@ -13,23 +13,30 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks.Components { public class HitCircleMask : CompositeDrawable { + private readonly HitCircle hitCircle; + public HitCircleMask(HitCircle hitCircle) { - Anchor = Anchor.Centre; + this.hitCircle = hitCircle; Origin = Anchor.Centre; Size = new Vector2((float)OsuHitObject.OBJECT_RADIUS * 2); Scale = new Vector2(hitCircle.Scale); - CornerRadius = Size.X / 2; - AddInternal(new RingPiece()); + InternalChild = new RingPiece(); + + hitCircle.PositionChanged += _ => UpdatePosition(); } [BackgroundDependencyLoader] private void load(OsuColour colours) { Colour = colours.Yellow; + + UpdatePosition(); } + + protected virtual void UpdatePosition() => Position = hitCircle.StackedPosition; } } diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCircleSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCircleSelectionMask.cs index c76d1411ef..f49f2fc137 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCircleSelectionMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCircleSelectionMask.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 osu.Framework.Graphics; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks.Components; using osu.Game.Rulesets.Osu.Objects; @@ -14,13 +13,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks public HitCircleSelectionMask(DrawableHitCircle hitCircle) : base(hitCircle) { - Origin = Anchor.Centre; - AutoSizeAxes = Axes.Both; - Position = hitCircle.Position; - InternalChild = new HitCircleMask((HitCircle)hitCircle.HitObject); - - hitCircle.HitObject.PositionChanged += _ => Position = hitCircle.Position; } } } diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderBodyMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderBodyMask.cs new file mode 100644 index 0000000000..a0f8a5be7b --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderBodyMask.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 osu.Framework.Allocation; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; +using OpenTK.Graphics; + +namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components +{ + public class SliderBodyMask : CompositeDrawable + { + private readonly Slider slider; + private readonly SliderBody body; + + public SliderBodyMask(Slider slider) + { + this.slider = slider; + InternalChild = body = new SliderBody(slider) + { + AccentColour = Color4.Transparent, + PathWidth = slider.Scale * 64 + }; + + slider.PositionChanged += _ => updatePosition(); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + body.BorderColour = colours.Yellow; + + updatePosition(); + } + + private void updatePosition() => Position = slider.StackedPosition; + + protected override void Update() + { + base.Update(); + + Size = body.Size; + OriginPosition = body.PathOffset; + + // Need to cause one update + body.UpdateProgress(0); + } + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderCircleMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderCircleMask.cs new file mode 100644 index 0000000000..3595d01582 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderCircleMask.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 osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks.Components; +using osu.Game.Rulesets.Osu.Objects; + +namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components +{ + public class SliderCircleMask : HitCircleMask + { + private readonly Slider slider; + private readonly SliderPosition position; + + public SliderCircleMask(Slider slider, SliderPosition position) + : base(slider.HeadCircle) + { + this.slider = slider; + this.position = position; + } + + protected override void UpdatePosition() + { + switch (position) + { + case SliderPosition.Start: + Position = slider.StackedPosition + slider.Curve.PositionAt(0); + break; + case SliderPosition.End: + Position = slider.StackedPosition + slider.Curve.PositionAt(1); + break; + } + } + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderCircleSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderCircleSelectionMask.cs index 5513e1fd84..7a4d3ab5db 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderCircleSelectionMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderCircleSelectionMask.cs @@ -1,60 +1,23 @@ // 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.Game.Graphics; using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; -using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; -using OpenTK; namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks { public class SliderCircleSelectionMask : SelectionMask { - public SliderCircleSelectionMask(DrawableHitCircle sliderHead, DrawableSlider slider) - : this(sliderHead, Vector2.Zero, slider) - { - } - - public SliderCircleSelectionMask(DrawableSliderTail sliderTail, DrawableSlider slider) - : this(sliderTail, ((Slider)slider.HitObject).Curve.PositionAt(1), slider) - { - } - - private readonly DrawableOsuHitObject hitObject; - - private SliderCircleSelectionMask(DrawableOsuHitObject hitObject, Vector2 position, DrawableSlider slider) + public SliderCircleSelectionMask(DrawableOsuHitObject hitObject, Slider slider, SliderPosition position) : base(hitObject) { - this.hitObject = hitObject; - - Origin = Anchor.Centre; - - Position = position; - Size = slider.HeadCircle.Size; - Scale = slider.HeadCircle.Scale; - - AddInternal(new RingPiece()); + InternalChild = new SliderCircleMask(slider, position); Select(); } - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - Colour = colours.Yellow; - } - - protected override void Update() - { - base.Update(); - - RelativeAnchorPosition = hitObject.RelativeAnchorPosition; - } - // 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; } diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPosition.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPosition.cs new file mode 100644 index 0000000000..01c1871131 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPosition.cs @@ -0,0 +1,11 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks +{ + public enum SliderPosition + { + Start, + End + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderSelectionMask.cs index 0ff67a0777..5ba264f2cb 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderSelectionMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderSelectionMask.cs @@ -1,67 +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.Framework.Graphics; -using osu.Framework.Graphics.Primitives; -using osu.Game.Graphics; using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; -using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; using OpenTK; -using OpenTK.Graphics; namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks { public class SliderSelectionMask : SelectionMask { - private readonly SliderBody body; - private readonly DrawableSlider slider; + private readonly SliderCircleSelectionMask headMask; public SliderSelectionMask(DrawableSlider slider) : base(slider) { - this.slider = slider; - - Position = slider.Position; - var sliderObject = (Slider)slider.HitObject; InternalChildren = new Drawable[] { - body = new SliderBody(sliderObject) - { - AccentColour = Color4.Transparent, - PathWidth = sliderObject.Scale * 64 - }, - new SliderCircleSelectionMask(slider.HeadCircle, slider), - new SliderCircleSelectionMask(slider.TailCircle, slider), + new SliderBodyMask(sliderObject), + headMask = new SliderCircleSelectionMask(slider.HeadCircle, sliderObject, SliderPosition.Start), + new SliderCircleSelectionMask(slider.TailCircle, sliderObject, SliderPosition.End), }; - - sliderObject.PositionChanged += _ => Position = slider.Position; } - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - body.BorderColour = colours.Yellow; - } - - protected override void Update() - { - base.Update(); - - Size = slider.Size; - OriginPosition = slider.OriginPosition; - - // Need to cause one update - body.UpdateProgress(0); - } - - public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => body.ReceivePositionalInputAt(screenSpacePos); - - public override Vector2 SelectionPoint => ToScreenSpace(OriginPosition); - public override Quad SelectionQuad => body.PathDrawQuad; + public override Vector2 SelectionPoint => headMask.SelectionPoint; } } diff --git a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs index fdf5aaffa8..9ababead13 100644 --- a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.Objects private Vector2 position; - public Vector2 Position + public virtual Vector2 Position { get => position; set diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 80be192b77..a6f5bdb24e 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -70,6 +70,21 @@ namespace osu.Game.Rulesets.Osu.Objects set { Curve.Distance = value; } } + public override Vector2 Position + { + get => base.Position; + set + { + base.Position = value; + + if (HeadCircle != null) + HeadCircle.Position = value; + + if (TailCircle != null) + TailCircle.Position = EndPosition; + } + } + public double? LegacyLastTickOffset { get; set; } /// diff --git a/osu.Game/Rulesets/Edit/SelectionMask.cs b/osu.Game/Rulesets/Edit/SelectionMask.cs index 9582c30457..3b78d5aaf6 100644 --- a/osu.Game/Rulesets/Edit/SelectionMask.cs +++ b/osu.Game/Rulesets/Edit/SelectionMask.cs @@ -3,6 +3,7 @@ using System; using osu.Framework; +using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Primitives; using osu.Framework.Input.Events; @@ -52,6 +53,8 @@ namespace osu.Game.Rulesets.Edit { HitObject = hitObject; + RelativeSizeAxes = Axes.Both; + AlwaysPresent = true; Alpha = 0; } @@ -94,6 +97,8 @@ namespace osu.Game.Rulesets.Edit public bool IsSelected => State == SelectionState.Selected; + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => HitObject.ReceivePositionalInputAt(screenSpacePos); + private bool selectionRequested; protected override bool OnMouseDown(MouseDownEvent e) @@ -132,11 +137,11 @@ namespace osu.Game.Rulesets.Edit /// /// The screen-space point that causes this to be selected. /// - public virtual Vector2 SelectionPoint => ScreenSpaceDrawQuad.Centre; + public virtual Vector2 SelectionPoint => HitObject.ScreenSpaceDrawQuad.Centre; /// /// The screen-space quad that outlines this for selections. /// - public virtual Quad SelectionQuad => ScreenSpaceDrawQuad; + public virtual Quad SelectionQuad => HitObject.ScreenSpaceDrawQuad; } } From ea3c960b5b9f2039a842965476c4e545e8445017 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 26 Oct 2018 13:51:03 +0900 Subject: [PATCH 175/333] Mask -> Piece for components --- .../Components/{HitCircleMask.cs => HitCirclePiece.cs} | 4 ++-- .../Edit/Masks/HitCircleMasks/HitCircleSelectionMask.cs | 2 +- .../Components/{SliderBodyMask.cs => SliderBodyPiece.cs} | 4 ++-- .../Components/{SliderCircleMask.cs => SliderCirclePiece.cs} | 4 ++-- .../Edit/Masks/SliderMasks/SliderCircleSelectionMask.cs | 2 +- .../Edit/Masks/SliderMasks/SliderSelectionMask.cs | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) rename osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/Components/{HitCircleMask.cs => HitCirclePiece.cs} (91%) rename osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/{SliderBodyMask.cs => SliderBodyPiece.cs} (93%) rename osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/{SliderCircleMask.cs => SliderCirclePiece.cs} (88%) diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/Components/HitCircleMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/Components/HitCirclePiece.cs similarity index 91% rename from osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/Components/HitCircleMask.cs rename to osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/Components/HitCirclePiece.cs index 713dedb84f..0450db5c13 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/Components/HitCircleMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/Components/HitCirclePiece.cs @@ -11,11 +11,11 @@ using OpenTK; namespace osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks.Components { - public class HitCircleMask : CompositeDrawable + public class HitCirclePiece : CompositeDrawable { private readonly HitCircle hitCircle; - public HitCircleMask(HitCircle hitCircle) + public HitCirclePiece(HitCircle hitCircle) { this.hitCircle = hitCircle; Origin = Anchor.Centre; diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCircleSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCircleSelectionMask.cs index f49f2fc137..da46da92a5 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCircleSelectionMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCircleSelectionMask.cs @@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks public HitCircleSelectionMask(DrawableHitCircle hitCircle) : base(hitCircle) { - InternalChild = new HitCircleMask((HitCircle)hitCircle.HitObject); + InternalChild = new HitCirclePiece((HitCircle)hitCircle.HitObject); } } } diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderBodyMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderBodyPiece.cs similarity index 93% rename from osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderBodyMask.cs rename to osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderBodyPiece.cs index a0f8a5be7b..0595b046d1 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderBodyMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderBodyPiece.cs @@ -10,12 +10,12 @@ using OpenTK.Graphics; namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components { - public class SliderBodyMask : CompositeDrawable + public class SliderBodyPiece : CompositeDrawable { private readonly Slider slider; private readonly SliderBody body; - public SliderBodyMask(Slider slider) + public SliderBodyPiece(Slider slider) { this.slider = slider; InternalChild = body = new SliderBody(slider) diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderCircleMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderCirclePiece.cs similarity index 88% rename from osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderCircleMask.cs rename to osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderCirclePiece.cs index 3595d01582..c5ecde5c4c 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderCircleMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderCirclePiece.cs @@ -6,12 +6,12 @@ using osu.Game.Rulesets.Osu.Objects; namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components { - public class SliderCircleMask : HitCircleMask + public class SliderCirclePiece : HitCirclePiece { private readonly Slider slider; private readonly SliderPosition position; - public SliderCircleMask(Slider slider, SliderPosition position) + public SliderCirclePiece(Slider slider, SliderPosition position) : base(slider.HeadCircle) { this.slider = slider; diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderCircleSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderCircleSelectionMask.cs index 7a4d3ab5db..a1b3fd545c 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderCircleSelectionMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderCircleSelectionMask.cs @@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks public SliderCircleSelectionMask(DrawableOsuHitObject hitObject, Slider slider, SliderPosition position) : base(hitObject) { - InternalChild = new SliderCircleMask(slider, position); + InternalChild = new SliderCirclePiece(slider, position); Select(); } diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderSelectionMask.cs index 5ba264f2cb..a411064f68 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderSelectionMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderSelectionMask.cs @@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks InternalChildren = new Drawable[] { - new SliderBodyMask(sliderObject), + new SliderBodyPiece(sliderObject), headMask = new SliderCircleSelectionMask(slider.HeadCircle, sliderObject, SliderPosition.Start), new SliderCircleSelectionMask(slider.TailCircle, sliderObject, SliderPosition.End), }; From ce9b400c4c70c0fc30f16ef4418af63a915adcca Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 25 Oct 2018 18:48:11 +0900 Subject: [PATCH 176/333] Add selection mask test cases --- .../TestCaseHitCircleSelectionMask.cs | 29 ++++++++++++ .../TestCaseSliderSelectionMask.cs | 42 +++++++++++++++++ .../Visual/HitObjectSelectionMaskTestCase.cs | 47 +++++++++++++++++++ 3 files changed, 118 insertions(+) create mode 100644 osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleSelectionMask.cs create mode 100644 osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionMask.cs create mode 100644 osu.Game/Tests/Visual/HitObjectSelectionMaskTestCase.cs diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleSelectionMask.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleSelectionMask.cs new file mode 100644 index 0000000000..e3d61623bf --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleSelectionMask.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.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Tests.Visual; +using OpenTK; + +namespace osu.Game.Rulesets.Osu.Tests +{ + public class TestCaseHitCircleSelectionMask : HitObjectSelectionMaskTestCase + { + private readonly DrawableHitCircle drawableObject; + + public TestCaseHitCircleSelectionMask() + { + var hitCircle = new HitCircle { Position = new Vector2(256, 192) }; + hitCircle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 2 }); + + Add(drawableObject = new DrawableHitCircle(hitCircle)); + } + + protected override SelectionMask CreateMask() => new HitCircleSelectionMask(drawableObject); + } +} diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionMask.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionMask.cs new file mode 100644 index 0000000000..5e68d5cdc9 --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionMask.cs @@ -0,0 +1,42 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +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.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Tests.Visual; +using OpenTK; + +namespace osu.Game.Rulesets.Osu.Tests +{ + public class TestCaseSliderSelectionMask : HitObjectSelectionMaskTestCase + { + private readonly DrawableSlider drawableObject; + + public TestCaseSliderSelectionMask() + { + var slider = new Slider + { + Position = new Vector2(256, 192), + ControlPoints = new[] + { + Vector2.Zero, + new Vector2(150, 150), + new Vector2(300, 0) + }, + CurveType = CurveType.Bezier, + Distance = 350 + }; + + slider.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 2 }); + + Add(drawableObject = new DrawableSlider(slider)); + } + + protected override SelectionMask CreateMask() => new SliderSelectionMask(drawableObject); + } +} diff --git a/osu.Game/Tests/Visual/HitObjectSelectionMaskTestCase.cs b/osu.Game/Tests/Visual/HitObjectSelectionMaskTestCase.cs new file mode 100644 index 0000000000..3ba6841280 --- /dev/null +++ b/osu.Game/Tests/Visual/HitObjectSelectionMaskTestCase.cs @@ -0,0 +1,47 @@ +// 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 osu.Framework.Input.Events; +using osu.Framework.Timing; +using osu.Game.Rulesets.Edit; + +namespace osu.Game.Tests.Visual +{ + public abstract class HitObjectSelectionMaskTestCase : OsuTestCase + { + private SelectionMask mask; + + protected override Container Content => content ?? base.Content; + private readonly Container content; + + protected HitObjectSelectionMaskTestCase() + { + base.Content.Add(content = new Container + { + Clock = new FramedClock(new StopwatchClock()), + RelativeSizeAxes = Axes.Both + }); + } + + [BackgroundDependencyLoader] + private void load() + { + base.Content.Add(mask = CreateMask()); + mask.SelectionRequested += (_, __) => mask.Select(); + + AddStep("Select", () => mask.Select()); + AddStep("Deselect", () => mask.Deselect()); + } + + protected override bool OnClick(ClickEvent e) + { + mask.Deselect(); + return true; + } + + protected abstract SelectionMask CreateMask(); + } +} From 4a507c66ee50710f4b0d9e37c8654cccb733caee Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 26 Oct 2018 15:26:08 +0900 Subject: [PATCH 177/333] Cleanup --- .../Edit/Masks/HitCircleMasks/HitCirclePlacementMask.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCirclePlacementMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCirclePlacementMask.cs index 930ccde814..0d0acbed7d 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCirclePlacementMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCirclePlacementMask.cs @@ -4,15 +4,16 @@ using osu.Framework.Input.Events; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks.Components; +using osu.Game.Rulesets.Osu.Objects; namespace osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks { public class HitCirclePlacementMask : PlacementMask { - public new Objects.HitCircle HitObject => (Objects.HitCircle)base.HitObject; + public new HitCircle HitObject => (HitCircle)base.HitObject; public HitCirclePlacementMask() - : base(new Objects.HitCircle()) + : base(new HitCircle()) { InternalChild = new HitCirclePiece(HitObject); } From 22c545ea8c94adea9e8c7285efe1f2b3746a6a66 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 26 Oct 2018 15:26:19 +0900 Subject: [PATCH 178/333] Make circle piece respond to hitobject scale --- .../HitCircleMasks/Components/HitCirclePiece.cs | 1 + .../Objects/Drawables/DrawableHitCircle.cs | 1 + osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs | 16 +++++++++++++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/Components/HitCirclePiece.cs b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/Components/HitCirclePiece.cs index 2c76a2e443..c11ae096a7 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/Components/HitCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/Components/HitCirclePiece.cs @@ -28,6 +28,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks.Components hitCircle.PositionChanged += _ => UpdatePosition(); hitCircle.StackHeightChanged += _ => UpdatePosition(); + hitCircle.ScaleChanged += _ => Scale = new Vector2(hitCircle.Scale); } [BackgroundDependencyLoader] diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs index 8b0973e3d3..e663989eeb 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -62,6 +62,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables HitObject.PositionChanged += _ => Position = HitObject.StackedPosition; HitObject.StackHeightChanged += _ => Position = HitObject.StackedPosition; + HitObject.ScaleChanged += s => Scale = new Vector2(s); } public override Color4 AccentColour diff --git a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs index 140f875a6f..67396c7ae4 100644 --- a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs @@ -17,6 +17,7 @@ namespace osu.Game.Rulesets.Osu.Objects public event Action PositionChanged; public event Action StackHeightChanged; + public event Action ScaleChanged; public double TimePreempt = 600; public double TimeFadeIn = 400; @@ -64,7 +65,20 @@ namespace osu.Game.Rulesets.Osu.Objects public double Radius => OBJECT_RADIUS * Scale; - public float Scale { get; set; } = 1; + private float scale = 1; + + public float Scale + { + get => scale; + set + { + if (scale == value) + return; + scale = value; + + ScaleChanged?.Invoke(value); + } + } public virtual bool NewCombo { get; set; } From 951a309d0447ed06c6691a2faed003bcf6c3e291 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 26 Oct 2018 15:36:09 +0900 Subject: [PATCH 179/333] Increase placement testcase circlesize --- osu.Game/Tests/Visual/HitObjectPlacementMaskTestCase.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Tests/Visual/HitObjectPlacementMaskTestCase.cs b/osu.Game/Tests/Visual/HitObjectPlacementMaskTestCase.cs index bb9b8a33bc..adf74b9a7d 100644 --- a/osu.Game/Tests/Visual/HitObjectPlacementMaskTestCase.cs +++ b/osu.Game/Tests/Visual/HitObjectPlacementMaskTestCase.cs @@ -20,6 +20,8 @@ namespace osu.Game.Tests.Visual protected HitObjectPlacementMaskTestCase() { + Beatmap.Value.BeatmapInfo.BaseDifficulty.CircleSize = 2; + Add(hitObjectContainer = new Container { RelativeSizeAxes = Axes.Both, From cf3b4447eb04413d0b3de61500abf417d9c0ee68 Mon Sep 17 00:00:00 2001 From: HoLLy Date: Fri, 26 Oct 2018 13:35:51 +0200 Subject: [PATCH 180/333] Fade only textContainer instead of entire MetadataSection --- osu.Game/Screens/Select/BeatmapDetails.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index 9a16c76c44..3999adfede 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.cs @@ -307,10 +307,10 @@ namespace osu.Game.Screens.Select { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; - Alpha = 0; InternalChild = textContainer = new FillFlowContainer { + Alpha = 0, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Spacing = new Vector2(spacing / 2), @@ -337,17 +337,14 @@ namespace osu.Game.Screens.Select { if (string.IsNullOrEmpty(value)) { - this.FadeOut(transition_duration); + textContainer.FadeOut(transition_duration); return; } - this.FadeIn(transition_duration); setTextAsync(value); } } - public override bool IsPresent => base.IsPresent || textFlow == null; // Visibility is updated in the LoadComponentAsync callback - private void setTextAsync(string text) { LoadComponentAsync(new OsuTextFlowContainer(s => s.TextSize = 14) @@ -362,7 +359,7 @@ namespace osu.Game.Screens.Select textContainer.Add(textFlow = loaded); // fade in if we haven't yet. - this.FadeIn(transition_duration); + textContainer.FadeIn(transition_duration); }); } } From a711112074d4eb30c4e452f498798a5af4d75785 Mon Sep 17 00:00:00 2001 From: TPGPL Date: Fri, 26 Oct 2018 14:08:29 +0200 Subject: [PATCH 181/333] Delete redundant fields --- .github/ISSUE_TEMPLATE/bug-issues.md | 2 -- .github/ISSUE_TEMPLATE/crash-issues.md | 2 -- .github/ISSUE_TEMPLATE/feature-issues.md | 2 -- .github/ISSUE_TEMPLATE/gamefeatures-issues.md | 2 -- 4 files changed, 8 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug-issues.md b/.github/ISSUE_TEMPLATE/bug-issues.md index ea29402902..8d85c92fec 100644 --- a/.github/ISSUE_TEMPLATE/bug-issues.md +++ b/.github/ISSUE_TEMPLATE/bug-issues.md @@ -5,8 +5,6 @@ about: For issues regarding encountered game bugs -**What is your problem:** - **Describe your problem:** **Screenshots or videos showing encountered issue:** diff --git a/.github/ISSUE_TEMPLATE/crash-issues.md b/.github/ISSUE_TEMPLATE/crash-issues.md index 7cf6acd549..6c82fdb1d1 100644 --- a/.github/ISSUE_TEMPLATE/crash-issues.md +++ b/.github/ISSUE_TEMPLATE/crash-issues.md @@ -5,8 +5,6 @@ about: For issues regarding game crashes or permanent freezes -**What is your problem:** - **Describe your problem:** **Screenshots or videos showing encountered issue:** diff --git a/.github/ISSUE_TEMPLATE/feature-issues.md b/.github/ISSUE_TEMPLATE/feature-issues.md index fbc44c5a03..73c4f37a3e 100644 --- a/.github/ISSUE_TEMPLATE/feature-issues.md +++ b/.github/ISSUE_TEMPLATE/feature-issues.md @@ -5,8 +5,6 @@ about: Let us know what you would like to see in the game! -**Feature Request:** - **Describe the feature:** **Proposal designs of the feature:** diff --git a/.github/ISSUE_TEMPLATE/gamefeatures-issues.md b/.github/ISSUE_TEMPLATE/gamefeatures-issues.md index a94efed32f..473fb4ae20 100644 --- a/.github/ISSUE_TEMPLATE/gamefeatures-issues.md +++ b/.github/ISSUE_TEMPLATE/gamefeatures-issues.md @@ -5,8 +5,6 @@ about: For issues regarding features to be found in the game -**Feature Request:** - **Describe the feature:** **Designs:** From daf7337fba8ffc774d7b59b39dcde38d2ea8923e Mon Sep 17 00:00:00 2001 From: TPGPL Date: Fri, 26 Oct 2018 14:09:17 +0200 Subject: [PATCH 182/333] Rename the issue templates --- .../{feature-issues.md => feature-request-issues.md} | 0 .../{gamefeatures-issues.md => missing-for-live-issues.md} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename .github/ISSUE_TEMPLATE/{feature-issues.md => feature-request-issues.md} (100%) rename .github/ISSUE_TEMPLATE/{gamefeatures-issues.md => missing-for-live-issues.md} (100%) diff --git a/.github/ISSUE_TEMPLATE/feature-issues.md b/.github/ISSUE_TEMPLATE/feature-request-issues.md similarity index 100% rename from .github/ISSUE_TEMPLATE/feature-issues.md rename to .github/ISSUE_TEMPLATE/feature-request-issues.md diff --git a/.github/ISSUE_TEMPLATE/gamefeatures-issues.md b/.github/ISSUE_TEMPLATE/missing-for-live-issues.md similarity index 100% rename from .github/ISSUE_TEMPLATE/gamefeatures-issues.md rename to .github/ISSUE_TEMPLATE/missing-for-live-issues.md From 52a9e21d3256dee3084feb40d401e25ce912ff6e Mon Sep 17 00:00:00 2001 From: TPGPL Date: Fri, 26 Oct 2018 14:12:18 +0200 Subject: [PATCH 183/333] Restructure the MfL issue template --- .github/ISSUE_TEMPLATE/missing-for-live-issues.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/missing-for-live-issues.md b/.github/ISSUE_TEMPLATE/missing-for-live-issues.md index 473fb4ae20..929399d192 100644 --- a/.github/ISSUE_TEMPLATE/missing-for-live-issues.md +++ b/.github/ISSUE_TEMPLATE/missing-for-live-issues.md @@ -1,10 +1,10 @@ --- -name: Game Feature -about: For issues regarding features to be found in the game +name: Missing for Live +about: For issues regarding game features required for live --- -**Describe the feature:** +**Describe the feature:** -**Designs:** +**Designs:** From df6fc4013a6e34c21b416e015726b1a533132365 Mon Sep 17 00:00:00 2001 From: Kyle Chang Date: Sun, 28 Oct 2018 01:40:19 -0400 Subject: [PATCH 184/333] Add interface to adjust Beatmaps --- .../Rulesets/Mods/IApplicableToBeatmap.cs | 19 +++++++++++++++++++ osu.Game/Rulesets/UI/RulesetContainer.cs | 19 +++++++++++++++++-- 2 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 osu.Game/Rulesets/Mods/IApplicableToBeatmap.cs diff --git a/osu.Game/Rulesets/Mods/IApplicableToBeatmap.cs b/osu.Game/Rulesets/Mods/IApplicableToBeatmap.cs new file mode 100644 index 0000000000..e1398ecf2b --- /dev/null +++ b/osu.Game/Rulesets/Mods/IApplicableToBeatmap.cs @@ -0,0 +1,19 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Beatmaps; + +namespace osu.Game.Rulesets.Mods +{ + /// + /// Interface for a that applies changes to a . + /// + public interface IApplicableToBeatmap : IApplicableMod + { + /// + /// Applies this to a . + /// + /// The to apply to. + void ApplyToBeatmap(IBeatmap beatmap); + } +} diff --git a/osu.Game/Rulesets/UI/RulesetContainer.cs b/osu.Game/Rulesets/UI/RulesetContainer.cs index a23a5a78f7..4b55bb558d 100644 --- a/osu.Game/Rulesets/UI/RulesetContainer.cs +++ b/osu.Game/Rulesets/UI/RulesetContainer.cs @@ -238,6 +238,8 @@ namespace osu.Game.Rulesets.UI KeyBindingInputManager = CreateInputManager(); KeyBindingInputManager.RelativeSizeAxes = Axes.Both; + + applyBeatmapMods(Mods); } [BackgroundDependencyLoader] @@ -255,16 +257,29 @@ namespace osu.Game.Rulesets.UI KeyBindingInputManager.Add(Cursor); // Apply mods - applyMods(Mods, config); + applyRulesetMods(Mods, config); loadObjects(); } + /// + /// Applies the active mods to the Beatmap. + /// + /// + private void applyBeatmapMods(IEnumerable mods) + { + if (mods == null) + return; + + foreach (var mod in mods.OfType()) + mod.ApplyToBeatmap(Beatmap); + } + /// /// Applies the active mods to this RulesetContainer. /// /// - private void applyMods(IEnumerable mods, OsuConfigManager config) + private void applyRulesetMods(IEnumerable mods, OsuConfigManager config) { if (mods == null) return; From 9b246f065c07769e8623edf9bf7e9885b0b5130c Mon Sep 17 00:00:00 2001 From: Kyle Chang Date: Sun, 28 Oct 2018 02:20:46 -0400 Subject: [PATCH 185/333] Have dual stage mod apply changes to beatmap directly --- .../Mods/ManiaModDualStages.cs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModDualStages.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModDualStages.cs index aecfb50fbe..12b62d2b65 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModDualStages.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModDualStages.cs @@ -4,14 +4,11 @@ using System.Collections.Generic; using osu.Game.Beatmaps; using osu.Game.Rulesets.Mania.Beatmaps; -using osu.Game.Rulesets.Mania.Objects; -using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Mania.Mods { - public class ManiaModDualStages : Mod, IPlayfieldTypeMod, IApplicableToBeatmapConverter, IApplicableToRulesetContainer + public class ManiaModDualStages : Mod, IPlayfieldTypeMod, IApplicableToBeatmapConverter, IApplicableToBeatmap { public override string Name => "Dual Stages"; public override string ShortenedName => "DS"; @@ -34,22 +31,21 @@ namespace osu.Game.Rulesets.Mania.Mods mbc.TargetColumns *= 2; } - public void ApplyToRulesetContainer(RulesetContainer rulesetContainer) + public void ApplyToBeatmap(IBeatmap beatmap) { - var mrc = (ManiaRulesetContainer)rulesetContainer; - - // Although this can work, for now let's not allow keymods for mania-specific beatmaps if (isForCurrentRuleset) return; + var maniaBeatmap = (ManiaBeatmap) beatmap; + var newDefinitions = new List(); - foreach (var existing in mrc.Beatmap.Stages) + foreach (var existing in maniaBeatmap.Stages) { newDefinitions.Add(new StageDefinition { Columns = existing.Columns / 2 }); newDefinitions.Add(new StageDefinition { Columns = existing.Columns / 2 }); } - mrc.Beatmap.Stages = newDefinitions; + maniaBeatmap.Stages = newDefinitions; } public PlayfieldType PlayfieldType => PlayfieldType.Dual; From 3a61594da4924803d860536a7829c1e1d5854025 Mon Sep 17 00:00:00 2001 From: miterosan Date: Sun, 28 Oct 2018 13:04:54 +0100 Subject: [PATCH 186/333] Reference the build script in the README. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index dc36145337..d0919e1d82 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ Build and run - Using Visual Studio 2017, Rider or Visual Studio Code (configurations are included) - From command line using `dotnet run --project osu.Desktop`. When building for non-development purposes, add `-c Release` to gain higher performance. +- And from command line using `powershell ./build.ps1`. This will also run tests and code analysis. This command is used on CI. The code analysis is windows only. Note: If you run from command line under linux, you will need to prefix the output folder to your `LD_LIBRARY_PATH`. See `.vscode/launch.json` for an example From f8a8c7cb6bc229170f5715ea4463d1c8542c7d1c Mon Sep 17 00:00:00 2001 From: Kyle Chang Date: Sun, 28 Oct 2018 12:43:19 -0400 Subject: [PATCH 187/333] Stop transferring track when editing --- osu.Game/Screens/Select/SongSelect.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index b4f552ce93..9d7e84aa04 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -225,7 +225,7 @@ namespace osu.Game.Screens.Select public void Edit(BeatmapInfo beatmap) { - Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap, Beatmap.Value); + Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap); Push(new Editor()); } From 2b736c3cd64727a720e0b8e23973804facb295ba Mon Sep 17 00:00:00 2001 From: Kyle Chang Date: Sun, 28 Oct 2018 13:04:45 -0400 Subject: [PATCH 188/333] Make beatmap edit button reload beatmap without mods --- osu.Game/Screens/Select/PlaySongSelect.cs | 2 +- osu.Game/Screens/Select/SongSelect.cs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index 917a08d172..fdb82f9e7f 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -68,7 +68,7 @@ namespace osu.Game.Screens.Select BeatmapOptions.AddButton(@"Edit", @"beatmap", FontAwesome.fa_pencil, colours.Yellow, () => { ValidForResume = false; - Push(new Editor()); + EditSelected(); }, Key.Number3); if (dialogOverlay != null) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 9d7e84aa04..32e77bb914 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -229,6 +229,8 @@ namespace osu.Game.Screens.Select Push(new Editor()); } + protected void EditSelected() => Edit(beatmapNoDebounce); + /// /// Call to make a selection and perform the default action for this SongSelect. /// From 886dd0f0d46fe2ba4f1192f2d01024a4e95d5560 Mon Sep 17 00:00:00 2001 From: Kyle Chang Date: Sun, 28 Oct 2018 13:21:12 -0400 Subject: [PATCH 189/333] Remove unneeded using directive --- osu.Game/Screens/Select/PlaySongSelect.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index fdb82f9e7f..1c4a0c58e9 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -16,7 +16,6 @@ using osu.Game.Graphics; using osu.Game.Overlays; using osu.Game.Overlays.Mods; using osu.Game.Rulesets.Mods; -using osu.Game.Screens.Edit; using osu.Game.Screens.Play; using osu.Game.Screens.Ranking; using osu.Game.Skinning; From c7e950af7f86ebaf2693b3f46eb035869fbe504d Mon Sep 17 00:00:00 2001 From: Kyle Chang Date: Mon, 29 Oct 2018 00:04:51 -0400 Subject: [PATCH 190/333] Remove EditSelected in favor in inlining beatmapNoDebounce in Edit --- osu.Game/Screens/Select/PlaySongSelect.cs | 2 +- osu.Game/Screens/Select/SongSelect.cs | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index 1c4a0c58e9..285410ce20 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -67,7 +67,7 @@ namespace osu.Game.Screens.Select BeatmapOptions.AddButton(@"Edit", @"beatmap", FontAwesome.fa_pencil, colours.Yellow, () => { ValidForResume = false; - EditSelected(); + Edit(); }, Key.Number3); if (dialogOverlay != null) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 32e77bb914..4288483caf 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -223,14 +223,12 @@ namespace osu.Game.Screens.Select Carousel.LoadBeatmapSetsFromManager(this.beatmaps); } - public void Edit(BeatmapInfo beatmap) + public void Edit(BeatmapInfo beatmap = null) { - Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap); + Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap ?? beatmapNoDebounce); Push(new Editor()); } - protected void EditSelected() => Edit(beatmapNoDebounce); - /// /// Call to make a selection and perform the default action for this SongSelect. /// From 86e09a68f7749dd35f5056859ea4f8f7e0df415c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 25 Oct 2018 15:49:45 +0900 Subject: [PATCH 191/333] Separate slider body to bypass snaking logic The snaking logic contains a lot of caching/optimisations and offsetting of the path which is tedious to re-compute when the path changes. --- .../Objects/Drawables/DrawableSlider.cs | 4 +- .../Drawables/Pieces/ManualSliderBody.cs | 20 +++ .../Objects/Drawables/Pieces/SliderBody.cs | 129 +++--------------- .../Drawables/Pieces/SnakingSliderBody.cs | 105 ++++++++++++++ 4 files changed, 146 insertions(+), 112 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ManualSliderBody.cs create mode 100644 osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SnakingSliderBody.cs diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index 89f380db4e..16bd522c1d 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables public readonly DrawableHitCircle HeadCircle; public readonly DrawableSliderTail TailCircle; - public readonly SliderBody Body; + public readonly SnakingSliderBody Body; public readonly SliderBall Ball; public DrawableSlider(Slider s) @@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables InternalChildren = new Drawable[] { - Body = new SliderBody(s) + Body = new SnakingSliderBody(s) { PathWidth = s.Scale * 64, }, diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ManualSliderBody.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ManualSliderBody.cs new file mode 100644 index 0000000000..9d239c15f2 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ManualSliderBody.cs @@ -0,0 +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 OpenTK; + +namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces +{ + /// + /// A with the ability to set the drawn vertices manually. + /// + public class ManualSliderBody : SliderBody + { + public new void SetVertices(IReadOnlyList vertices) + { + base.SetVertices(vertices); + Size = Path.Size; + } + } +} diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs index f4ccf673e9..ca2daa3adb 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs @@ -1,24 +1,22 @@ -// 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 osu.Framework.Allocation; -using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Lines; -using OpenTK.Graphics.ES30; -using OpenTK.Graphics; using osu.Framework.Graphics.Primitives; -using osu.Game.Rulesets.Objects.Types; using OpenTK; +using OpenTK.Graphics; +using OpenTK.Graphics.ES30; namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces { - public class SliderBody : Container, ISliderProgress + public abstract class SliderBody : CompositeDrawable { private readonly SliderPath path; + protected Path Path => path; + private readonly BufferedContainer container; public float PathWidth @@ -30,15 +28,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces /// /// Offset in absolute coordinates from the start of the curve. /// - public Vector2 PathOffset { get; private set; } - - public readonly List CurrentCurve = new List(); - - public readonly Bindable SnakingIn = new Bindable(); - public readonly Bindable SnakingOut = new Bindable(); - - public double? SnakedStart { get; private set; } - public double? SnakedEnd { get; private set; } + public virtual Vector2 PathOffset => path.PositionInBoundingBox(path.Vertices[0]); /// /// Used to colour the path. @@ -74,28 +64,13 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces public Quad PathDrawQuad => container.ScreenSpaceDrawQuad; - private Vector2 topLeftOffset; - - private readonly Slider slider; - - public SliderBody(Slider s) + protected SliderBody() { - slider = s; - - Children = new Drawable[] + InternalChild = container = new BufferedContainer { - container = new BufferedContainer - { - RelativeSizeAxes = Axes.Both, - CacheDrawnFrameBuffer = true, - Children = new Drawable[] - { - path = new SliderPath - { - Blending = BlendingMode.None, - }, - } - }, + RelativeSizeAxes = Axes.Both, + CacheDrawnFrameBuffer = true, + Child = path = new SliderPath { Blending = BlendingMode.None } }; container.Attach(RenderbufferInternalFormat.DepthComponent16); @@ -103,80 +78,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => path.ReceivePositionalInputAt(screenSpacePos); - public void SetRange(double p0, double p1) + /// + /// Sets the vertices of the path which should be drawn by this . + /// + /// The vertices + protected void SetVertices(IReadOnlyList vertices) { - if (p0 > p1) - MathHelper.Swap(ref p0, ref p1); - - if (updateSnaking(p0, p1)) - { - // The path is generated such that its size encloses it. This change of size causes the path - // to move around while snaking, so we need to offset it to make sure it maintains the - // same position as when it is fully snaked. - var newTopLeftOffset = path.PositionInBoundingBox(Vector2.Zero); - path.Position = topLeftOffset - newTopLeftOffset; - - container.ForceRedraw(); - } - } - - [BackgroundDependencyLoader] - private void load() - { - computeSize(); - } - - private void computeSize() - { - // Generate the entire curve - slider.Curve.GetPathToProgress(CurrentCurve, 0, 1); - foreach (Vector2 p in CurrentCurve) - path.AddVertex(p); - - Size = path.Size; - - topLeftOffset = path.PositionInBoundingBox(Vector2.Zero); - PathOffset = path.PositionInBoundingBox(CurrentCurve[0]); - } - - private bool updateSnaking(double p0, double p1) - { - if (SnakedStart == p0 && SnakedEnd == p1) return false; - - SnakedStart = p0; - SnakedEnd = p1; - - slider.Curve.GetPathToProgress(CurrentCurve, p0, p1); - - path.ClearVertices(); - foreach (Vector2 p in CurrentCurve) - path.AddVertex(p); - - return true; - } - - public void UpdateProgress(double completionProgress) - { - var span = slider.SpanAt(completionProgress); - var spanProgress = slider.ProgressAt(completionProgress); - - double start = 0; - double end = SnakingIn ? MathHelper.Clamp((Time.Current - (slider.StartTime - slider.TimePreempt)) / slider.TimeFadeIn, 0, 1) : 1; - - if (span >= slider.SpanCount() - 1) - { - if (Math.Min(span, slider.SpanCount() - 1) % 2 == 1) - { - start = 0; - end = SnakingOut ? spanProgress : 1; - } - else - { - start = SnakingOut ? spanProgress : 0; - } - } - - SetRange(start, end); + path.Vertices = vertices; + container.ForceRedraw(); } private class SliderPath : SmoothPath diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SnakingSliderBody.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SnakingSliderBody.cs new file mode 100644 index 0000000000..09d6f9459a --- /dev/null +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SnakingSliderBody.cs @@ -0,0 +1,105 @@ +// 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.Allocation; +using osu.Framework.Configuration; +using osu.Game.Rulesets.Objects.Types; +using OpenTK; + +namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces +{ + /// + /// A which changes its curve depending on the snaking progress. + /// + public class SnakingSliderBody : SliderBody, ISliderProgress + { + public readonly List CurrentCurve = new List(); + + public readonly Bindable SnakingIn = new Bindable(); + public readonly Bindable SnakingOut = new Bindable(); + + public double? SnakedStart { get; private set; } + public double? SnakedEnd { get; private set; } + + public override Vector2 PathOffset => snakedPathOffset; + + /// + /// The top-left position of the path when fully snaked. + /// + private Vector2 snakedPosition; + + /// + /// The offset of the path from when fully snaked. + /// + private Vector2 snakedPathOffset; + + private readonly Slider slider; + + public SnakingSliderBody(Slider slider) + { + this.slider = slider; + } + + [BackgroundDependencyLoader] + private void load() + { + // Generate the entire curve + slider.Curve.GetPathToProgress(CurrentCurve, 0, 1); + SetVertices(CurrentCurve); + + // The body is sized to the full path size to avoid excessive autosize computations + Size = Path.Size; + + snakedPosition = Path.PositionInBoundingBox(Vector2.Zero); + snakedPathOffset = Path.PositionInBoundingBox(Path.Vertices[0]); + } + + public void UpdateProgress(double completionProgress) + { + var span = slider.SpanAt(completionProgress); + var spanProgress = slider.ProgressAt(completionProgress); + + double start = 0; + double end = SnakingIn ? MathHelper.Clamp((Time.Current - (slider.StartTime - slider.TimePreempt)) / slider.TimeFadeIn, 0, 1) : 1; + + if (span >= slider.SpanCount() - 1) + { + if (Math.Min(span, slider.SpanCount() - 1) % 2 == 1) + { + start = 0; + end = SnakingOut ? spanProgress : 1; + } + else + { + start = SnakingOut ? spanProgress : 0; + } + } + + setRange(start, end); + } + + private void setRange(double p0, double p1) + { + if (p0 > p1) + MathHelper.Swap(ref p0, ref p1); + + if (SnakedStart == p0 && SnakedEnd == p1) return; + + SnakedStart = p0; + SnakedEnd = p1; + + slider.Curve.GetPathToProgress(CurrentCurve, p0, p1); + + SetVertices(CurrentCurve); + + // The bounding box of the path expands as it snakes, which in turn shifts the position of the path. + // Depending on the direction of expansion, it may appear as if the path is expanding towards the position of the slider + // rather than expanding out from the position of the slider. + // To remove this effect, the path's position is shifted towards its final snaked position + + Path.Position = snakedPosition - Path.PositionInBoundingBox(Vector2.Zero); + } + } +} From dd5a3ad59cfef2e37cf778eb1adb1cc8650d9b67 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 29 Oct 2018 15:17:45 +0900 Subject: [PATCH 192/333] Fix SliderMask not working --- .../Edit/Layers/Selection/Overlays/SliderMask.cs | 4 ++-- osu.Game/osu.Game.csproj | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderMask.cs b/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderMask.cs index aff42dd233..90d1b8f31a 100644 --- a/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderMask.cs @@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Layers.Selection.Overlays { public class SliderMask : HitObjectMask { - private readonly SliderBody body; + private readonly SnakingSliderBody body; private readonly DrawableSlider slider; public SliderMask(DrawableSlider slider) @@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Layers.Selection.Overlays InternalChildren = new Drawable[] { - body = new SliderBody(sliderObject) + body = new SnakingSliderBody(sliderObject) { AccentColour = Color4.Transparent, PathWidth = sliderObject.Scale * 64 diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 26004b513f..e2b466c69f 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -18,7 +18,7 @@ - + From 9b19050fafde5ebe051f7b2daa478805644552e1 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 29 Oct 2018 15:25:20 +0900 Subject: [PATCH 193/333] Update with slider body changes --- .../Edit/Masks/SliderMasks/Components/SliderBodyPiece.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderBodyPiece.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderBodyPiece.cs index 0595b046d1..3123a4fcea 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderBodyPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderBodyPiece.cs @@ -13,12 +13,12 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components public class SliderBodyPiece : CompositeDrawable { private readonly Slider slider; - private readonly SliderBody body; + private readonly SnakingSliderBody body; public SliderBodyPiece(Slider slider) { this.slider = slider; - InternalChild = body = new SliderBody(slider) + InternalChild = body = new SnakingSliderBody(slider) { AccentColour = Color4.Transparent, PathWidth = slider.Scale * 64 From 38ce8f8af1fec6b7ff25b0594edca3a820c281b8 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 4 Oct 2018 13:44:20 +0900 Subject: [PATCH 194/333] Refactor SliderSelectionMask --- .../Edit/Masks/SliderSelectionMask.cs | 67 +++++++++++++++++++ ...SliderSelectionMask_CircleSelectionMask.cs | 64 ++++++++++++++++++ .../Visual/TestCaseHitObjectComposer.cs | 1 + 3 files changed, 132 insertions(+) create mode 100644 osu.Game.Rulesets.Osu/Edit/Masks/SliderSelectionMask.cs create mode 100644 osu.Game.Rulesets.Osu/Edit/Masks/SliderSelectionMask_CircleSelectionMask.cs diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderSelectionMask.cs new file mode 100644 index 0000000000..46c807f4b3 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderSelectionMask.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 osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Primitives; +using osu.Game.Graphics; +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; +using OpenTK; +using OpenTK.Graphics; + +namespace osu.Game.Rulesets.Osu.Edit.Masks +{ + public partial class SliderSelectionMask : SelectionMask + { + private readonly SliderBody body; + private readonly DrawableSlider slider; + + public SliderSelectionMask(DrawableSlider slider) + : base(slider) + { + this.slider = slider; + + Position = slider.Position; + + var sliderObject = (Slider)slider.HitObject; + + InternalChildren = new Drawable[] + { + body = new SliderBody(sliderObject) + { + AccentColour = Color4.Transparent, + PathWidth = sliderObject.Scale * 64 + }, + new CircleSelectionMask(slider.HeadCircle, slider), + new CircleSelectionMask(slider.TailCircle, slider), + }; + + sliderObject.PositionChanged += _ => Position = slider.Position; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + body.BorderColour = colours.Yellow; + } + + protected override void Update() + { + base.Update(); + + Size = slider.Size; + OriginPosition = slider.OriginPosition; + + // Need to cause one update + body.UpdateProgress(0); + } + + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => body.ReceivePositionalInputAt(screenSpacePos); + + public override Vector2 SelectionPoint => ToScreenSpace(OriginPosition); + public override Quad SelectionQuad => body.PathDrawQuad; + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderSelectionMask_CircleSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderSelectionMask_CircleSelectionMask.cs new file mode 100644 index 0000000000..f4d4749343 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderSelectionMask_CircleSelectionMask.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 osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Game.Graphics; +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; +using OpenTK; + +namespace osu.Game.Rulesets.Osu.Edit.Masks +{ + public partial class SliderSelectionMask + { + private class CircleSelectionMask : SelectionMask + { + public CircleSelectionMask(DrawableHitCircle sliderHead, DrawableSlider slider) + : this(sliderHead, Vector2.Zero, slider) + { + } + + public CircleSelectionMask(DrawableSliderTail sliderTail, DrawableSlider slider) + : this(sliderTail, ((Slider)slider.HitObject).Curve.PositionAt(1), slider) + { + } + + private readonly DrawableOsuHitObject hitObject; + + private CircleSelectionMask(DrawableOsuHitObject hitObject, Vector2 position, DrawableSlider slider) + : base(hitObject) + { + this.hitObject = hitObject; + + Origin = Anchor.Centre; + + Position = position; + Size = slider.HeadCircle.Size; + Scale = slider.HeadCircle.Scale; + + AddInternal(new RingPiece()); + + Select(); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + Colour = colours.Yellow; + } + + protected override void Update() + { + base.Update(); + + RelativeAnchorPosition = hitObject.RelativeAnchorPosition; + } + + // 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; + } + } +} diff --git a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs index 61647ffdc5..99a8f3f51b 100644 --- a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs +++ b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs @@ -37,6 +37,7 @@ namespace osu.Game.Tests.Visual typeof(HitCirclePiece), typeof(HitCircleSelectionMask), typeof(HitCirclePlacementMask), + typeof(SliderSelectionMask), }; private HitObjectComposer composer; From bd915e8dca19e43468b12a3a592249064c5e8137 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 4 Oct 2018 13:44:49 +0900 Subject: [PATCH 195/333] Implement initial slider placement (linear) --- .../Edit/Masks/SliderPlacementMask.cs | 99 +++++++++++++++++++ ...SliderPlacementMask_CirclePlacementMask.cs | 29 ++++++ .../Edit/OsuHitObjectComposer.cs | 3 +- .../Edit/SliderCompositionTool.cs | 20 ++++ .../Visual/TestCaseHitObjectComposer.cs | 1 + 5 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask.cs create mode 100644 osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask_CirclePlacementMask.cs create mode 100644 osu.Game.Rulesets.Osu/Edit/SliderCompositionTool.cs diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask.cs new file mode 100644 index 0000000000..287d19ed93 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask.cs @@ -0,0 +1,99 @@ +// 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.Drawing.Imaging; +using System.Linq; +using osu.Framework.Graphics; +using osu.Framework.Input.Events; +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Objects.Types; +using osu.Game.Rulesets.Osu.Objects; +using OpenTK; + +namespace osu.Game.Rulesets.Osu.Edit.Masks +{ + public partial class SliderPlacementMask : PlacementMask + { + public new Slider HitObject => (Slider)base.HitObject; + + private readonly CirclePlacementMask headMask; + private readonly CirclePlacementMask tailMask; + + private readonly List controlPoints = new List(); + + private PlacementState state = PlacementState.Head; + + public SliderPlacementMask() + : base(new Slider()) + { + RelativeSizeAxes = Axes.Both; + + InternalChildren = new Drawable[] + { + headMask = new CirclePlacementMask(), + tailMask = new CirclePlacementMask(), + }; + + setState(PlacementState.Head); + } + + protected override bool OnMouseMove(MouseMoveEvent e) + { + switch (state) + { + case PlacementState.Head: + headMask.Position = e.MousePosition; + return true; + case PlacementState.Tail: + tailMask.Position = ToLocalSpace(e.ScreenSpaceMousePosition); + return true; + } + + return false; + } + + protected override bool OnClick(ClickEvent e) + { + switch (state) + { + case PlacementState.Head: + setState(PlacementState.Tail); + controlPoints.Add(Vector2.Zero); + break; + case PlacementState.Tail: + controlPoints.Add(tailMask.Position - headMask.Position); + HitObject.Position = headMask.Position; + HitObject.ControlPoints = controlPoints.ToList(); + HitObject.CurveType = CurveType.Linear; + HitObject.Distance = Vector2.Distance(controlPoints.First(), controlPoints.Last()); + Finish(); + break; + } + + return base.OnClick(e); + } + + private void setState(PlacementState newState) + { + switch (newState) + { + case PlacementState.Head: + tailMask.Alpha = 0; + break; + case PlacementState.Tail: + tailMask.Alpha = 1; + break; + } + + state = newState; + } + + private enum PlacementState + { + Head, + Body, + Tail + } + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask_CirclePlacementMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask_CirclePlacementMask.cs new file mode 100644 index 0000000000..4a3574c885 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask_CirclePlacementMask.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.Graphics; +using osu.Framework.Input.Events; +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Osu.Objects; + +namespace osu.Game.Rulesets.Osu.Edit.Masks +{ + public partial class SliderPlacementMask + { + private class CirclePlacementMask : PlacementMask + { + public new HitCircle HitObject => (HitCircle)base.HitObject; + + public CirclePlacementMask() + : base(new HitCircle()) + { + Origin = Anchor.Centre; + AutoSizeAxes = Axes.Both; + + InternalChild = new HitCircleMask(HitObject); + } + + protected override bool Handle(UIEvent e) => false; + } + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index ac41d6ef27..c54cec94f6 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -27,9 +27,10 @@ namespace osu.Game.Rulesets.Osu.Edit protected override RulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) => new OsuEditRulesetContainer(ruleset, beatmap); - protected override IReadOnlyList CompositionTools => new[] + protected override IReadOnlyList CompositionTools => new HitObjectCompositionTool[] { new HitCircleCompositionTool(), + new SliderCompositionTool(), }; protected override Container CreateLayerContainer() => new PlayfieldAdjustmentContainer { RelativeSizeAxes = Axes.Both }; diff --git a/osu.Game.Rulesets.Osu/Edit/SliderCompositionTool.cs b/osu.Game.Rulesets.Osu/Edit/SliderCompositionTool.cs new file mode 100644 index 0000000000..f7cdd76655 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/SliderCompositionTool.cs @@ -0,0 +1,20 @@ +// 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.Edit.Tools; +using osu.Game.Rulesets.Osu.Edit.Masks; +using osu.Game.Rulesets.Osu.Objects; + +namespace osu.Game.Rulesets.Osu.Edit +{ + public class SliderCompositionTool : HitObjectCompositionTool + { + public SliderCompositionTool() + : base(nameof(Slider)) + { + } + + public override PlacementMask CreatePlacementMask() => new SliderPlacementMask(); + } +} diff --git a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs index 99a8f3f51b..196cb9320a 100644 --- a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs +++ b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs @@ -38,6 +38,7 @@ namespace osu.Game.Tests.Visual typeof(HitCircleSelectionMask), typeof(HitCirclePlacementMask), typeof(SliderSelectionMask), + typeof(SliderPlacementMask) }; private HitObjectComposer composer; From b3e105ba932146c5c9753d68148799e12f1dfe02 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 4 Oct 2018 16:13:18 +0900 Subject: [PATCH 196/333] Make curve approximators implement common interface --- .../Rulesets/Objects/BezierApproximator.cs | 125 +++++++++--------- .../Rulesets/Objects/CatmullApproximator.cs | 20 +-- .../Objects/CircularArcApproximator.cs | 14 +- osu.Game/Rulesets/Objects/IApproximator.cs | 13 ++ .../Rulesets/Objects/LinearApproximator.cs | 13 ++ 5 files changed, 96 insertions(+), 89 deletions(-) create mode 100644 osu.Game/Rulesets/Objects/IApproximator.cs create mode 100644 osu.Game/Rulesets/Objects/LinearApproximator.cs diff --git a/osu.Game/Rulesets/Objects/BezierApproximator.cs b/osu.Game/Rulesets/Objects/BezierApproximator.cs index a1803e32f7..011526339e 100644 --- a/osu.Game/Rulesets/Objects/BezierApproximator.cs +++ b/osu.Game/Rulesets/Objects/BezierApproximator.cs @@ -1,29 +1,77 @@ // 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 OpenTK; namespace osu.Game.Rulesets.Objects { - public readonly ref struct BezierApproximator + public class BezierApproximator : IApproximator { - private readonly int count; - private readonly ReadOnlySpan controlPoints; - private readonly Vector2[] subdivisionBuffer1; - private readonly Vector2[] subdivisionBuffer2; - private const float tolerance = 0.25f; private const float tolerance_sq = tolerance * tolerance; - public BezierApproximator(ReadOnlySpan controlPoints) - { - this.controlPoints = controlPoints; - count = controlPoints.Length; + private int count; + private Vector2[] subdivisionBuffer1; + private Vector2[] subdivisionBuffer2; + /// + /// Creates a piecewise-linear approximation of a bezier curve, by adaptively repeatedly subdividing + /// the control points until their approximation error vanishes below a given threshold. + /// + /// A list of vectors representing the piecewise-linear approximation. + public List Approximate(List controlPoints) + { + count = controlPoints.Count; subdivisionBuffer1 = new Vector2[count]; subdivisionBuffer2 = new Vector2[count * 2 - 1]; + + List output = new List(); + + if (count == 0) + return output; + + Stack toFlatten = new Stack(); + Stack freeBuffers = new Stack(); + + // "toFlatten" contains all the curves which are not yet approximated well enough. + // We use a stack to emulate recursion without the risk of running into a stack overflow. + // (More specifically, we iteratively and adaptively refine our curve with a + // Depth-first search + // over the tree resulting from the subdivisions we make.) + toFlatten.Push(controlPoints.ToArray()); + + Vector2[] leftChild = subdivisionBuffer2; + + while (toFlatten.Count > 0) + { + Vector2[] parent = toFlatten.Pop(); + if (isFlatEnough(parent)) + { + // If the control points we currently operate on are sufficiently "flat", we use + // an extension to De Casteljau's algorithm to obtain a piecewise-linear approximation + // of the bezier curve represented by our control points, consisting of the same amount + // of points as there are control points. + approximate(parent, output); + freeBuffers.Push(parent); + continue; + } + + // If we do not yet have a sufficiently "flat" (in other words, detailed) approximation we keep + // subdividing the curve we are currently operating on. + Vector2[] rightChild = freeBuffers.Count > 0 ? freeBuffers.Pop() : new Vector2[count]; + subdivide(parent, leftChild, rightChild); + + // We re-use the buffer of the parent for one of the children, so that we save one allocation per iteration. + for (int i = 0; i < count; ++i) + parent[i] = leftChild[i]; + + toFlatten.Push(rightChild); + toFlatten.Push(parent); + } + + output.Add(controlPoints[count - 1]); + return output; } /// @@ -92,60 +140,5 @@ namespace osu.Game.Rulesets.Objects output.Add(p); } } - - /// - /// Creates a piecewise-linear approximation of a bezier curve, by adaptively repeatedly subdividing - /// the control points until their approximation error vanishes below a given threshold. - /// - /// A list of vectors representing the piecewise-linear approximation. - public List CreateBezier() - { - List output = new List(); - - if (count == 0) - return output; - - Stack toFlatten = new Stack(); - Stack freeBuffers = new Stack(); - - // "toFlatten" contains all the curves which are not yet approximated well enough. - // We use a stack to emulate recursion without the risk of running into a stack overflow. - // (More specifically, we iteratively and adaptively refine our curve with a - // Depth-first search - // over the tree resulting from the subdivisions we make.) - toFlatten.Push(controlPoints.ToArray()); - - Vector2[] leftChild = subdivisionBuffer2; - - while (toFlatten.Count > 0) - { - Vector2[] parent = toFlatten.Pop(); - if (isFlatEnough(parent)) - { - // If the control points we currently operate on are sufficiently "flat", we use - // an extension to De Casteljau's algorithm to obtain a piecewise-linear approximation - // of the bezier curve represented by our control points, consisting of the same amount - // of points as there are control points. - approximate(parent, output); - freeBuffers.Push(parent); - continue; - } - - // If we do not yet have a sufficiently "flat" (in other words, detailed) approximation we keep - // subdividing the curve we are currently operating on. - Vector2[] rightChild = freeBuffers.Count > 0 ? freeBuffers.Pop() : new Vector2[count]; - subdivide(parent, leftChild, rightChild); - - // We re-use the buffer of the parent for one of the children, so that we save one allocation per iteration. - for (int i = 0; i < count; ++i) - parent[i] = leftChild[i]; - - toFlatten.Push(rightChild); - toFlatten.Push(parent); - } - - output.Add(controlPoints[count - 1]); - return output; - } } } diff --git a/osu.Game/Rulesets/Objects/CatmullApproximator.cs b/osu.Game/Rulesets/Objects/CatmullApproximator.cs index 78f8e471f3..624f5fc9ab 100644 --- a/osu.Game/Rulesets/Objects/CatmullApproximator.cs +++ b/osu.Game/Rulesets/Objects/CatmullApproximator.cs @@ -1,40 +1,32 @@ // 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 OpenTK; namespace osu.Game.Rulesets.Objects { - public readonly ref struct CatmullApproximator + public class CatmullApproximator : IApproximator { /// /// The amount of pieces to calculate for each controlpoint quadruplet. /// private const int detail = 50; - private readonly ReadOnlySpan controlPoints; - - public CatmullApproximator(ReadOnlySpan controlPoints) - { - this.controlPoints = controlPoints; - } - /// /// Creates a piecewise-linear approximation of a Catmull-Rom spline. /// /// A list of vectors representing the piecewise-linear approximation. - public List CreateCatmull() + public List Approximate(List controlPoints) { - var result = new List((controlPoints.Length - 1) * detail * 2); + var result = new List(); - for (int i = 0; i < controlPoints.Length - 1; i++) + for (int i = 0; i < controlPoints.Count - 1; i++) { var v1 = i > 0 ? controlPoints[i - 1] : controlPoints[i]; var v2 = controlPoints[i]; - var v3 = i < controlPoints.Length - 1 ? controlPoints[i + 1] : v2 + v2 - v1; - var v4 = i < controlPoints.Length - 2 ? controlPoints[i + 2] : v3 + v3 - v2; + var v3 = i < controlPoints.Count - 1 ? controlPoints[i + 1] : v2 + v2 - v1; + var v4 = i < controlPoints.Count - 2 ? controlPoints[i + 2] : v3 + v3 - v2; for (int c = 0; c < detail; c++) { diff --git a/osu.Game/Rulesets/Objects/CircularArcApproximator.cs b/osu.Game/Rulesets/Objects/CircularArcApproximator.cs index 28d7442aaf..201c6296ba 100644 --- a/osu.Game/Rulesets/Objects/CircularArcApproximator.cs +++ b/osu.Game/Rulesets/Objects/CircularArcApproximator.cs @@ -8,23 +8,19 @@ using OpenTK; namespace osu.Game.Rulesets.Objects { - public readonly ref struct CircularArcApproximator + public class CircularArcApproximator : IApproximator { private const float tolerance = 0.1f; - private readonly ReadOnlySpan controlPoints; - - public CircularArcApproximator(ReadOnlySpan controlPoints) - { - this.controlPoints = controlPoints; - } - /// /// Creates a piecewise-linear approximation of a circular arc curve. /// /// A list of vectors representing the piecewise-linear approximation. - public List CreateArc() + public List Approximate(List controlPoints) { + if (controlPoints.Count != 3) + throw new ArgumentException("Must have 3 control points to perform circular arc approximation.", nameof(controlPoints)); + Vector2 a = controlPoints[0]; Vector2 b = controlPoints[1]; Vector2 c = controlPoints[2]; diff --git a/osu.Game/Rulesets/Objects/IApproximator.cs b/osu.Game/Rulesets/Objects/IApproximator.cs new file mode 100644 index 0000000000..f865172bb4 --- /dev/null +++ b/osu.Game/Rulesets/Objects/IApproximator.cs @@ -0,0 +1,13 @@ +// 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 OpenTK; + +namespace osu.Game.Rulesets.Objects +{ + public interface IApproximator + { + List Approximate(List controlPoints); + } +} diff --git a/osu.Game/Rulesets/Objects/LinearApproximator.cs b/osu.Game/Rulesets/Objects/LinearApproximator.cs new file mode 100644 index 0000000000..a2c2dd5a93 --- /dev/null +++ b/osu.Game/Rulesets/Objects/LinearApproximator.cs @@ -0,0 +1,13 @@ +// 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 OpenTK; + +namespace osu.Game.Rulesets.Objects +{ + public class LinearApproximator : IApproximator + { + public List Approximate(List controlpoints) => controlpoints; + } +} From 402950b132666db4ca4dea2c20df16731f18f16d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 4 Oct 2018 18:24:25 +0900 Subject: [PATCH 197/333] Implement path drawing --- .../Edit/Masks/SliderPlacementMask.cs | 157 +++++++++++++++--- 1 file changed, 135 insertions(+), 22 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask.cs index 287d19ed93..3ee63b1d7b 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask.cs @@ -2,14 +2,19 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System.Collections.Generic; -using System.Drawing.Imaging; using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; +using osu.Framework.Graphics.Lines; using osu.Framework.Input.Events; +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.Objects; using OpenTK; +using OpenTK.Input; namespace osu.Game.Rulesets.Osu.Edit.Masks { @@ -19,10 +24,12 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks private readonly CirclePlacementMask headMask; private readonly CirclePlacementMask tailMask; + private readonly Path path; - private readonly List controlPoints = new List(); + private readonly List segments = new List(); + private Vector2 cursor; - private PlacementState state = PlacementState.Head; + private PlacementState state; public SliderPlacementMask() : base(new Slider()) @@ -31,22 +38,32 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks InternalChildren = new Drawable[] { + path = new Path { PathWidth = 5 }, headMask = new CirclePlacementMask(), tailMask = new CirclePlacementMask(), }; - setState(PlacementState.Head); + segments.Add(new Segment(Vector2.Zero)); + + setState(PlacementState.Initial); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + path.Colour = colours.Yellow; } protected override bool OnMouseMove(MouseMoveEvent e) { switch (state) { - case PlacementState.Head: + case PlacementState.Initial: headMask.Position = e.MousePosition; return true; - case PlacementState.Tail: - tailMask.Position = ToLocalSpace(e.ScreenSpaceMousePosition); + case PlacementState.Body: + tailMask.Position = e.MousePosition; + cursor = tailMask.Position - headMask.Position; return true; } @@ -57,31 +74,84 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks { switch (state) { - case PlacementState.Head: - setState(PlacementState.Tail); - controlPoints.Add(Vector2.Zero); + case PlacementState.Initial: + beginCurve(); break; - case PlacementState.Tail: - controlPoints.Add(tailMask.Position - headMask.Position); - HitObject.Position = headMask.Position; - HitObject.ControlPoints = controlPoints.ToList(); - HitObject.CurveType = CurveType.Linear; - HitObject.Distance = Vector2.Distance(controlPoints.First(), controlPoints.Last()); - Finish(); + case PlacementState.Body: + switch (e.Button) + { + case MouseButton.Left: + segments.Last().ControlPoints.Add(cursor); + break; + } + break; } - return base.OnClick(e); + return true; + } + + protected override bool OnMouseUp(MouseUpEvent e) + { + if (state == PlacementState.Body && e.Button == MouseButton.Right) + endCurve(); + return base.OnMouseUp(e); + } + + protected override bool OnDoubleClick(DoubleClickEvent e) + { + segments.Add(new Segment(segments[segments.Count - 1].ControlPoints.Last())); + return true; + } + + private void beginCurve() + { + setState(PlacementState.Body); + } + + private void endCurve() + { + HitObject.Position = headMask.Position; + HitObject.ControlPoints = segments.SelectMany(s => s.ControlPoints).Concat(cursor.Yield()).ToList(); + HitObject.CurveType = HitObject.ControlPoints.Count > 2 ? CurveType.Bezier : CurveType.Linear; + HitObject.Distance = segments.Sum(s => s.Distance); + + Finish(); + } + + protected override void Update() + { + base.Update(); + + segments.ForEach(s => s.Calculate()); + + switch (state) + { + case PlacementState.Body: + path.Position = headMask.Position; + path.PathWidth = 10; + + path.ClearVertices(); + + for (int i = 0; i < segments.Count; i++) + { + var segmentPath = segments[i].Calculate(i == segments.Count - 1 ? (Vector2?)cursor : null); + segmentPath.ForEach(v => path.AddVertex(v)); + } + + path.OriginPosition = path.PositionInBoundingBox(Vector2.Zero); + break; + } } private void setState(PlacementState newState) { switch (newState) { - case PlacementState.Head: + case PlacementState.Initial: tailMask.Alpha = 0; break; - case PlacementState.Tail: + case PlacementState.Body: tailMask.Alpha = 1; break; } @@ -91,9 +161,52 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks private enum PlacementState { - Head, + Initial, Body, - Tail + } + + private class Segment + { + public float Distance { get; private set; } + + public readonly List ControlPoints = new List(); + public IApproximator Approximator = new LinearApproximator(); + + public Segment(Vector2 offset) + { + ControlPoints.Add(offset); + } + + public List Calculate(Vector2? cursor = null) + { + var allControlPoints = ControlPoints.ToList(); + if (cursor.HasValue) + allControlPoints.Add(cursor.Value); + + IApproximator approximator; + + switch (Approximator) + { + case null: + approximator = new LinearApproximator(); + break; + case LinearApproximator _ when allControlPoints.Count > 2: + case CircularArcApproximator _ when allControlPoints.Count > 3: + approximator = new BezierApproximator(); + break; + default: + approximator = Approximator; + break; + } + + Distance = 0; + + var points = approximator.Approximate(allControlPoints); + for (int i = 0; i < points.Count - 1; i++) + Distance += Vector2.Distance(points[i], points[i + 1]); + + return points; + } } } } From 2c4616dbb1b89a7aec5a0864a9a221c907e6f223 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 5 Oct 2018 15:59:37 +0900 Subject: [PATCH 198/333] Adjust visual display of the placement curve --- osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask.cs index 3ee63b1d7b..1308b5ae3a 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask.cs @@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks InternalChildren = new Drawable[] { - path = new Path { PathWidth = 5 }, + path = new SmoothPath { PathWidth = 3 }, headMask = new CirclePlacementMask(), tailMask = new CirclePlacementMask(), }; @@ -51,7 +51,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks [BackgroundDependencyLoader] private void load(OsuColour colours) { - path.Colour = colours.Yellow; + path.Colour = colours.YellowDark; } protected override bool OnMouseMove(MouseMoveEvent e) @@ -129,8 +129,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks { case PlacementState.Body: path.Position = headMask.Position; - path.PathWidth = 10; - path.ClearVertices(); for (int i = 0; i < segments.Count; i++) From 9540e53e32fed8e4e45bce4f00207b233aed08a3 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 5 Oct 2018 17:05:39 +0900 Subject: [PATCH 199/333] Initial controlpoint implementation --- .../Edit/Masks/SliderPlacementMask.cs | 19 ++-- .../Masks/SliderPlacementMask_ControlPoint.cs | 95 +++++++++++++++++++ 2 files changed, 106 insertions(+), 8 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask_ControlPoint.cs diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask.cs index 1308b5ae3a..ec5d09d530 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask.cs @@ -6,6 +6,7 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Lines; using osu.Framework.Input.Events; using osu.Game.Graphics; @@ -27,6 +28,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks private readonly Path path; private readonly List segments = new List(); + private readonly Container controlPointContainer; private Vector2 cursor; private PlacementState state; @@ -41,6 +43,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks path = new SmoothPath { PathWidth = 3 }, headMask = new CirclePlacementMask(), tailMask = new CirclePlacementMask(), + controlPointContainer = new Container { RelativeSizeAxes = Axes.Both } }; segments.Add(new Segment(Vector2.Zero)); @@ -64,6 +67,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks case PlacementState.Body: tailMask.Position = e.MousePosition; cursor = tailMask.Position - headMask.Position; + controlPointContainer.Last().NextPoint = e.MousePosition; return true; } @@ -88,6 +92,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks break; } + controlPointContainer.Add(new SliderControlPoint { Position = e.MousePosition }); + return true; } @@ -101,6 +107,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks protected override bool OnDoubleClick(DoubleClickEvent e) { segments.Add(new Segment(segments[segments.Count - 1].ControlPoints.Last())); + controlPointContainer.Last().SegmentSeparator = true; return true; } @@ -168,7 +175,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks public float Distance { get; private set; } public readonly List ControlPoints = new List(); - public IApproximator Approximator = new LinearApproximator(); public Segment(Vector2 offset) { @@ -183,17 +189,14 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks IApproximator approximator; - switch (Approximator) + switch (allControlPoints.Count) { - case null: + case 1: + case 2: approximator = new LinearApproximator(); break; - case LinearApproximator _ when allControlPoints.Count > 2: - case CircularArcApproximator _ when allControlPoints.Count > 3: - approximator = new BezierApproximator(); - break; default: - approximator = Approximator; + approximator = new BezierApproximator(); break; } diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask_ControlPoint.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask_ControlPoint.cs new file mode 100644 index 0000000000..d4aba5c1f5 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask_ControlPoint.cs @@ -0,0 +1,95 @@ +// 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.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Lines; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using OpenTK; + +namespace osu.Game.Rulesets.Osu.Edit.Masks +{ + public partial class SliderPlacementMask + { + /// + /// Todo: Move this out of SliderPlacementMask... + /// + private class SliderControlPoint : CompositeDrawable + { + private readonly Path path; + private readonly CircularContainer marker; + + private OsuColour colours; + + public SliderControlPoint() + { + Size = new Vector2(5); + Origin = Anchor.Centre; + + NextPoint = Position; + + InternalChildren = new Drawable[] + { + path = new SmoothPath + { + BypassAutoSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + PathWidth = 1, + }, + marker = new CircularContainer + { + RelativeSizeAxes = Axes.Both, + Masking = true, + Child = new Box { RelativeSizeAxes = Axes.Both } + } + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + this.colours = colours; + + marker.Colour = colours.YellowDark; + } + + public bool SegmentSeparator { set => marker.Colour = value ? colours.Red : colours.YellowDark; } + + private Vector2 nextPoint; + + public Vector2 NextPoint + { + set + { + nextPoint = value; + pathCache.Invalidate(); + } + } + + protected override void Update() + { + base.Update(); + + validatePath(); + } + + private Cached pathCache = new Cached(); + + private void validatePath() + { + if (pathCache.IsValid) + return; + + path.ClearVertices(); + path.AddVertex(nextPoint - Position); + path.AddVertex(Vector2.Zero); + path.OriginPosition = path.PositionInBoundingBox(Vector2.Zero); + + pathCache.Validate(); + } + } + } +} From a491fb42df113a8d7c58737d5d0c3cbfbcce2b16 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 10 Oct 2018 15:37:42 +0900 Subject: [PATCH 200/333] Set slider start time when head is placed --- osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask.cs index ec5d09d530..f48dfeacb4 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask.cs @@ -113,6 +113,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks private void beginCurve() { + HitObject.StartTime = EditorClock.CurrentTime; setState(PlacementState.Body); } From 8fa783b4c56272d1125c66c715d723bafab10fea Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 17 Oct 2018 18:20:39 +0900 Subject: [PATCH 201/333] Use begin/end placement methods --- osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask.cs index f48dfeacb4..71093927c2 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask.cs @@ -113,6 +113,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks private void beginCurve() { + BeginPlacement(); + HitObject.StartTime = EditorClock.CurrentTime; setState(PlacementState.Body); } @@ -124,7 +126,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks HitObject.CurveType = HitObject.ControlPoints.Count > 2 ? CurveType.Bezier : CurveType.Linear; HitObject.Distance = segments.Sum(s => s.Distance); - Finish(); + EndPlacement(); } protected override void Update() From 6310c183fa93ba604725a12fa31e5db0e2c19f92 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 24 Oct 2018 13:42:51 +0900 Subject: [PATCH 202/333] Modify slider position directly --- .../Edit/Masks/SliderPlacementMask.cs | 45 +++++++------------ ...SliderPlacementMask_CirclePlacementMask.cs | 10 ++--- 2 files changed, 20 insertions(+), 35 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask.cs index 71093927c2..f663104acb 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask.cs @@ -23,12 +23,10 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks { public new Slider HitObject => (Slider)base.HitObject; - private readonly CirclePlacementMask headMask; - private readonly CirclePlacementMask tailMask; - private readonly Path path; + private Path path; + private Container controlPointContainer; private readonly List segments = new List(); - private readonly Container controlPointContainer; private Vector2 cursor; private PlacementState state; @@ -37,24 +35,23 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks : base(new Slider()) { RelativeSizeAxes = Axes.Both; - - InternalChildren = new Drawable[] - { - path = new SmoothPath { PathWidth = 3 }, - headMask = new CirclePlacementMask(), - tailMask = new CirclePlacementMask(), - controlPointContainer = new Container { RelativeSizeAxes = Axes.Both } - }; - segments.Add(new Segment(Vector2.Zero)); - - setState(PlacementState.Initial); } [BackgroundDependencyLoader] private void load(OsuColour colours) { + InternalChildren = new Drawable[] + { + path = new SmoothPath { PathWidth = 3 }, + new CirclePlacementMask(HitObject.HeadCircle), + new CirclePlacementMask(HitObject.TailCircle), + controlPointContainer = new Container { RelativeSizeAxes = Axes.Both } + }; + path.Colour = colours.YellowDark; + + setState(PlacementState.Initial); } protected override bool OnMouseMove(MouseMoveEvent e) @@ -62,11 +59,10 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks switch (state) { case PlacementState.Initial: - headMask.Position = e.MousePosition; + HitObject.Position = e.MousePosition; return true; case PlacementState.Body: - tailMask.Position = e.MousePosition; - cursor = tailMask.Position - headMask.Position; + cursor = e.MousePosition - HitObject.Position; controlPointContainer.Last().NextPoint = e.MousePosition; return true; } @@ -121,7 +117,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks private void endCurve() { - HitObject.Position = headMask.Position; HitObject.ControlPoints = segments.SelectMany(s => s.ControlPoints).Concat(cursor.Yield()).ToList(); HitObject.CurveType = HitObject.ControlPoints.Count > 2 ? CurveType.Bezier : CurveType.Linear; HitObject.Distance = segments.Sum(s => s.Distance); @@ -138,7 +133,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks switch (state) { case PlacementState.Body: - path.Position = headMask.Position; + path.Position = HitObject.Position; path.ClearVertices(); for (int i = 0; i < segments.Count; i++) @@ -154,16 +149,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks private void setState(PlacementState newState) { - switch (newState) - { - case PlacementState.Initial: - tailMask.Alpha = 0; - break; - case PlacementState.Body: - tailMask.Alpha = 1; - break; - } - state = newState; } diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask_CirclePlacementMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask_CirclePlacementMask.cs index 4a3574c885..390ea50e0d 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask_CirclePlacementMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask_CirclePlacementMask.cs @@ -12,15 +12,15 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks { private class CirclePlacementMask : PlacementMask { - public new HitCircle HitObject => (HitCircle)base.HitObject; - - public CirclePlacementMask() - : base(new HitCircle()) + public CirclePlacementMask(HitCircle hitCircle) + : base(hitCircle) { Origin = Anchor.Centre; AutoSizeAxes = Axes.Both; - InternalChild = new HitCircleMask(HitObject); + InternalChild = new HitCircleMask(hitCircle); + + hitCircle.PositionChanged += _ => Position = hitCircle.StackedPosition; } protected override bool Handle(UIEvent e) => false; From 8b36d9b482352403a173f8cbf859be1ad0135a7f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 25 Oct 2018 14:24:50 +0900 Subject: [PATCH 203/333] Remove SliderCurve.Offset (unused) --- osu.Game/Rulesets/Objects/SliderCurve.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/osu.Game/Rulesets/Objects/SliderCurve.cs b/osu.Game/Rulesets/Objects/SliderCurve.cs index dfccdf68f2..124195b033 100644 --- a/osu.Game/Rulesets/Objects/SliderCurve.cs +++ b/osu.Game/Rulesets/Objects/SliderCurve.cs @@ -18,8 +18,6 @@ namespace osu.Game.Rulesets.Objects public CurveType CurveType = CurveType.PerfectCurve; - public Vector2 Offset; - private readonly List calculatedPath = new List(); private readonly List cumulativeLength = new List(); @@ -187,12 +185,12 @@ namespace osu.Game.Rulesets.Objects int i = 0; 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)); } /// @@ -207,7 +205,7 @@ namespace osu.Game.Rulesets.Objects Calculate(); double d = progressToDistance(progress); - return interpolateVertices(indexOfDistance(d), d) + Offset; + return interpolateVertices(indexOfDistance(d), d); } } } From b28f44087d614ecfca8b17fe9498d6fb9b797327 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 25 Oct 2018 19:34:35 +0900 Subject: [PATCH 204/333] Bring up to date with further placement changes --- .../TestCaseSliderPlacementMask.cs | 19 ++++ .../Slider/Components/SliderControlPoint.cs | 95 +++++++++++++++++++ .../Masks/{ => Slider}/SliderPlacementMask.cs | 14 +-- .../SliderMasks/Components/SliderBodyPiece.cs | 17 +++- ...SliderPlacementMask_CirclePlacementMask.cs | 29 ------ .../Masks/SliderPlacementMask_ControlPoint.cs | 95 ------------------- .../Edit/Masks/SliderSelectionMask.cs | 67 ------------- ...SliderSelectionMask_CircleSelectionMask.cs | 64 ------------- .../Edit/SliderCompositionTool.cs | 2 +- .../Visual/TestCaseHitObjectComposer.cs | 2 - 10 files changed, 134 insertions(+), 270 deletions(-) create mode 100644 osu.Game.Rulesets.Osu.Tests/TestCaseSliderPlacementMask.cs create mode 100644 osu.Game.Rulesets.Osu/Edit/Masks/Slider/Components/SliderControlPoint.cs rename osu.Game.Rulesets.Osu/Edit/Masks/{ => Slider}/SliderPlacementMask.cs (93%) delete mode 100644 osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask_CirclePlacementMask.cs delete mode 100644 osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask_ControlPoint.cs delete mode 100644 osu.Game.Rulesets.Osu/Edit/Masks/SliderSelectionMask.cs delete mode 100644 osu.Game.Rulesets.Osu/Edit/Masks/SliderSelectionMask_CircleSelectionMask.cs diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderPlacementMask.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSliderPlacementMask.cs new file mode 100644 index 0000000000..ad75779d80 --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSliderPlacementMask.cs @@ -0,0 +1,19 @@ +// 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.Objects; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Osu.Edit.Masks.Slider; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Tests.Visual; + +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(); + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/Slider/Components/SliderControlPoint.cs b/osu.Game.Rulesets.Osu/Edit/Masks/Slider/Components/SliderControlPoint.cs new file mode 100644 index 0000000000..47bae20c30 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/Masks/Slider/Components/SliderControlPoint.cs @@ -0,0 +1,95 @@ +// 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.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Lines; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using OpenTK; + +namespace osu.Game.Rulesets.Osu.Edit.Masks.Slider.Components +{ + /// + /// Todo: Move this out of SliderPlacementMask... + /// + public class SliderControlPoint : CompositeDrawable + { + private readonly Path path; + private readonly CircularContainer marker; + + private OsuColour colours; + + public SliderControlPoint() + { + Size = new Vector2(5); + Origin = Anchor.Centre; + + NextPoint = Position; + + InternalChildren = new Drawable[] + { + path = new SmoothPath + { + BypassAutoSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + PathWidth = 1, + }, + marker = new CircularContainer + { + RelativeSizeAxes = Axes.Both, + Masking = true, + Child = new Box { RelativeSizeAxes = Axes.Both } + } + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + this.colours = colours; + + marker.Colour = colours.YellowDark; + } + + public bool SegmentSeparator + { + set => marker.Colour = value ? colours.Red : colours.YellowDark; + } + + private Vector2 nextPoint; + + public Vector2 NextPoint + { + set + { + nextPoint = value; + pathCache.Invalidate(); + } + } + + protected override void Update() + { + base.Update(); + + validatePath(); + } + + private Cached pathCache = new Cached(); + + private void validatePath() + { + if (pathCache.IsValid) + return; + + path.ClearVertices(); + path.AddVertex(nextPoint - Position); + path.AddVertex(Vector2.Zero); + path.OriginPosition = path.PositionInBoundingBox(Vector2.Zero); + + pathCache.Validate(); + } + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/Slider/SliderPlacementMask.cs similarity index 93% rename from osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask.cs rename to osu.Game.Rulesets.Osu/Edit/Masks/Slider/SliderPlacementMask.cs index f663104acb..f23ab5b4dd 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/Slider/SliderPlacementMask.cs @@ -13,15 +13,15 @@ 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.Objects; +using osu.Game.Rulesets.Osu.Edit.Masks.Slider.Components; using OpenTK; using OpenTK.Input; -namespace osu.Game.Rulesets.Osu.Edit.Masks +namespace osu.Game.Rulesets.Osu.Edit.Masks.Slider { - public partial class SliderPlacementMask : PlacementMask + public class SliderPlacementMask : PlacementMask { - public new Slider HitObject => (Slider)base.HitObject; + public new Objects.Slider HitObject => (Objects.Slider)base.HitObject; private Path path; private Container controlPointContainer; @@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks private PlacementState state; public SliderPlacementMask() - : base(new Slider()) + : base(new Objects.Slider()) { RelativeSizeAxes = Axes.Both; segments.Add(new Segment(Vector2.Zero)); @@ -44,8 +44,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks InternalChildren = new Drawable[] { path = new SmoothPath { PathWidth = 3 }, - new CirclePlacementMask(HitObject.HeadCircle), - new CirclePlacementMask(HitObject.TailCircle), + new SliderCirclePiece(HitObject, SliderPosition.Start), + new SliderCirclePiece(HitObject, SliderPosition.End), controlPointContainer = new Container { RelativeSizeAxes = Axes.Both } }; diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderBodyPiece.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderBodyPiece.cs index 3123a4fcea..141459a0d8 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderBodyPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderBodyPiece.cs @@ -1,11 +1,13 @@ // 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.Containers; using osu.Game.Graphics; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; +using OpenTK; using OpenTK.Graphics; namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components @@ -13,12 +15,13 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components public class SliderBodyPiece : CompositeDrawable { private readonly Slider slider; - private readonly SnakingSliderBody body; + private readonly ManualSliderBody body; public SliderBodyPiece(Slider slider) { this.slider = slider; - InternalChild = body = new SnakingSliderBody(slider) + + InternalChild = body = new ManualSliderBody { AccentColour = Color4.Transparent, PathWidth = slider.Scale * 64 @@ -41,11 +44,15 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components { base.Update(); + slider.Curve.Calculate(); + + var vertices = new List(); + slider.Curve.GetPathToProgress(vertices, 0, 1); + + body.SetVertices(vertices); + Size = body.Size; OriginPosition = body.PathOffset; - - // Need to cause one update - body.UpdateProgress(0); } } } diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask_CirclePlacementMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask_CirclePlacementMask.cs deleted file mode 100644 index 390ea50e0d..0000000000 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask_CirclePlacementMask.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.Framework.Graphics; -using osu.Framework.Input.Events; -using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Osu.Objects; - -namespace osu.Game.Rulesets.Osu.Edit.Masks -{ - public partial class SliderPlacementMask - { - private class CirclePlacementMask : PlacementMask - { - public CirclePlacementMask(HitCircle hitCircle) - : base(hitCircle) - { - Origin = Anchor.Centre; - AutoSizeAxes = Axes.Both; - - InternalChild = new HitCircleMask(hitCircle); - - hitCircle.PositionChanged += _ => Position = hitCircle.StackedPosition; - } - - protected override bool Handle(UIEvent e) => false; - } - } -} diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask_ControlPoint.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask_ControlPoint.cs deleted file mode 100644 index d4aba5c1f5..0000000000 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderPlacementMask_ControlPoint.cs +++ /dev/null @@ -1,95 +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.Caching; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Lines; -using osu.Framework.Graphics.Shapes; -using osu.Game.Graphics; -using OpenTK; - -namespace osu.Game.Rulesets.Osu.Edit.Masks -{ - public partial class SliderPlacementMask - { - /// - /// Todo: Move this out of SliderPlacementMask... - /// - private class SliderControlPoint : CompositeDrawable - { - private readonly Path path; - private readonly CircularContainer marker; - - private OsuColour colours; - - public SliderControlPoint() - { - Size = new Vector2(5); - Origin = Anchor.Centre; - - NextPoint = Position; - - InternalChildren = new Drawable[] - { - path = new SmoothPath - { - BypassAutoSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - PathWidth = 1, - }, - marker = new CircularContainer - { - RelativeSizeAxes = Axes.Both, - Masking = true, - Child = new Box { RelativeSizeAxes = Axes.Both } - } - }; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - this.colours = colours; - - marker.Colour = colours.YellowDark; - } - - public bool SegmentSeparator { set => marker.Colour = value ? colours.Red : colours.YellowDark; } - - private Vector2 nextPoint; - - public Vector2 NextPoint - { - set - { - nextPoint = value; - pathCache.Invalidate(); - } - } - - protected override void Update() - { - base.Update(); - - validatePath(); - } - - private Cached pathCache = new Cached(); - - private void validatePath() - { - if (pathCache.IsValid) - return; - - path.ClearVertices(); - path.AddVertex(nextPoint - Position); - path.AddVertex(Vector2.Zero); - path.OriginPosition = path.PositionInBoundingBox(Vector2.Zero); - - pathCache.Validate(); - } - } - } -} diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderSelectionMask.cs deleted file mode 100644 index 46c807f4b3..0000000000 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderSelectionMask.cs +++ /dev/null @@ -1,67 +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.Graphics; -using osu.Framework.Graphics.Primitives; -using osu.Game.Graphics; -using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Osu.Objects; -using osu.Game.Rulesets.Osu.Objects.Drawables; -using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; -using OpenTK; -using OpenTK.Graphics; - -namespace osu.Game.Rulesets.Osu.Edit.Masks -{ - public partial class SliderSelectionMask : SelectionMask - { - private readonly SliderBody body; - private readonly DrawableSlider slider; - - public SliderSelectionMask(DrawableSlider slider) - : base(slider) - { - this.slider = slider; - - Position = slider.Position; - - var sliderObject = (Slider)slider.HitObject; - - InternalChildren = new Drawable[] - { - body = new SliderBody(sliderObject) - { - AccentColour = Color4.Transparent, - PathWidth = sliderObject.Scale * 64 - }, - new CircleSelectionMask(slider.HeadCircle, slider), - new CircleSelectionMask(slider.TailCircle, slider), - }; - - sliderObject.PositionChanged += _ => Position = slider.Position; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - body.BorderColour = colours.Yellow; - } - - protected override void Update() - { - base.Update(); - - Size = slider.Size; - OriginPosition = slider.OriginPosition; - - // Need to cause one update - body.UpdateProgress(0); - } - - public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => body.ReceivePositionalInputAt(screenSpacePos); - - public override Vector2 SelectionPoint => ToScreenSpace(OriginPosition); - public override Quad SelectionQuad => body.PathDrawQuad; - } -} diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderSelectionMask_CircleSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderSelectionMask_CircleSelectionMask.cs deleted file mode 100644 index f4d4749343..0000000000 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderSelectionMask_CircleSelectionMask.cs +++ /dev/null @@ -1,64 +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.Graphics; -using osu.Game.Graphics; -using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Osu.Objects; -using osu.Game.Rulesets.Osu.Objects.Drawables; -using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; -using OpenTK; - -namespace osu.Game.Rulesets.Osu.Edit.Masks -{ - public partial class SliderSelectionMask - { - private class CircleSelectionMask : SelectionMask - { - public CircleSelectionMask(DrawableHitCircle sliderHead, DrawableSlider slider) - : this(sliderHead, Vector2.Zero, slider) - { - } - - public CircleSelectionMask(DrawableSliderTail sliderTail, DrawableSlider slider) - : this(sliderTail, ((Slider)slider.HitObject).Curve.PositionAt(1), slider) - { - } - - private readonly DrawableOsuHitObject hitObject; - - private CircleSelectionMask(DrawableOsuHitObject hitObject, Vector2 position, DrawableSlider slider) - : base(hitObject) - { - this.hitObject = hitObject; - - Origin = Anchor.Centre; - - Position = position; - Size = slider.HeadCircle.Size; - Scale = slider.HeadCircle.Scale; - - AddInternal(new RingPiece()); - - Select(); - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - Colour = colours.Yellow; - } - - protected override void Update() - { - base.Update(); - - RelativeAnchorPosition = hitObject.RelativeAnchorPosition; - } - - // 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; - } - } -} diff --git a/osu.Game.Rulesets.Osu/Edit/SliderCompositionTool.cs b/osu.Game.Rulesets.Osu/Edit/SliderCompositionTool.cs index f7cdd76655..30ebc51179 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; +using osu.Game.Rulesets.Osu.Edit.Masks.Slider; 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 196cb9320a..61647ffdc5 100644 --- a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs +++ b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs @@ -37,8 +37,6 @@ namespace osu.Game.Tests.Visual typeof(HitCirclePiece), typeof(HitCircleSelectionMask), typeof(HitCirclePlacementMask), - typeof(SliderSelectionMask), - typeof(SliderPlacementMask) }; private HitObjectComposer composer; From e964a555d0bdf4a4ad1f7f5a7553c88ef8caa00b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 25 Oct 2018 19:34:49 +0900 Subject: [PATCH 205/333] Fix DummyWorkingBeatmap having unrealistic defaults --- osu.Game/Beatmaps/DummyWorkingBeatmap.cs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/osu.Game/Beatmaps/DummyWorkingBeatmap.cs b/osu.Game/Beatmaps/DummyWorkingBeatmap.cs index 25a76b52a7..5c129f76ec 100644 --- a/osu.Game/Beatmaps/DummyWorkingBeatmap.cs +++ b/osu.Game/Beatmaps/DummyWorkingBeatmap.cs @@ -26,15 +26,7 @@ namespace osu.Game.Beatmaps Title = "no beatmaps available!" }, BeatmapSet = new BeatmapSetInfo(), - BaseDifficulty = new BeatmapDifficulty - { - DrainRate = 0, - CircleSize = 0, - OverallDifficulty = 0, - ApproachRate = 0, - SliderMultiplier = 0, - SliderTickRate = 0, - }, + BaseDifficulty = new BeatmapDifficulty(), Ruleset = new DummyRulesetInfo() }) { From 4fa511043e8f708ddce9df6a1e18b62096f81de2 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 25 Oct 2018 19:38:00 +0900 Subject: [PATCH 206/333] Use common body piece --- .../Edit/Masks/Slider/SliderPlacementMask.cs | 27 +++++-------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/Slider/SliderPlacementMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/Slider/SliderPlacementMask.cs index f23ab5b4dd..94ac8208f4 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/Slider/SliderPlacementMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/Slider/SliderPlacementMask.cs @@ -7,7 +7,6 @@ using osu.Framework.Allocation; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Lines; using osu.Framework.Input.Events; using osu.Game.Graphics; using osu.Game.Rulesets.Edit; @@ -23,7 +22,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.Slider { public new Objects.Slider HitObject => (Objects.Slider)base.HitObject; - private Path path; private Container controlPointContainer; private readonly List segments = new List(); @@ -43,14 +41,12 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.Slider { InternalChildren = new Drawable[] { - path = new SmoothPath { PathWidth = 3 }, + new BodyPiece(HitObject), new SliderCirclePiece(HitObject, SliderPosition.Start), new SliderCirclePiece(HitObject, SliderPosition.End), controlPointContainer = new Container { RelativeSizeAxes = Axes.Both } }; - path.Colour = colours.YellowDark; - setState(PlacementState.Initial); } @@ -128,23 +124,12 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.Slider { base.Update(); - segments.ForEach(s => s.Calculate()); + for (int i = 0; i < segments.Count; i++) + segments[i].Calculate(i == segments.Count - 1 ? (Vector2?)cursor : null); - switch (state) - { - case PlacementState.Body: - path.Position = HitObject.Position; - path.ClearVertices(); - - for (int i = 0; i < segments.Count; i++) - { - var segmentPath = segments[i].Calculate(i == segments.Count - 1 ? (Vector2?)cursor : null); - segmentPath.ForEach(v => path.AddVertex(v)); - } - - path.OriginPosition = path.PositionInBoundingBox(Vector2.Zero); - break; - } + HitObject.ControlPoints = segments.SelectMany(s => s.ControlPoints).Concat(cursor.Yield()).ToList(); + HitObject.CurveType = HitObject.ControlPoints.Count > 2 ? CurveType.Bezier : CurveType.Linear; + HitObject.Distance = segments.Sum(s => s.Distance); } private void setState(PlacementState newState) From a9f1484e8b2f1a413283893e1da578db592276b2 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 26 Oct 2018 14:18:48 +0900 Subject: [PATCH 207/333] Fix some post-rebase issues --- .../TestCaseSliderPlacementMask.cs | 2 +- .../Components/SliderControlPoint.cs | 2 +- .../SliderPlacementMask.cs | 40 +++--- .../Edit/SliderCompositionTool.cs | 2 +- .../Rulesets/Objects/BezierApproximator.cs | 125 +++++++++--------- .../Rulesets/Objects/CatmullApproximator.cs | 20 ++- .../Objects/CircularArcApproximator.cs | 14 +- osu.Game/Rulesets/Objects/IApproximator.cs | 13 -- .../Rulesets/Objects/LinearApproximator.cs | 20 ++- osu.Game/Rulesets/Objects/SliderCurve.cs | 18 ++- 10 files changed, 138 insertions(+), 118 deletions(-) rename osu.Game.Rulesets.Osu/Edit/Masks/{Slider => SliderMasks}/Components/SliderControlPoint.cs (97%) rename osu.Game.Rulesets.Osu/Edit/Masks/{Slider => SliderMasks}/SliderPlacementMask.cs (79%) delete mode 100644 osu.Game/Rulesets/Objects/IApproximator.cs diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderPlacementMask.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSliderPlacementMask.cs index ad75779d80..889ea0c311 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderPlacementMask.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSliderPlacementMask.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.Slider; +using osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks; 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/Slider/Components/SliderControlPoint.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderControlPoint.cs similarity index 97% rename from osu.Game.Rulesets.Osu/Edit/Masks/Slider/Components/SliderControlPoint.cs rename to osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderControlPoint.cs index 47bae20c30..7d2f94a82d 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/Slider/Components/SliderControlPoint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderControlPoint.cs @@ -10,7 +10,7 @@ using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using OpenTK; -namespace osu.Game.Rulesets.Osu.Edit.Masks.Slider.Components +namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components { /// /// Todo: Move this out of SliderPlacementMask... diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/Slider/SliderPlacementMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPlacementMask.cs similarity index 79% rename from osu.Game.Rulesets.Osu/Edit/Masks/Slider/SliderPlacementMask.cs rename to osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPlacementMask.cs index 94ac8208f4..2ee996fb00 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/Slider/SliderPlacementMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPlacementMask.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.Allocation; @@ -12,11 +13,11 @@ 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.Masks.Slider.Components; +using osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components; using OpenTK; using OpenTK.Input; -namespace osu.Game.Rulesets.Osu.Edit.Masks.Slider +namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks { public class SliderPlacementMask : PlacementMask { @@ -41,7 +42,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.Slider { InternalChildren = new Drawable[] { - new BodyPiece(HitObject), + new SliderBodyPiece(HitObject), new SliderCirclePiece(HitObject, SliderPosition.Start), new SliderCirclePiece(HitObject, SliderPosition.End), controlPointContainer = new Container { RelativeSizeAxes = Axes.Both } @@ -113,8 +114,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.Slider private void endCurve() { - HitObject.ControlPoints = segments.SelectMany(s => s.ControlPoints).Concat(cursor.Yield()).ToList(); - HitObject.CurveType = HitObject.ControlPoints.Count > 2 ? CurveType.Bezier : CurveType.Linear; + HitObject.ControlPoints = segments.SelectMany(s => s.ControlPoints).Concat(cursor.Yield()).ToArray(); + HitObject.CurveType = HitObject.ControlPoints.Length > 2 ? CurveType.Bezier : CurveType.Linear; HitObject.Distance = segments.Sum(s => s.Distance); EndPlacement(); @@ -127,8 +128,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.Slider 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()).ToList(); - HitObject.CurveType = HitObject.ControlPoints.Count > 2 ? CurveType.Bezier : CurveType.Linear; + HitObject.ControlPoints = segments.SelectMany(s => s.ControlPoints).Concat(cursor.Yield()).ToArray(); + HitObject.CurveType = HitObject.ControlPoints.Length > 2 ? CurveType.Bezier : CurveType.Linear; HitObject.Distance = segments.Sum(s => s.Distance); } @@ -154,32 +155,31 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.Slider ControlPoints.Add(offset); } - public List Calculate(Vector2? cursor = null) + public void Calculate(Vector2? cursor = null) { - var allControlPoints = ControlPoints.ToList(); + 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.Add(cursor.Value); + allControlPoints[allControlPoints.Length - 1] = cursor.Value; - IApproximator approximator; + List result; - switch (allControlPoints.Count) + switch (allControlPoints.Length) { case 1: case 2: - approximator = new LinearApproximator(); + result = new LinearApproximator(allControlPoints).CreateLinear(); break; default: - approximator = new BezierApproximator(); + result = new BezierApproximator(allControlPoints).CreateBezier(); break; } Distance = 0; - - var points = approximator.Approximate(allControlPoints); - for (int i = 0; i < points.Count - 1; i++) - Distance += Vector2.Distance(points[i], points[i + 1]); - - return points; + for (int i = 0; i < result.Count - 1; i++) + Distance += Vector2.Distance(result[i], result[i + 1]); } } } diff --git a/osu.Game.Rulesets.Osu/Edit/SliderCompositionTool.cs b/osu.Game.Rulesets.Osu/Edit/SliderCompositionTool.cs index 30ebc51179..fd0430ce4c 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.Slider; +using osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks; using osu.Game.Rulesets.Osu.Objects; namespace osu.Game.Rulesets.Osu.Edit diff --git a/osu.Game/Rulesets/Objects/BezierApproximator.cs b/osu.Game/Rulesets/Objects/BezierApproximator.cs index 011526339e..a1803e32f7 100644 --- a/osu.Game/Rulesets/Objects/BezierApproximator.cs +++ b/osu.Game/Rulesets/Objects/BezierApproximator.cs @@ -1,77 +1,29 @@ // 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 OpenTK; namespace osu.Game.Rulesets.Objects { - public class BezierApproximator : IApproximator + public readonly ref struct BezierApproximator { + private readonly int count; + private readonly ReadOnlySpan controlPoints; + private readonly Vector2[] subdivisionBuffer1; + private readonly Vector2[] subdivisionBuffer2; + private const float tolerance = 0.25f; private const float tolerance_sq = tolerance * tolerance; - private int count; - private Vector2[] subdivisionBuffer1; - private Vector2[] subdivisionBuffer2; - - /// - /// Creates a piecewise-linear approximation of a bezier curve, by adaptively repeatedly subdividing - /// the control points until their approximation error vanishes below a given threshold. - /// - /// A list of vectors representing the piecewise-linear approximation. - public List Approximate(List controlPoints) + public BezierApproximator(ReadOnlySpan controlPoints) { - count = controlPoints.Count; + this.controlPoints = controlPoints; + count = controlPoints.Length; + subdivisionBuffer1 = new Vector2[count]; subdivisionBuffer2 = new Vector2[count * 2 - 1]; - - List output = new List(); - - if (count == 0) - return output; - - Stack toFlatten = new Stack(); - Stack freeBuffers = new Stack(); - - // "toFlatten" contains all the curves which are not yet approximated well enough. - // We use a stack to emulate recursion without the risk of running into a stack overflow. - // (More specifically, we iteratively and adaptively refine our curve with a - // Depth-first search - // over the tree resulting from the subdivisions we make.) - toFlatten.Push(controlPoints.ToArray()); - - Vector2[] leftChild = subdivisionBuffer2; - - while (toFlatten.Count > 0) - { - Vector2[] parent = toFlatten.Pop(); - if (isFlatEnough(parent)) - { - // If the control points we currently operate on are sufficiently "flat", we use - // an extension to De Casteljau's algorithm to obtain a piecewise-linear approximation - // of the bezier curve represented by our control points, consisting of the same amount - // of points as there are control points. - approximate(parent, output); - freeBuffers.Push(parent); - continue; - } - - // If we do not yet have a sufficiently "flat" (in other words, detailed) approximation we keep - // subdividing the curve we are currently operating on. - Vector2[] rightChild = freeBuffers.Count > 0 ? freeBuffers.Pop() : new Vector2[count]; - subdivide(parent, leftChild, rightChild); - - // We re-use the buffer of the parent for one of the children, so that we save one allocation per iteration. - for (int i = 0; i < count; ++i) - parent[i] = leftChild[i]; - - toFlatten.Push(rightChild); - toFlatten.Push(parent); - } - - output.Add(controlPoints[count - 1]); - return output; } /// @@ -140,5 +92,60 @@ namespace osu.Game.Rulesets.Objects output.Add(p); } } + + /// + /// Creates a piecewise-linear approximation of a bezier curve, by adaptively repeatedly subdividing + /// the control points until their approximation error vanishes below a given threshold. + /// + /// A list of vectors representing the piecewise-linear approximation. + public List CreateBezier() + { + List output = new List(); + + if (count == 0) + return output; + + Stack toFlatten = new Stack(); + Stack freeBuffers = new Stack(); + + // "toFlatten" contains all the curves which are not yet approximated well enough. + // We use a stack to emulate recursion without the risk of running into a stack overflow. + // (More specifically, we iteratively and adaptively refine our curve with a + // Depth-first search + // over the tree resulting from the subdivisions we make.) + toFlatten.Push(controlPoints.ToArray()); + + Vector2[] leftChild = subdivisionBuffer2; + + while (toFlatten.Count > 0) + { + Vector2[] parent = toFlatten.Pop(); + if (isFlatEnough(parent)) + { + // If the control points we currently operate on are sufficiently "flat", we use + // an extension to De Casteljau's algorithm to obtain a piecewise-linear approximation + // of the bezier curve represented by our control points, consisting of the same amount + // of points as there are control points. + approximate(parent, output); + freeBuffers.Push(parent); + continue; + } + + // If we do not yet have a sufficiently "flat" (in other words, detailed) approximation we keep + // subdividing the curve we are currently operating on. + Vector2[] rightChild = freeBuffers.Count > 0 ? freeBuffers.Pop() : new Vector2[count]; + subdivide(parent, leftChild, rightChild); + + // We re-use the buffer of the parent for one of the children, so that we save one allocation per iteration. + for (int i = 0; i < count; ++i) + parent[i] = leftChild[i]; + + toFlatten.Push(rightChild); + toFlatten.Push(parent); + } + + output.Add(controlPoints[count - 1]); + return output; + } } } diff --git a/osu.Game/Rulesets/Objects/CatmullApproximator.cs b/osu.Game/Rulesets/Objects/CatmullApproximator.cs index 624f5fc9ab..78f8e471f3 100644 --- a/osu.Game/Rulesets/Objects/CatmullApproximator.cs +++ b/osu.Game/Rulesets/Objects/CatmullApproximator.cs @@ -1,32 +1,40 @@ // 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 OpenTK; namespace osu.Game.Rulesets.Objects { - public class CatmullApproximator : IApproximator + public readonly ref struct CatmullApproximator { /// /// The amount of pieces to calculate for each controlpoint quadruplet. /// private const int detail = 50; + private readonly ReadOnlySpan controlPoints; + + public CatmullApproximator(ReadOnlySpan controlPoints) + { + this.controlPoints = controlPoints; + } + /// /// Creates a piecewise-linear approximation of a Catmull-Rom spline. /// /// A list of vectors representing the piecewise-linear approximation. - public List Approximate(List controlPoints) + public List CreateCatmull() { - var result = new List(); + var result = new List((controlPoints.Length - 1) * detail * 2); - for (int i = 0; i < controlPoints.Count - 1; i++) + for (int i = 0; i < controlPoints.Length - 1; i++) { var v1 = i > 0 ? controlPoints[i - 1] : controlPoints[i]; var v2 = controlPoints[i]; - var v3 = i < controlPoints.Count - 1 ? controlPoints[i + 1] : v2 + v2 - v1; - var v4 = i < controlPoints.Count - 2 ? controlPoints[i + 2] : v3 + v3 - v2; + var v3 = i < controlPoints.Length - 1 ? controlPoints[i + 1] : v2 + v2 - v1; + var v4 = i < controlPoints.Length - 2 ? controlPoints[i + 2] : v3 + v3 - v2; for (int c = 0; c < detail; c++) { diff --git a/osu.Game/Rulesets/Objects/CircularArcApproximator.cs b/osu.Game/Rulesets/Objects/CircularArcApproximator.cs index 201c6296ba..28d7442aaf 100644 --- a/osu.Game/Rulesets/Objects/CircularArcApproximator.cs +++ b/osu.Game/Rulesets/Objects/CircularArcApproximator.cs @@ -8,19 +8,23 @@ using OpenTK; namespace osu.Game.Rulesets.Objects { - public class CircularArcApproximator : IApproximator + public readonly ref struct CircularArcApproximator { private const float tolerance = 0.1f; + private readonly ReadOnlySpan controlPoints; + + public CircularArcApproximator(ReadOnlySpan controlPoints) + { + this.controlPoints = controlPoints; + } + /// /// Creates a piecewise-linear approximation of a circular arc curve. /// /// A list of vectors representing the piecewise-linear approximation. - public List Approximate(List controlPoints) + public List CreateArc() { - if (controlPoints.Count != 3) - throw new ArgumentException("Must have 3 control points to perform circular arc approximation.", nameof(controlPoints)); - Vector2 a = controlPoints[0]; Vector2 b = controlPoints[1]; Vector2 c = controlPoints[2]; diff --git a/osu.Game/Rulesets/Objects/IApproximator.cs b/osu.Game/Rulesets/Objects/IApproximator.cs deleted file mode 100644 index f865172bb4..0000000000 --- a/osu.Game/Rulesets/Objects/IApproximator.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 System.Collections.Generic; -using OpenTK; - -namespace osu.Game.Rulesets.Objects -{ - public interface IApproximator - { - List Approximate(List controlPoints); - } -} diff --git a/osu.Game/Rulesets/Objects/LinearApproximator.cs b/osu.Game/Rulesets/Objects/LinearApproximator.cs index a2c2dd5a93..c513d40ad6 100644 --- a/osu.Game/Rulesets/Objects/LinearApproximator.cs +++ b/osu.Game/Rulesets/Objects/LinearApproximator.cs @@ -1,13 +1,29 @@ // 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 OpenTK; namespace osu.Game.Rulesets.Objects { - public class LinearApproximator : IApproximator + public readonly ref struct LinearApproximator { - public List Approximate(List controlpoints) => controlpoints; + private readonly ReadOnlySpan controlPoints; + + public LinearApproximator(ReadOnlySpan controlPoints) + { + this.controlPoints = controlPoints; + } + + public List CreateLinear() + { + var result = new List(controlPoints.Length); + + foreach (var c in controlPoints) + result.Add(c); + + return result; + } } } diff --git a/osu.Game/Rulesets/Objects/SliderCurve.cs b/osu.Game/Rulesets/Objects/SliderCurve.cs index 124195b033..e3c9c53a2b 100644 --- a/osu.Game/Rulesets/Objects/SliderCurve.cs +++ b/osu.Game/Rulesets/Objects/SliderCurve.cs @@ -14,10 +14,12 @@ namespace osu.Game.Rulesets.Objects { public double Distance; - public Vector2[] ControlPoints; + public Vector2[] ControlPoints = Array.Empty(); public CurveType CurveType = CurveType.PerfectCurve; + public Vector2 Offset; + private readonly List calculatedPath = new List(); private readonly List cumulativeLength = new List(); @@ -26,11 +28,7 @@ namespace osu.Game.Rulesets.Objects switch (CurveType) { case CurveType.Linear: - var result = new List(subControlPoints.Length); - foreach (var c in subControlPoints) - result.Add(c); - - return result; + return new LinearApproximator(subControlPoints).CreateLinear(); case CurveType.PerfectCurve: //we can only use CircularArc iff we have exactly three control points and no dissection. if (ControlPoints.Length != 3 || subControlPoints.Length != 3) @@ -185,12 +183,12 @@ namespace osu.Game.Rulesets.Objects int i = 0; for (; i < calculatedPath.Count && cumulativeLength[i] < d0; ++i) { } - path.Add(interpolateVertices(i, d0)); + path.Add(interpolateVertices(i, d0) + Offset); for (; i < calculatedPath.Count && cumulativeLength[i] <= d1; ++i) - path.Add(calculatedPath[i]); + path.Add(calculatedPath[i] + Offset); - path.Add(interpolateVertices(i, d1)); + path.Add(interpolateVertices(i, d1) + Offset); } /// @@ -205,7 +203,7 @@ namespace osu.Game.Rulesets.Objects Calculate(); double d = progressToDistance(progress); - return interpolateVertices(indexOfDistance(d), d); + return interpolateVertices(indexOfDistance(d), d) + Offset; } } } From 660cd247502dd0663f5e220f2cf6ac74b3004e70 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 26 Oct 2018 15:33:21 +0900 Subject: [PATCH 208/333] Make sliders respond to scale changes --- .../Edit/Masks/SliderMasks/Components/SliderBodyPiece.cs | 1 + .../Edit/Masks/SliderMasks/Components/SliderControlPoint.cs | 3 --- osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs | 5 +++++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderBodyPiece.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderBodyPiece.cs index 141459a0d8..78ef42872e 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderBodyPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderBodyPiece.cs @@ -28,6 +28,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components }; slider.PositionChanged += _ => updatePosition(); + slider.ScaleChanged += _ => body.PathWidth = slider.Scale * 64; } [BackgroundDependencyLoader] diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderControlPoint.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderControlPoint.cs index 7d2f94a82d..e9693e7a3c 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderControlPoint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderControlPoint.cs @@ -12,9 +12,6 @@ using OpenTK; namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components { - /// - /// Todo: Move this out of SliderPlacementMask... - /// public class SliderControlPoint : CompositeDrawable { private readonly Path path; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index 16bd522c1d..7f708ec182 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -85,6 +85,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables } HitObject.PositionChanged += _ => Position = HitObject.StackedPosition; + HitObject.ScaleChanged += _ => + { + Body.PathWidth = HitObject.Scale * 64; + Ball.Scale = new Vector2(HitObject.Scale); + }; } public override Color4 AccentColour From b0f5ace0e88b07ee34bbb2ed2020fa0e7ce64b33 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 29 Oct 2018 14:07:06 +0900 Subject: [PATCH 209/333] Implement slider control point visualisation --- .../TestCaseSliderSelectionMask.cs | 13 +++ .../Components/ControlPointPiece.cs | 90 +++++++++++++++++++ .../Components/ControlPointVisualiser.cs | 34 +++++++ .../Masks/SliderMasks/SliderSelectionMask.cs | 1 + osu.Game.Rulesets.Osu/Objects/Slider.cs | 13 ++- 5 files changed, 149 insertions(+), 2 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/ControlPointPiece.cs create mode 100644 osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/ControlPointVisualiser.cs diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionMask.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionMask.cs index 5e68d5cdc9..a73cb69536 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionMask.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionMask.cs @@ -1,11 +1,14 @@ // 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.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.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Tests.Visual; @@ -15,6 +18,16 @@ namespace osu.Game.Rulesets.Osu.Tests { public class TestCaseSliderSelectionMask : HitObjectSelectionMaskTestCase { + public override IReadOnlyList RequiredTypes => new Type[] + { + typeof(SliderSelectionMask), + typeof(SliderCircleSelectionMask), + typeof(SliderBodyPiece), + typeof(SliderCircle), + typeof(ControlPointVisualiser), + typeof(ControlPointPiece) + }; + private readonly DrawableSlider drawableObject; public TestCaseSliderSelectionMask() diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/ControlPointPiece.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/ControlPointPiece.cs new file mode 100644 index 0000000000..5a3c5d5aaf --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/ControlPointPiece.cs @@ -0,0 +1,90 @@ +// 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; +using osu.Framework.Graphics.Lines; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.Events; +using osu.Game.Graphics; +using osu.Game.Rulesets.Osu.Objects; +using OpenTK; + +namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components +{ + public class ControlPointPiece : CompositeDrawable + { + private readonly Slider slider; + private readonly int index; + + private readonly Path path; + private readonly CircularContainer marker; + + [Resolved] + private OsuColour colours { get; set; } + + public ControlPointPiece(Slider slider, int index) + { + this.slider = slider; + this.index = index; + + Origin = Anchor.Centre; + Size = new Vector2(10); + + InternalChildren = new Drawable[] + { + path = new SmoothPath + { + BypassAutoSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + PathWidth = 1 + }, + marker = new CircularContainer + { + RelativeSizeAxes = Axes.Both, + Masking = true, + Child = new Box { RelativeSizeAxes = Axes.Both } + } + }; + } + + protected override void Update() + { + base.Update(); + + Position = slider.StackedPosition + slider.ControlPoints[index]; + + marker.Colour = segmentSeparator ? colours.Red : colours.Yellow; + + path.ClearVertices(); + + if (index != slider.ControlPoints.Length - 1) + { + path.AddVertex(Vector2.Zero); + path.AddVertex(slider.ControlPoints[index + 1] - slider.ControlPoints[index]); + } + + path.OriginPosition = path.PositionInBoundingBox(Vector2.Zero); + } + + protected override bool OnDragStart(DragStartEvent e) => true; + + protected override bool OnDrag(DragEvent e) + { + var newControlPoints = slider.ControlPoints.ToArray(); + newControlPoints[index] += e.Delta; + + slider.ControlPoints = newControlPoints; + + return true; + } + + protected override bool OnDragEnd(DragEndEvent e) => true; + + private bool segmentSeparator => index != 0 && index != slider.ControlPoints.Length - 1 + && slider.ControlPoints[index - 1] != slider.ControlPoints[index] + && slider.ControlPoints[index + 1] != slider.ControlPoints[index]; + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/ControlPointVisualiser.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/ControlPointVisualiser.cs new file mode 100644 index 0000000000..d8031c4f5b --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/ControlPointVisualiser.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 osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Rulesets.Osu.Objects; + +namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components +{ + public class ControlPointVisualiser : CompositeDrawable + { + private readonly Slider slider; + + private readonly Container pieces; + + public ControlPointVisualiser(Slider slider) + { + this.slider = slider; + + InternalChild = pieces = new Container { RelativeSizeAxes = Axes.Both }; + + slider.ControlPointsChanged += _ => updateControlPoints(); + updateControlPoints(); + } + + private void updateControlPoints() + { + while (slider.ControlPoints.Length > pieces.Count) + pieces.Add(new ControlPointPiece(slider, pieces.Count)); + while (slider.ControlPoints.Length < pieces.Count) + pieces.Remove(pieces[pieces.Count - 1]); + } + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderSelectionMask.cs index a411064f68..8478374a5f 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderSelectionMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderSelectionMask.cs @@ -24,6 +24,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks new SliderBodyPiece(sliderObject), headMask = new SliderCircleSelectionMask(slider.HeadCircle, sliderObject, SliderPosition.Start), new SliderCircleSelectionMask(slider.TailCircle, sliderObject, SliderPosition.End), + new ControlPointVisualiser(sliderObject), }; } diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index a6f5bdb24e..10ffe82579 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -22,6 +22,8 @@ namespace osu.Game.Rulesets.Osu.Objects /// private const float base_scoring_distance = 100; + public event Action ControlPointsChanged; + public double EndTime => StartTime + this.SpanCount() * Curve.Distance / Velocity; public double Duration => EndTime - StartTime; @@ -54,8 +56,15 @@ namespace osu.Game.Rulesets.Osu.Objects public Vector2[] ControlPoints { - get { return Curve.ControlPoints; } - set { Curve.ControlPoints = value; } + get => Curve.ControlPoints; + set + { + if (Curve.ControlPoints == value) + return; + Curve.ControlPoints = value; + + ControlPointsChanged?.Invoke(value); + } } public CurveType CurveType From acd703c27b3f8d1b147e9e7144524bb1e604beb8 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 29 Oct 2018 15:36:43 +0900 Subject: [PATCH 210/333] Make sliders respond to control point changes --- .../TestCaseSliderSelectionMask.cs | 2 +- .../Components/ControlPointPiece.cs | 23 ++++++++++++-- .../SliderMasks/Components/SliderBodyPiece.cs | 1 + .../Components/SliderCirclePiece.cs | 2 ++ .../Objects/Drawables/DrawableSlider.cs | 2 ++ .../Objects/Drawables/DrawableSliderHead.cs | 7 ++++- .../Objects/Drawables/DrawableSliderTail.cs | 11 ++++++- .../Drawables/Pieces/SnakingSliderBody.cs | 31 +++++++++++++------ osu.Game.Rulesets.Osu/Objects/Slider.cs | 3 ++ osu.Game/Rulesets/Objects/SliderCurve.cs | 27 ++++++++++++++-- 10 files changed, 92 insertions(+), 17 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionMask.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionMask.cs index a73cb69536..1ba3e26e65 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionMask.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionMask.cs @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Osu.Tests { public class TestCaseSliderSelectionMask : HitObjectSelectionMaskTestCase { - public override IReadOnlyList RequiredTypes => new Type[] + public override IReadOnlyList RequiredTypes => new[] { typeof(SliderSelectionMask), typeof(SliderCircleSelectionMask), diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/ControlPointPiece.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/ControlPointPiece.cs index 5a3c5d5aaf..401fc24902 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/ControlPointPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/ControlPointPiece.cs @@ -73,10 +73,27 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components protected override bool OnDrag(DragEvent e) { - var newControlPoints = slider.ControlPoints.ToArray(); - newControlPoints[index] += e.Delta; + if (index == 0) + { + // Special handling for the head - only the position of the slider changes + slider.Position += e.Delta; - slider.ControlPoints = newControlPoints; + // Since control points are relative to the position of the slider, they all need to be offset backwards by the delta + var newControlPoints = slider.ControlPoints.ToArray(); + for (int i = 1; i < newControlPoints.Length; i++) + newControlPoints[i] -= e.Delta; + + slider.ControlPoints = newControlPoints; + slider.Curve.Calculate(true); + } + else + { + var newControlPoints = slider.ControlPoints.ToArray(); + newControlPoints[index] += e.Delta; + + slider.ControlPoints = newControlPoints; + slider.Curve.Calculate(true); + } return true; } diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderBodyPiece.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderBodyPiece.cs index 3123a4fcea..46d99e1740 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderBodyPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderBodyPiece.cs @@ -46,6 +46,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components // Need to cause one update body.UpdateProgress(0); + body.Refresh(); } } } diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderCirclePiece.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderCirclePiece.cs index c5ecde5c4c..a8565fafb6 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderCirclePiece.cs @@ -16,6 +16,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components { this.slider = slider; this.position = position; + + slider.ControlPointsChanged += _ => UpdatePosition(); } protected override void UpdatePosition() diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index 16bd522c1d..7599001a82 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -85,6 +85,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables } HitObject.PositionChanged += _ => Position = HitObject.StackedPosition; + + slider.ControlPointsChanged += _ => 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 6d6cba4936..6a836679a2 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs @@ -16,7 +16,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables { this.slider = slider; - Position = HitObject.Position - slider.Position; + h.PositionChanged += _ => updatePosition(); + slider.ControlPointsChanged += _ => updatePosition(); + + updatePosition(); } protected override void Update() @@ -33,5 +36,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables public Action OnShake; protected override void Shake(double maximumLength) => OnShake?.Invoke(maximumLength); + + private void updatePosition() => Position = HitObject.Position - slider.Position; } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs index 45c925b87a..cc88a6718b 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs @@ -8,6 +8,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables { public class DrawableSliderTail : DrawableOsuHitObject, IRequireTracking { + private readonly Slider slider; + /// /// The judgement text is provided by the . /// @@ -18,6 +20,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables public DrawableSliderTail(Slider slider, SliderTailCircle hitCircle) : base(hitCircle) { + this.slider = slider; + Origin = Anchor.Centre; RelativeSizeAxes = Axes.Both; @@ -25,7 +29,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables AlwaysPresent = true; - Position = HitObject.Position - slider.Position; + hitCircle.PositionChanged += _ => updatePosition(); + slider.ControlPointsChanged += _ => updatePosition(); + + updatePosition(); } protected override void CheckForResult(bool userTriggered, double timeOffset) @@ -33,5 +40,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables if (!userTriggered && timeOffset >= 0) ApplyResult(r => r.Type = Tracking ? HitResult.Great : HitResult.Miss); } + + private void updatePosition() => Position = HitObject.Position - slider.Position; } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SnakingSliderBody.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SnakingSliderBody.cs index 09d6f9459a..3d02f9a92d 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SnakingSliderBody.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SnakingSliderBody.cs @@ -45,15 +45,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces [BackgroundDependencyLoader] private void load() { - // Generate the entire curve - slider.Curve.GetPathToProgress(CurrentCurve, 0, 1); - SetVertices(CurrentCurve); - - // The body is sized to the full path size to avoid excessive autosize computations - Size = Path.Size; - - snakedPosition = Path.PositionInBoundingBox(Vector2.Zero); - snakedPathOffset = Path.PositionInBoundingBox(Path.Vertices[0]); + Refresh(); } public void UpdateProgress(double completionProgress) @@ -80,6 +72,27 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces setRange(start, end); } + public void Refresh() + { + // Generate the entire curve + slider.Curve.GetPathToProgress(CurrentCurve, 0, 1); + SetVertices(CurrentCurve); + + // The body is sized to the full path size to avoid excessive autosize computations + Size = Path.Size; + + snakedPosition = Path.PositionInBoundingBox(Vector2.Zero); + snakedPathOffset = Path.PositionInBoundingBox(Path.Vertices[0]); + + var lastSnakedStart = SnakedStart ?? 0; + var lastSnakedEnd = SnakedEnd ?? 0; + + SnakedStart = null; + SnakedEnd = null; + + setRange(lastSnakedStart, lastSnakedEnd); + } + private void setRange(double p0, double p1) { if (p0 > p1) diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 10ffe82579..de7ba8451b 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -64,6 +64,9 @@ namespace osu.Game.Rulesets.Osu.Objects Curve.ControlPoints = value; ControlPointsChanged?.Invoke(value); + + if (TailCircle != null) + TailCircle.Position = EndPosition; } } diff --git a/osu.Game/Rulesets/Objects/SliderCurve.cs b/osu.Game/Rulesets/Objects/SliderCurve.cs index dfccdf68f2..6a8192a4f2 100644 --- a/osu.Game/Rulesets/Objects/SliderCurve.cs +++ b/osu.Game/Rulesets/Objects/SliderCurve.cs @@ -124,10 +124,33 @@ namespace osu.Game.Rulesets.Objects } } - public void Calculate() + private void calculateCumulativeLength() + { + 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; + + l += d; + cumulativeLength.Add(l); + } + + Distance = l; + } + + public void Calculate(bool updateDistance = false) { calculatePath(); - calculateCumulativeLengthAndTrimPath(); + + if (!updateDistance) + calculateCumulativeLengthAndTrimPath(); + else + calculateCumulativeLength(); } private int indexOfDistance(double d) From c1fffde10db3cb0ccf508899dc9545f7b0d58816 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 29 Oct 2018 15:52:28 +0900 Subject: [PATCH 211/333] Fix broken conditional --- .../Components/ControlPointPiece.cs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/ControlPointPiece.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/ControlPointPiece.cs index 401fc24902..7547b4523b 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/ControlPointPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/ControlPointPiece.cs @@ -56,7 +56,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components Position = slider.StackedPosition + slider.ControlPoints[index]; - marker.Colour = segmentSeparator ? colours.Red : colours.Yellow; + marker.Colour = isSegmentSeparator ? colours.Red : colours.Yellow; path.ClearVertices(); @@ -100,8 +100,19 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components protected override bool OnDragEnd(DragEndEvent e) => true; - private bool segmentSeparator => index != 0 && index != slider.ControlPoints.Length - 1 - && slider.ControlPoints[index - 1] != slider.ControlPoints[index] - && slider.ControlPoints[index + 1] != slider.ControlPoints[index]; + private bool isSegmentSeparator + { + get + { + bool separator = false; + + if (index < slider.ControlPoints.Length - 1) + separator |= slider.ControlPoints[index + 1] == slider.ControlPoints[index]; + if (index > 0) + separator |= slider.ControlPoints[index - 1] == slider.ControlPoints[index]; + + return separator; + } + } } } From 5998d6454b7731168fd36da65ed6e1fa6295ccba Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 29 Oct 2018 15:56:17 +0900 Subject: [PATCH 212/333] Use ControlPointVisualiser instead of custom implementation --- .../Components/SliderControlPoint.cs | 92 ------------------- .../Masks/SliderMasks/SliderPlacementMask.cs | 9 +- 2 files changed, 1 insertion(+), 100 deletions(-) delete mode 100644 osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderControlPoint.cs diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderControlPoint.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderControlPoint.cs deleted file mode 100644 index e9693e7a3c..0000000000 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderControlPoint.cs +++ /dev/null @@ -1,92 +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.Caching; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Lines; -using osu.Framework.Graphics.Shapes; -using osu.Game.Graphics; -using OpenTK; - -namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components -{ - public class SliderControlPoint : CompositeDrawable - { - private readonly Path path; - private readonly CircularContainer marker; - - private OsuColour colours; - - public SliderControlPoint() - { - Size = new Vector2(5); - Origin = Anchor.Centre; - - NextPoint = Position; - - InternalChildren = new Drawable[] - { - path = new SmoothPath - { - BypassAutoSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - PathWidth = 1, - }, - marker = new CircularContainer - { - RelativeSizeAxes = Axes.Both, - Masking = true, - Child = new Box { RelativeSizeAxes = Axes.Both } - } - }; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - this.colours = colours; - - marker.Colour = colours.YellowDark; - } - - public bool SegmentSeparator - { - set => marker.Colour = value ? colours.Red : colours.YellowDark; - } - - private Vector2 nextPoint; - - public Vector2 NextPoint - { - set - { - nextPoint = value; - pathCache.Invalidate(); - } - } - - protected override void Update() - { - base.Update(); - - validatePath(); - } - - private Cached pathCache = new Cached(); - - private void validatePath() - { - if (pathCache.IsValid) - return; - - path.ClearVertices(); - path.AddVertex(nextPoint - Position); - path.AddVertex(Vector2.Zero); - path.OriginPosition = path.PositionInBoundingBox(Vector2.Zero); - - pathCache.Validate(); - } - } -} diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPlacementMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPlacementMask.cs index 2ee996fb00..727ec4c8d5 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPlacementMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPlacementMask.cs @@ -7,7 +7,6 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; using osu.Game.Graphics; using osu.Game.Rulesets.Edit; @@ -23,8 +22,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks { public new Objects.Slider HitObject => (Objects.Slider)base.HitObject; - private Container controlPointContainer; - private readonly List segments = new List(); private Vector2 cursor; @@ -45,7 +42,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks new SliderBodyPiece(HitObject), new SliderCirclePiece(HitObject, SliderPosition.Start), new SliderCirclePiece(HitObject, SliderPosition.End), - controlPointContainer = new Container { RelativeSizeAxes = Axes.Both } + new ControlPointVisualiser(HitObject), }; setState(PlacementState.Initial); @@ -60,7 +57,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks return true; case PlacementState.Body: cursor = e.MousePosition - HitObject.Position; - controlPointContainer.Last().NextPoint = e.MousePosition; return true; } @@ -85,8 +81,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks break; } - controlPointContainer.Add(new SliderControlPoint { Position = e.MousePosition }); - return true; } @@ -100,7 +94,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks protected override bool OnDoubleClick(DoubleClickEvent e) { segments.Add(new Segment(segments[segments.Count - 1].ControlPoints.Last())); - controlPointContainer.Last().SegmentSeparator = true; return true; } From 2ae7b4224464bc544598f3d9e1724f6a0e4731d0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 29 Oct 2018 16:15:04 +0900 Subject: [PATCH 213/333] Fix control points disappearing if moved offscreen --- .../Masks/SliderMasks/Components/ControlPointPiece.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/ControlPointPiece.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/ControlPointPiece.cs index 7547b4523b..b1d157d9b7 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/ControlPointPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/ControlPointPiece.cs @@ -31,19 +31,20 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components this.index = index; Origin = Anchor.Centre; - Size = new Vector2(10); + AutoSizeAxes = Axes.Both; InternalChildren = new Drawable[] { path = new SmoothPath { - BypassAutoSizeAxes = Axes.Both, Anchor = Anchor.Centre, PathWidth = 1 }, marker = new CircularContainer { - RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(15), Masking = true, Child = new Box { RelativeSizeAxes = Axes.Both } } @@ -69,6 +70,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components path.OriginPosition = path.PositionInBoundingBox(Vector2.Zero); } + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => marker.ReceivePositionalInputAt(screenSpacePos); + protected override bool OnDragStart(DragStartEvent e) => true; protected override bool OnDrag(DragEvent e) From af1de01ed61d258a4d579ec0f7354163e9a24e58 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 29 Oct 2018 18:23:23 +0900 Subject: [PATCH 214/333] Add a spinner selection mask --- .../TestCaseSpinnerSelectionMask.cs | 50 ++++++++++++++ .../SpinnerMasks/Components/SpinnerPiece.cs | 65 +++++++++++++++++++ .../SpinnerMasks/SpinnerSelectionMask.cs | 24 +++++++ .../Edit/OsuHitObjectComposer.cs | 3 + .../Objects/Drawables/DrawableSpinner.cs | 4 +- 5 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerSelectionMask.cs create mode 100644 osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/Components/SpinnerPiece.cs create mode 100644 osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerSelectionMask.cs diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerSelectionMask.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerSelectionMask.cs new file mode 100644 index 0000000000..b436ff0e9f --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerSelectionMask.cs @@ -0,0 +1,50 @@ +// 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.Graphics; +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.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Tests.Visual; +using OpenTK; + +namespace osu.Game.Rulesets.Osu.Tests +{ + public class TestCaseSpinnerSelectionMask : HitObjectSelectionMaskTestCase + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(SpinnerSelectionMask), + typeof(SpinnerPiece) + }; + + private readonly DrawableSpinner drawableSpinner; + + public TestCaseSpinnerSelectionMask() + { + var spinner = new Spinner + { + Position = new Vector2(256, 256), + StartTime = -1000, + EndTime = 2000 + }; + spinner.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 2 }); + + Add(new Container + { + RelativeSizeAxes = Axes.Both, + Size = new Vector2(0.5f), + Child = drawableSpinner = new DrawableSpinner(spinner) + }); + } + + protected override SelectionMask CreateMask() => new SpinnerSelectionMask(drawableSpinner) { Size = new Vector2(0.5f) }; + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/Components/SpinnerPiece.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/Components/SpinnerPiece.cs new file mode 100644 index 0000000000..ce2b5cd1d6 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/Components/SpinnerPiece.cs @@ -0,0 +1,65 @@ +// 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 osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +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 +{ + public class SpinnerPiece : CompositeDrawable + { + private readonly Spinner spinner; + private readonly CircularContainer circle; + + public SpinnerPiece(Spinner spinner) + { + this.spinner = spinner; + + Origin = Anchor.Centre; + + RelativeSizeAxes = Axes.Both; + FillMode = FillMode.Fit; + Size = new Vector2(1.3f); + + RingPiece ring; + InternalChildren = new Drawable[] + { + circle = new CircularContainer + { + RelativeSizeAxes = Axes.Both, + Masking = true, + Alpha = 0.5f, + Child = new Box { RelativeSizeAxes = Axes.Both } + }, + ring = new RingPiece + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre + } + }; + + ring.Scale = new Vector2(spinner.Scale); + + spinner.PositionChanged += _ => updatePosition(); + spinner.StackHeightChanged += _ => updatePosition(); + + updatePosition(); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + Colour = colours.Yellow; + } + + private void updatePosition() => Position = spinner.Position; + + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => circle.ReceivePositionalInputAt(screenSpacePos); + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerSelectionMask.cs new file mode 100644 index 0000000000..0e47bd2a8b --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerSelectionMask.cs @@ -0,0 +1,24 @@ +// 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.Masks.SpinnerMasks.Components; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using OpenTK; + +namespace osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks +{ + public class SpinnerSelectionMask : SelectionMask + { + private readonly SpinnerPiece piece; + + public SpinnerSelectionMask(DrawableSpinner spinner) + : base(spinner) + { + InternalChild = piece = new SpinnerPiece((Spinner)spinner.HitObject); + } + + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => piece.ReceivePositionalInputAt(screenSpacePos); + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index ac41d6ef27..386665ab7c 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -10,6 +10,7 @@ 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.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.UI; @@ -42,6 +43,8 @@ namespace osu.Game.Rulesets.Osu.Edit return new HitCircleSelectionMask(circle); case DrawableSlider slider: return new SliderSelectionMask(slider); + case DrawableSpinner spinner: + return new SpinnerSelectionMask(spinner); } return base.CreateMaskFor(hitObject); diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs index 51b1990a21..f3846bd52f 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs @@ -112,6 +112,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Alpha = 0 } }; + + s.PositionChanged += _ => Position = s.Position; } public float Progress => MathHelper.Clamp(Disc.RotationAbsolute / 360 / Spinner.SpinsRequired, 0, 1); @@ -167,7 +169,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables protected override void Update() { - Disc.Tracking = OsuActionInputManager.PressedActions.Any(x => x == OsuAction.LeftButton || x == OsuAction.RightButton); + Disc.Tracking = OsuActionInputManager?.PressedActions.Any(x => x == OsuAction.LeftButton || x == OsuAction.RightButton) ?? false; if (!spmCounter.IsPresent && Disc.Tracking) spmCounter.FadeIn(HitObject.TimeFadeIn); From e04ad8357d1e32b849e059a65c71e10e0cecc97a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 29 Oct 2018 18:37:12 +0900 Subject: [PATCH 215/333] Make spinner piece respond to scale changes --- .../Edit/Masks/SpinnerMasks/Components/SpinnerPiece.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/Components/SpinnerPiece.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/Components/SpinnerPiece.cs index ce2b5cd1d6..0d9609facf 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/Components/SpinnerPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/Components/SpinnerPiece.cs @@ -48,6 +48,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks.Components spinner.PositionChanged += _ => updatePosition(); spinner.StackHeightChanged += _ => updatePosition(); + spinner.ScaleChanged += _ => ring.Scale = new Vector2(spinner.Scale); updatePosition(); } From aec1d95f045ce65b5b5ef0fe0efaa4416cffd4f6 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 29 Oct 2018 18:35:46 +0900 Subject: [PATCH 216/333] Implement spinner placement --- .../TestCaseSpinnerPlacementMask.cs | 20 +++++++ .../SpinnerMasks/SpinnerPlacementMask.cs | 59 +++++++++++++++++++ .../Edit/OsuHitObjectComposer.cs | 3 +- .../Edit/SpinnerCompositionTool.cs | 20 +++++++ 4 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerPlacementMask.cs create mode 100644 osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerPlacementMask.cs create mode 100644 osu.Game.Rulesets.Osu/Edit/SpinnerCompositionTool.cs diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerPlacementMask.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerPlacementMask.cs new file mode 100644 index 0000000000..c2c7942c57 --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerPlacementMask.cs @@ -0,0 +1,20 @@ +// 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.Objects; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Tests.Visual; + +namespace osu.Game.Rulesets.Osu.Tests +{ + public class TestCaseSpinnerPlacementMask : HitObjectPlacementMaskTestCase + { + protected override DrawableHitObject CreateHitObject(HitObject hitObject) => new DrawableSpinner((Spinner)hitObject); + + protected override PlacementMask CreateMask() => new SpinnerPlacementMask(); + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerPlacementMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerPlacementMask.cs new file mode 100644 index 0000000000..97356fa8b6 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerPlacementMask.cs @@ -0,0 +1,59 @@ +// 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.Osu.Edit.Masks.SpinnerMasks.Components; +using osu.Game.Rulesets.Osu.Objects; + +namespace osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks +{ + public class SpinnerPlacementMask : PlacementMask + { + public new Spinner HitObject => (Spinner)base.HitObject; + + private readonly SpinnerPiece piece; + + private bool isPlacingEnd; + + public SpinnerPlacementMask() + : base(new Spinner()) + { + InternalChild = piece = new SpinnerPiece(HitObject) { Alpha = 0.5f }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + // Fixes a 1-frame position discrpancy due to the first mouse move event happening in the next frame + HitObject.Position = GetContainingInputManager().CurrentState.Mouse.Position; + } + + protected override bool OnClick(ClickEvent e) + { + if (isPlacingEnd) + { + HitObject.EndTime = EditorClock.CurrentTime; + EndPlacement(); + } + else + { + HitObject.StartTime = EditorClock.CurrentTime; + + isPlacingEnd = true; + piece.FadeTo(1f, 150, Easing.OutQuint); + } + + return true; + } + + protected override bool OnMouseMove(MouseMoveEvent e) + { + if (!isPlacingEnd) + HitObject.Position = e.MousePosition; + return true; + } + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index 386665ab7c..a1629803c0 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -28,9 +28,10 @@ namespace osu.Game.Rulesets.Osu.Edit protected override RulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) => new OsuEditRulesetContainer(ruleset, beatmap); - protected override IReadOnlyList CompositionTools => new[] + protected override IReadOnlyList CompositionTools => new HitObjectCompositionTool[] { new HitCircleCompositionTool(), + new SpinnerCompositionTool() }; protected override Container CreateLayerContainer() => new PlayfieldAdjustmentContainer { RelativeSizeAxes = Axes.Both }; diff --git a/osu.Game.Rulesets.Osu/Edit/SpinnerCompositionTool.cs b/osu.Game.Rulesets.Osu/Edit/SpinnerCompositionTool.cs new file mode 100644 index 0000000000..a1419fe281 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/SpinnerCompositionTool.cs @@ -0,0 +1,20 @@ +// 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.Edit.Tools; +using osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks; +using osu.Game.Rulesets.Osu.Objects; + +namespace osu.Game.Rulesets.Osu.Edit +{ + public class SpinnerCompositionTool : HitObjectCompositionTool + { + public SpinnerCompositionTool() + : base(nameof(Spinner)) + { + } + + public override PlacementMask CreatePlacementMask() => new SpinnerPlacementMask(); + } +} From ff47b2be7a6eb17cd29b7be24156394597a14a9a Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 29 Oct 2018 18:42:35 +0100 Subject: [PATCH 217/333] Create a simple bootstrapper in the bash script language --- build.sh | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 build.sh diff --git a/build.sh b/build.sh new file mode 100644 index 0000000000..caf1702f41 --- /dev/null +++ b/build.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash + +########################################################################## +# This is a customized Cake bootstrapper script for Shell. +########################################################################## + +echo "Preparing to run build script..." + +SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) +TOOLS_DIR=$SCRIPT_DIR/tools +CAKE_BINARY_PATH=$TOOLS_DIR/"cake.coreclr" + +SCRIPT="build.cake" +CAKE_CSPROJ=$TOOLS_DIR/"cakebuild.csproj" + +# Parse arguments. +CAKE_ARGUMENTS=() +for i in "$@"; do + case $1 in + -s|--script) SCRIPT="$2"; shift ;; + --) shift; CAKE_ARGUMENTS+=("$@"); break ;; + *) CAKE_ARGUMENTS+=("$1") ;; + esac + shift +done + +# Install the required tools locally. +echo "Restoring cake tools..." +dotnet restore $CAKE_CSPROJ --packages $TOOLS_DIR > /dev/null 2>&1 + +# Search for the CakeBuild binary. +CAKE_BINARY=$(find $CAKE_BINARY_PATH -name "Cake.dll") + +# Start Cake +echo "Running build script..." + +dotnet "$CAKE_BINARY" $SCRIPT "${CAKE_ARGUMENTS[@]}" From bf83c1eb6adaf256172776843cf77bebf0b39f41 Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 29 Oct 2018 18:45:08 +0100 Subject: [PATCH 218/333] Mention the bash script in the readme. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d0919e1d82..00f55242d2 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Build and run - Using Visual Studio 2017, Rider or Visual Studio Code (configurations are included) - From command line using `dotnet run --project osu.Desktop`. When building for non-development purposes, add `-c Release` to gain higher performance. -- And from command line using `powershell ./build.ps1`. This will also run tests and code analysis. This command is used on CI. The code analysis is windows only. +- And from command line using `powershell ./build.ps1` or if you use bash as your shell: `./build.sh`. This will also run tests and code analysis. This command is used on CI. The code analysis is windows only. Note: If you run from command line under linux, you will need to prefix the output folder to your `LD_LIBRARY_PATH`. See `.vscode/launch.json` for an example From 4d97b96705214a6d8da94363c8cb96236651108d Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 29 Oct 2018 18:49:31 +0100 Subject: [PATCH 219/333] Remove the framework settings. It is not used. --- build.cake | 1 - 1 file changed, 1 deletion(-) diff --git a/build.cake b/build.cake index fff39079b6..136ad67ab9 100644 --- a/build.cake +++ b/build.cake @@ -7,7 +7,6 @@ /////////////////////////////////////////////////////////////////////////////// var target = Argument("target", "Build"); -var framework = Argument("framework", "netcoreapp2.1"); var configuration = Argument("configuration", "Release"); var osuSolution = new FilePath("./osu.sln"); From 6d00aff9fd7958227a16e607b32121130b9d3e70 Mon Sep 17 00:00:00 2001 From: Kyle Chang Date: Tue, 30 Oct 2018 00:13:33 -0400 Subject: [PATCH 220/333] Add type parameter to IApplicableToBeatmap --- osu.Game.Rulesets.Mania/Mods/ManiaModDualStages.cs | 7 ++++--- osu.Game/Rulesets/Mods/IApplicableToBeatmap.cs | 13 ++++++++----- osu.Game/Rulesets/UI/RulesetContainer.cs | 2 +- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModDualStages.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModDualStages.cs index 12b62d2b65..4790a77cc0 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModDualStages.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModDualStages.cs @@ -4,11 +4,12 @@ using System.Collections.Generic; using osu.Game.Beatmaps; using osu.Game.Rulesets.Mania.Beatmaps; +using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mods; namespace osu.Game.Rulesets.Mania.Mods { - public class ManiaModDualStages : Mod, IPlayfieldTypeMod, IApplicableToBeatmapConverter, IApplicableToBeatmap + public class ManiaModDualStages : Mod, IPlayfieldTypeMod, IApplicableToBeatmapConverter, IApplicableToBeatmap { public override string Name => "Dual Stages"; public override string ShortenedName => "DS"; @@ -31,12 +32,12 @@ namespace osu.Game.Rulesets.Mania.Mods mbc.TargetColumns *= 2; } - public void ApplyToBeatmap(IBeatmap beatmap) + public void ApplyToBeatmap(Beatmap beatmap) { if (isForCurrentRuleset) return; - var maniaBeatmap = (ManiaBeatmap) beatmap; + var maniaBeatmap = (ManiaBeatmap)beatmap; var newDefinitions = new List(); foreach (var existing in maniaBeatmap.Stages) diff --git a/osu.Game/Rulesets/Mods/IApplicableToBeatmap.cs b/osu.Game/Rulesets/Mods/IApplicableToBeatmap.cs index e1398ecf2b..1eb74ca76a 100644 --- a/osu.Game/Rulesets/Mods/IApplicableToBeatmap.cs +++ b/osu.Game/Rulesets/Mods/IApplicableToBeatmap.cs @@ -2,18 +2,21 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Game.Beatmaps; +using osu.Game.Rulesets.Objects; namespace osu.Game.Rulesets.Mods { /// - /// Interface for a that applies changes to a . + /// Interface for a that applies changes to a + /// after conversion and post-processing has completed. /// - public interface IApplicableToBeatmap : IApplicableMod + public interface IApplicableToBeatmap : IApplicableMod + where TObject : HitObject { /// - /// Applies this to a . + /// Applies this to a . /// - /// The to apply to. - void ApplyToBeatmap(IBeatmap beatmap); + /// The to apply to. + void ApplyToBeatmap(Beatmap beatmap); } } diff --git a/osu.Game/Rulesets/UI/RulesetContainer.cs b/osu.Game/Rulesets/UI/RulesetContainer.cs index 4b55bb558d..d1303e21a9 100644 --- a/osu.Game/Rulesets/UI/RulesetContainer.cs +++ b/osu.Game/Rulesets/UI/RulesetContainer.cs @@ -271,7 +271,7 @@ namespace osu.Game.Rulesets.UI if (mods == null) return; - foreach (var mod in mods.OfType()) + foreach (var mod in mods.OfType>()) mod.ApplyToBeatmap(Beatmap); } From b0ccd614805c9d89dc1da5f3e5fb5b43ab164dd1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 29 Oct 2018 12:41:22 -0700 Subject: [PATCH 221/333] Fix weird code formatting --- build.cake | 70 +++++++++++++++++++++++++++--------------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/build.cake b/build.cake index 136ad67ab9..bc7dfafb8c 100644 --- a/build.cake +++ b/build.cake @@ -16,57 +16,57 @@ var osuSolution = new FilePath("./osu.sln"); /////////////////////////////////////////////////////////////////////////////// Task("Restore") -.Does(() => { - DotNetCoreRestore(osuSolution.FullPath); -}); + .Does(() => { + DotNetCoreRestore(osuSolution.FullPath); + }); Task("Compile") -.IsDependentOn("Restore") -.Does(() => { - DotNetCoreBuild(osuSolution.FullPath, new DotNetCoreBuildSettings { - Configuration = configuration, - NoRestore = true, + .IsDependentOn("Restore") + .Does(() => { + DotNetCoreBuild(osuSolution.FullPath, new DotNetCoreBuildSettings { + Configuration = configuration, + NoRestore = true, + }); }); -}); Task("Test") -.IsDependentOn("Compile") -.Does(() => { - var testAssemblies = GetFiles("**/*.Tests/bin/**/*.Tests.dll"); + .IsDependentOn("Compile") + .Does(() => { + var testAssemblies = GetFiles("**/*.Tests/bin/**/*.Tests.dll"); - DotNetCoreVSTest(testAssemblies, new DotNetCoreVSTestSettings { - Logger = AppVeyor.IsRunningOnAppVeyor ? "Appveyor" : $"trx", - Parallel = true, - ToolTimeout = TimeSpan.FromMinutes(10), + DotNetCoreVSTest(testAssemblies, new DotNetCoreVSTestSettings { + Logger = AppVeyor.IsRunningOnAppVeyor ? "Appveyor" : $"trx", + Parallel = true, + ToolTimeout = TimeSpan.FromMinutes(10), + }); }); -}); // windows only because both inspectcore and nvika depend on net45 Task("InspectCode") -.WithCriteria(IsRunningOnWindows()) -.IsDependentOn("Compile") -.Does(() => { - var nVikaToolPath = GetFiles("./tools/NVika.MSBuild.*/tools/NVika.exe").First(); + .WithCriteria(IsRunningOnWindows()) + .IsDependentOn("Compile") + .Does(() => { + var nVikaToolPath = GetFiles("./tools/NVika.MSBuild.*/tools/NVika.exe").First(); - InspectCode(osuSolution, new InspectCodeSettings { - CachesHome = "inspectcode", - OutputFile = "inspectcodereport.xml", + InspectCode(osuSolution, new InspectCodeSettings { + CachesHome = "inspectcode", + OutputFile = "inspectcodereport.xml", + }); + + StartProcess(nVikaToolPath, @"parsereport ""inspectcodereport.xml"" --treatwarningsaserrors"); }); - StartProcess(nVikaToolPath, @"parsereport ""inspectcodereport.xml"" --treatwarningsaserrors"); -}); - Task("CodeFileSanity") -.Does(() => { - ValidateCodeSanity(new ValidateCodeSanitySettings { - RootDirectory = ".", - IsAppveyorBuild = AppVeyor.IsRunningOnAppVeyor + .Does(() => { + ValidateCodeSanity(new ValidateCodeSanitySettings { + RootDirectory = ".", + IsAppveyorBuild = AppVeyor.IsRunningOnAppVeyor + }); }); -}); Task("Build") -.IsDependentOn("CodeFileSanity") -.IsDependentOn("InspectCode") -.IsDependentOn("Test"); + .IsDependentOn("CodeFileSanity") + .IsDependentOn("InspectCode") + .IsDependentOn("Test"); RunTarget(target); \ No newline at end of file From d173335b6d2760936d015d814bd7172e79cc2e07 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 30 Oct 2018 00:02:32 -0700 Subject: [PATCH 222/333] Reword readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 00f55242d2..baaba22726 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Build and run - Using Visual Studio 2017, Rider or Visual Studio Code (configurations are included) - From command line using `dotnet run --project osu.Desktop`. When building for non-development purposes, add `-c Release` to gain higher performance. -- And from command line using `powershell ./build.ps1` or if you use bash as your shell: `./build.sh`. This will also run tests and code analysis. This command is used on CI. The code analysis is windows only. +- To run with code analysis, instead use `powershell ./build.ps1` or `build.sh`. This is currently only supported under windows due to [resharper cli shortcomings](https://youtrack.jetbrains.com/issue/RSRP-410004). Alternative, you can install resharper or use rider to get inline support in your IDE of choice. Note: If you run from command line under linux, you will need to prefix the output folder to your `LD_LIBRARY_PATH`. See `.vscode/launch.json` for an example From 0b534885b8a021b72c184983f38d89ac15ad1f08 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 30 Oct 2018 00:10:34 -0700 Subject: [PATCH 223/333] Update framework --- 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 e2b466c69f..2f8c743bee 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -18,7 +18,7 @@ - + From 71b6789136b786d36163c8f5bb576f8f8f932d28 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 30 Oct 2018 16:47:39 +0900 Subject: [PATCH 224/333] Fix post-merge conflict --- .../Edit/Masks/SliderMasks/Components/SliderBodyPiece.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderBodyPiece.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderBodyPiece.cs index 0595b046d1..3123a4fcea 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderBodyPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderBodyPiece.cs @@ -13,12 +13,12 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components public class SliderBodyPiece : CompositeDrawable { private readonly Slider slider; - private readonly SliderBody body; + private readonly SnakingSliderBody body; public SliderBodyPiece(Slider slider) { this.slider = slider; - InternalChild = body = new SliderBody(slider) + InternalChild = body = new SnakingSliderBody(slider) { AccentColour = Color4.Transparent, PathWidth = slider.Scale * 64 From 4bc9161cd1412bfcce6179d210fa6e7a4b43d9a1 Mon Sep 17 00:00:00 2001 From: Paul Teng Date: Tue, 30 Oct 2018 08:32:12 -0400 Subject: [PATCH 225/333] Leave bigger gap if replaying --- osu.Game/Screens/Play/HUDOverlay.cs | 2 ++ osu.Game/Screens/Play/SongProgress.cs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index db0d7b6ccc..0f9f4fc20a 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -134,11 +134,13 @@ namespace osu.Game.Screens.Play { PlayerSettingsOverlay.Show(); ModDisplay.FadeIn(200); + KeyCounter.Margin = new MarginPadding(10) { Bottom = 30 }; } else { PlayerSettingsOverlay.Hide(); ModDisplay.Delay(2000).FadeOut(200); + KeyCounter.Margin = new MarginPadding(10); } } diff --git a/osu.Game/Screens/Play/SongProgress.cs b/osu.Game/Screens/Play/SongProgress.cs index e921cd602b..d1fc7b3378 100644 --- a/osu.Game/Screens/Play/SongProgress.cs +++ b/osu.Game/Screens/Play/SongProgress.cs @@ -135,6 +135,8 @@ namespace osu.Game.Screens.Play { bar.FadeTo(allowSeeking ? 1 : 0, transition_duration, Easing.In); this.MoveTo(new Vector2(0, allowSeeking ? 0 : bottom_bar_height), transition_duration, Easing.In); + + info.Margin = new MarginPadding { Bottom = Height - (allowSeeking ? 0 : handle_size.Y) }; } protected override void PopIn() From 6f1ef3243d2c7bd21e271e01883cbc2bac202ca8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 31 Oct 2018 02:56:25 +0900 Subject: [PATCH 226/333] Proportionally adjust width in line with change --- osu.Game/Screens/Play/SongProgress.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/SongProgress.cs b/osu.Game/Screens/Play/SongProgress.cs index d1fc7b3378..d4615b3016 100644 --- a/osu.Game/Screens/Play/SongProgress.cs +++ b/osu.Game/Screens/Play/SongProgress.cs @@ -21,7 +21,7 @@ namespace osu.Game.Screens.Play { private const int bottom_bar_height = 5; - private static readonly Vector2 handle_size = new Vector2(14, 18); + private static readonly Vector2 handle_size = new Vector2(10, 18); private const float transition_duration = 200; From 3207a585c6e4dcd0bd82f74c854b5d05f8afaa42 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 31 Oct 2018 12:01:10 +0900 Subject: [PATCH 227/333] Add missing xmldoc --- osu.Game/Rulesets/Edit/PlacementMask.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Rulesets/Edit/PlacementMask.cs b/osu.Game/Rulesets/Edit/PlacementMask.cs index a588a9e181..be2c42b586 100644 --- a/osu.Game/Rulesets/Edit/PlacementMask.cs +++ b/osu.Game/Rulesets/Edit/PlacementMask.cs @@ -15,6 +15,9 @@ using OpenTK; namespace osu.Game.Rulesets.Edit { + /// + /// A mask which governs the creation of a new to actualisation. + /// public abstract class PlacementMask : CompositeDrawable, IRequireHighFrequencyMousePosition { /// From 5eaf80ab7671c43412cbad7f185c550fb9313ba2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 31 Oct 2018 12:07:06 +0900 Subject: [PATCH 228/333] Add missing newline --- osu.Game/Screens/Edit/Screens/Compose/Layers/MaskSelection.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskSelection.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskSelection.cs index 4946b35abb..17b34bfb49 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskSelection.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskSelection.cs @@ -87,6 +87,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers placementHandler.Delete(h.HitObject.HitObject); return true; } + return base.OnKeyDown(e); } From 214ed43b812666383e4cea2098620404ddef4922 Mon Sep 17 00:00:00 2001 From: Kyle Chang Date: Tue, 30 Oct 2018 23:47:54 -0400 Subject: [PATCH 229/333] Check if SongSelect is current screen before playing selected song --- osu.Game/Screens/Select/SongSelect.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 4288483caf..acf699aa24 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -350,7 +350,7 @@ namespace osu.Game.Screens.Select } } - ensurePlayingSelected(preview); + if (IsCurrentScreen) ensurePlayingSelected(preview); UpdateBeatmap(Beatmap.Value); } From 29a1d092fad67cd2bdbc65c36ce0fca08dbfd6c6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 31 Oct 2018 16:43:35 +0900 Subject: [PATCH 230/333] Don't log disk space related IO errors --- osu.Game/Utils/RavenLogger.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Utils/RavenLogger.cs b/osu.Game/Utils/RavenLogger.cs index b28dd1fb73..6679ff94a9 100644 --- a/osu.Game/Utils/RavenLogger.cs +++ b/osu.Game/Utils/RavenLogger.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.IO; using System.Threading.Tasks; using osu.Framework.Logging; using SharpRaven; @@ -35,6 +36,9 @@ namespace osu.Game.Utils if (exception != null) { + if (exception is IOException ioe && ioe.Message.StartsWith("There is not enough space on the disk")) + return; + // since we let unhandled exceptions go ignored at times, we want to ensure they don't get submitted on subsequent reports. if (lastException != null && lastException.Message == exception.Message && exception.StackTrace.StartsWith(lastException.StackTrace)) From 9aa88293e2509a9f9a3f3426647519e505e94992 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 31 Oct 2018 17:07:05 +0900 Subject: [PATCH 231/333] Use HResult --- osu.Game/Utils/RavenLogger.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/osu.Game/Utils/RavenLogger.cs b/osu.Game/Utils/RavenLogger.cs index 6679ff94a9..c6e6d1e9d7 100644 --- a/osu.Game/Utils/RavenLogger.cs +++ b/osu.Game/Utils/RavenLogger.cs @@ -36,8 +36,15 @@ namespace osu.Game.Utils if (exception != null) { - if (exception is IOException ioe && ioe.Message.StartsWith("There is not enough space on the disk")) - return; + if (exception is IOException ioe) + { + // disk full exceptions, see https://stackoverflow.com/a/9294382 + const int hr_error_handle_disk_full = unchecked((int)0x80070027); + const int hr_error_disk_full = unchecked((int)0x80070070); + + if (ioe.HResult == hr_error_handle_disk_full || ioe.HResult == hr_error_disk_full) + return; + } // since we let unhandled exceptions go ignored at times, we want to ensure they don't get submitted on subsequent reports. if (lastException != null && From 85a732591141310e576abbe95c7c073cc32bd2d3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 31 Oct 2018 17:23:27 +0900 Subject: [PATCH 232/333] Fix placement masks handling scroll events --- osu.Game/Rulesets/Edit/PlacementMask.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Rulesets/Edit/PlacementMask.cs b/osu.Game/Rulesets/Edit/PlacementMask.cs index be2c42b586..97c6a74c92 100644 --- a/osu.Game/Rulesets/Edit/PlacementMask.cs +++ b/osu.Game/Rulesets/Edit/PlacementMask.cs @@ -84,6 +84,8 @@ namespace osu.Game.Rulesets.Edit switch (e) { + case ScrollEvent _: + return false; case MouseEvent _: return true; default: From d2fbf051377bc1af9bf2e0a61bc0f8715364cc54 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 31 Oct 2018 18:01:53 +0900 Subject: [PATCH 233/333] Reduce size of control point --- .../Edit/Masks/SliderMasks/Components/ControlPointPiece.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/ControlPointPiece.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/ControlPointPiece.cs index b1d157d9b7..2c6f9120c2 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/ControlPointPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/ControlPointPiece.cs @@ -44,7 +44,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Size = new Vector2(15), + Size = new Vector2(10), Masking = true, Child = new Box { RelativeSizeAxes = Axes.Both } } From ffec532079a74c71478b1e2cda3ac770c76a5ef6 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 31 Oct 2018 18:02:08 +0900 Subject: [PATCH 234/333] Fix segment control points not changing in unison --- .../Components/ControlPointPiece.cs | 34 +++++++------------ 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/ControlPointPiece.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/ControlPointPiece.cs index 2c6f9120c2..aedde870ca 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/ControlPointPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/ControlPointPiece.cs @@ -76,46 +76,38 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components protected override bool OnDrag(DragEvent e) { + var newControlPoints = slider.ControlPoints.ToArray(); + if (index == 0) { // Special handling for the head - only the position of the slider changes slider.Position += e.Delta; // Since control points are relative to the position of the slider, they all need to be offset backwards by the delta - var newControlPoints = slider.ControlPoints.ToArray(); for (int i = 1; i < newControlPoints.Length; i++) newControlPoints[i] -= e.Delta; - - slider.ControlPoints = newControlPoints; - slider.Curve.Calculate(true); } else - { - var newControlPoints = slider.ControlPoints.ToArray(); newControlPoints[index] += e.Delta; - slider.ControlPoints = newControlPoints; - slider.Curve.Calculate(true); - } + if (isSegmentSeparatorWithNext) + newControlPoints[index + 1] = newControlPoints[index]; + + if (isSegmentSeparatorWithPrevious) + newControlPoints[index - 1] = newControlPoints[index]; + + slider.ControlPoints = newControlPoints; + slider.Curve.Calculate(true); return true; } protected override bool OnDragEnd(DragEndEvent e) => true; - private bool isSegmentSeparator - { - get - { - bool separator = false; + private bool isSegmentSeparator => isSegmentSeparatorWithNext || isSegmentSeparatorWithPrevious; - if (index < slider.ControlPoints.Length - 1) - separator |= slider.ControlPoints[index + 1] == slider.ControlPoints[index]; - if (index > 0) - separator |= slider.ControlPoints[index - 1] == slider.ControlPoints[index]; + private bool isSegmentSeparatorWithNext => index < slider.ControlPoints.Length - 1 && slider.ControlPoints[index + 1] == slider.ControlPoints[index]; - return separator; - } - } + private bool isSegmentSeparatorWithPrevious => index > 0 && slider.ControlPoints[index - 1] == slider.ControlPoints[index]; } } From bb2f8deb18bff435c70a96d36dee0d1e1c0e1d0a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 1 Nov 2018 03:52:24 +0900 Subject: [PATCH 235/333] ControlPoint -> PathControlPoint Also Curve -> Path. --- .../TestCaseAutoJuiceStream.cs | 2 +- .../Beatmaps/CatchBeatmapConverter.cs | 2 +- .../Objects/JuiceStream.cs | 26 +++++++++---------- osu.Game.Rulesets.Osu.Tests/TestCaseSlider.cs | 8 +++--- .../TestCaseSliderSelectionMask.cs | 6 ++--- .../Beatmaps/OsuBeatmapConverter.cs | 2 +- .../Preprocessing/OsuDifficultyHitObject.cs | 2 +- ...PointPiece.cs => PathControlPointPiece.cs} | 6 ++--- ...liser.cs => PathControlPointVisualiser.cs} | 16 ++++++------ .../Components/SliderCirclePiece.cs | 4 +-- .../Masks/SliderMasks/SliderSelectionMask.cs | 2 +- osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs | 2 +- .../Objects/Drawables/DrawableSlider.cs | 2 +- .../Drawables/Pieces/SnakingSliderBody.cs | 4 +-- osu.Game.Rulesets.Osu/Objects/Slider.cs | 26 +++++++++---------- .../Legacy/Catch/ConvertHitObjectParser.cs | 4 +-- .../Objects/Legacy/ConvertHitObjectParser.cs | 20 +++++++------- .../Rulesets/Objects/Legacy/ConvertSlider.cs | 4 +-- .../Legacy/Mania/ConvertHitObjectParser.cs | 4 +-- .../Legacy/Osu/ConvertHitObjectParser.cs | 4 +-- .../Legacy/Taiko/ConvertHitObjectParser.cs | 4 +-- .../Objects/{SliderCurve.cs => SliderPath.cs} | 26 +++++++++---------- osu.Game/Rulesets/Objects/Types/IHasCurve.cs | 6 ++--- .../Types/{CurveType.cs => PathType.cs} | 2 +- 24 files changed, 92 insertions(+), 92 deletions(-) rename osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/{ControlPointPiece.cs => PathControlPointPiece.cs} (95%) rename osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/{ControlPointVisualiser.cs => PathControlPointVisualiser.cs} (54%) rename osu.Game/Rulesets/Objects/{SliderCurve.cs => SliderPath.cs} (92%) rename osu.Game/Rulesets/Objects/Types/{CurveType.cs => PathType.cs} (91%) diff --git a/osu.Game.Rulesets.Catch.Tests/TestCaseAutoJuiceStream.cs b/osu.Game.Rulesets.Catch.Tests/TestCaseAutoJuiceStream.cs index 5e68acde94..cac1356c81 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestCaseAutoJuiceStream.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestCaseAutoJuiceStream.cs @@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Catch.Tests Vector2.Zero, new Vector2(width * CatchPlayfield.BASE_WIDTH, 0) }, - CurveType = CurveType.Linear, + 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 15d4edc411..a178748bd5 100644 --- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs +++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs @@ -35,7 +35,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps StartTime = obj.StartTime, Samples = obj.Samples, ControlPoints = curveData.ControlPoints, - CurveType = curveData.CurveType, + PathType = curveData.PathType, Distance = curveData.Distance, RepeatSamples = curveData.RepeatSamples, RepeatCount = curveData.RepeatCount, diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index 82e32d24d2..da581d9619 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -50,7 +50,7 @@ namespace osu.Game.Rulesets.Catch.Objects if (TickDistance == 0) return; - var length = Curve.Distance; + var length = Path.Distance; var tickDistance = Math.Min(TickDistance, length); var spanDuration = length / Velocity; @@ -95,7 +95,7 @@ namespace osu.Game.Rulesets.Catch.Objects AddNested(new TinyDroplet { StartTime = t, - X = X + Curve.PositionAt(progress).X / CatchPlayfield.BASE_WIDTH, + X = X + Path.PositionAt(progress).X / CatchPlayfield.BASE_WIDTH, Samples = new List(Samples.Select(s => new SampleInfo { Bank = s.Bank, @@ -110,7 +110,7 @@ namespace osu.Game.Rulesets.Catch.Objects AddNested(new Droplet { StartTime = time, - X = X + Curve.PositionAt(distanceProgress).X / CatchPlayfield.BASE_WIDTH, + X = X + Path.PositionAt(distanceProgress).X / CatchPlayfield.BASE_WIDTH, Samples = new List(Samples.Select(s => new SampleInfo { Bank = s.Bank, @@ -127,12 +127,12 @@ namespace osu.Game.Rulesets.Catch.Objects { Samples = Samples, StartTime = spanStartTime + spanDuration, - X = X + Curve.PositionAt(reversed ? 0 : 1).X / CatchPlayfield.BASE_WIDTH + X = X + Path.PositionAt(reversed ? 0 : 1).X / CatchPlayfield.BASE_WIDTH }); } } - public double EndTime => StartTime + this.SpanCount() * Curve.Distance / Velocity; + public double EndTime => StartTime + this.SpanCount() * Path.Distance / Velocity; public float EndX => X + this.CurvePositionAt(1).X / CatchPlayfield.BASE_WIDTH; @@ -140,24 +140,24 @@ namespace osu.Game.Rulesets.Catch.Objects public double Distance { - get { return Curve.Distance; } - set { Curve.Distance = value; } + get { return Path.Distance; } + set { Path.Distance = value; } } - public SliderCurve Curve { get; } = new SliderCurve(); + public SliderPath Path { get; } = new SliderPath(); public Vector2[] ControlPoints { - get { return Curve.ControlPoints; } - set { Curve.ControlPoints = value; } + get { return Path.ControlPoints; } + set { Path.ControlPoints = value; } } public List> RepeatSamples { get; set; } = new List>(); - public CurveType CurveType + public PathType PathType { - get { return Curve.CurveType; } - set { Curve.CurveType = value; } + 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 300ac16155..4c0385deda 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseSlider.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSlider.cs @@ -181,7 +181,7 @@ namespace osu.Game.Rulesets.Osu.Tests { var slider = new Slider { - CurveType = CurveType.Linear, + PathType = PathType.Linear, StartTime = Time.Current + 1000, Position = new Vector2(-200, 0), ControlPoints = new[] @@ -207,7 +207,7 @@ namespace osu.Game.Rulesets.Osu.Tests { var slider = new Slider { - CurveType = CurveType.Bezier, + PathType = PathType.Bezier, StartTime = Time.Current + 1000, Position = new Vector2(-200, 0), ControlPoints = new[] @@ -232,7 +232,7 @@ namespace osu.Game.Rulesets.Osu.Tests { var slider = new Slider { - CurveType = CurveType.Linear, + PathType = PathType.Linear, StartTime = Time.Current + 1000, Position = new Vector2(0, 0), ControlPoints = new[] @@ -264,7 +264,7 @@ namespace osu.Game.Rulesets.Osu.Tests { StartTime = Time.Current + 1000, Position = new Vector2(-100, 0), - CurveType = CurveType.Catmull, + PathType = PathType.Catmull, ControlPoints = new[] { Vector2.Zero, diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionMask.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionMask.cs index 1ba3e26e65..87e0e1a7ec 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionMask.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionMask.cs @@ -24,8 +24,8 @@ namespace osu.Game.Rulesets.Osu.Tests typeof(SliderCircleSelectionMask), typeof(SliderBodyPiece), typeof(SliderCircle), - typeof(ControlPointVisualiser), - typeof(ControlPointPiece) + typeof(PathControlPointVisualiser), + typeof(PathControlPointPiece) }; private readonly DrawableSlider drawableObject; @@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Osu.Tests new Vector2(150, 150), new Vector2(300, 0) }, - CurveType = CurveType.Bezier, + PathType = PathType.Bezier, Distance = 350 }; diff --git a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs index b2914d4b82..9f432fc31a 100644 --- a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs +++ b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs @@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps StartTime = original.StartTime, Samples = original.Samples, ControlPoints = curveData.ControlPoints, - CurveType = curveData.CurveType, + PathType = curveData.PathType, Distance = curveData.Distance, RepeatSamples = curveData.RepeatSamples, RepeatCount = curveData.RepeatCount, diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index d6684f55af..39e3c009da 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -108,7 +108,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing progress = progress % 1; // ReSharper disable once PossibleInvalidOperationException (bugged in current r# version) - var diff = slider.StackedPosition + slider.Curve.PositionAt(progress) - slider.LazyEndPosition.Value; + var diff = slider.StackedPosition + slider.Path.PositionAt(progress) - slider.LazyEndPosition.Value; float dist = diff.Length; if (dist > approxFollowCircleRadius) diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/ControlPointPiece.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/PathControlPointPiece.cs similarity index 95% rename from osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/ControlPointPiece.cs rename to osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/PathControlPointPiece.cs index aedde870ca..70156578b4 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/ControlPointPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/PathControlPointPiece.cs @@ -14,7 +14,7 @@ using OpenTK; namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components { - public class ControlPointPiece : CompositeDrawable + public class PathControlPointPiece : CompositeDrawable { private readonly Slider slider; private readonly int index; @@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components [Resolved] private OsuColour colours { get; set; } - public ControlPointPiece(Slider slider, int index) + public PathControlPointPiece(Slider slider, int index) { this.slider = slider; this.index = index; @@ -97,7 +97,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components newControlPoints[index - 1] = newControlPoints[index]; slider.ControlPoints = newControlPoints; - slider.Curve.Calculate(true); + slider.Path.Calculate(true); return true; } diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/ControlPointVisualiser.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/PathControlPointVisualiser.cs similarity index 54% rename from osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/ControlPointVisualiser.cs rename to osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/PathControlPointVisualiser.cs index d8031c4f5b..1d25f8cd39 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/ControlPointVisualiser.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/PathControlPointVisualiser.cs @@ -7,26 +7,26 @@ using osu.Game.Rulesets.Osu.Objects; namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components { - public class ControlPointVisualiser : CompositeDrawable + public class PathControlPointVisualiser : CompositeDrawable { private readonly Slider slider; - private readonly Container pieces; + private readonly Container pieces; - public ControlPointVisualiser(Slider slider) + public PathControlPointVisualiser(Slider slider) { this.slider = slider; - InternalChild = pieces = new Container { RelativeSizeAxes = Axes.Both }; + InternalChild = pieces = new Container { RelativeSizeAxes = Axes.Both }; - slider.ControlPointsChanged += _ => updateControlPoints(); - updateControlPoints(); + slider.ControlPointsChanged += _ => updatePathControlPoints(); + updatePathControlPoints(); } - private void updateControlPoints() + private void updatePathControlPoints() { while (slider.ControlPoints.Length > pieces.Count) - pieces.Add(new ControlPointPiece(slider, pieces.Count)); + pieces.Add(new PathControlPointPiece(slider, pieces.Count)); while (slider.ControlPoints.Length < pieces.Count) pieces.Remove(pieces[pieces.Count - 1]); } diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderCirclePiece.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderCirclePiece.cs index a8565fafb6..7864429d93 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderCirclePiece.cs @@ -25,10 +25,10 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components switch (position) { case SliderPosition.Start: - Position = slider.StackedPosition + slider.Curve.PositionAt(0); + Position = slider.StackedPosition + slider.Path.PositionAt(0); break; case SliderPosition.End: - Position = slider.StackedPosition + slider.Curve.PositionAt(1); + Position = slider.StackedPosition + slider.Path.PositionAt(1); break; } } diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderSelectionMask.cs index 8478374a5f..b79b0ba1fb 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderSelectionMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderSelectionMask.cs @@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks new SliderBodyPiece(sliderObject), headMask = new SliderCircleSelectionMask(slider.HeadCircle, sliderObject, SliderPosition.Start), new SliderCircleSelectionMask(slider.TailCircle, sliderObject, SliderPosition.End), - new ControlPointVisualiser(sliderObject), + new PathControlPointVisualiser(sliderObject), }; } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs b/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs index 1b3725a15e..e01d71e1f8 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs @@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Osu.Mods newControlPoints[i] = new Vector2(slider.ControlPoints[i].X, -slider.ControlPoints[i].Y); slider.ControlPoints = newControlPoints; - slider.Curve?.Calculate(); // Recalculate the slider curve + slider.Path?.Calculate(); // Recalculate the slider curve } } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index 7599001a82..a137343cfe 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -121,7 +121,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables double completionProgress = MathHelper.Clamp((Time.Current - slider.StartTime) / slider.Duration, 0, 1); foreach (var c in components.OfType()) c.UpdateProgress(completionProgress); - foreach (var c in components.OfType()) c.UpdateSnakingPosition(slider.Curve.PositionAt(Body.SnakedStart ?? 0), slider.Curve.PositionAt(Body.SnakedEnd ?? 0)); + foreach (var c in components.OfType()) c.UpdateSnakingPosition(slider.Path.PositionAt(Body.SnakedStart ?? 0), slider.Path.PositionAt(Body.SnakedEnd ?? 0)); foreach (var t in components.OfType()) t.Tracking = Ball.Tracking; Size = Body.Size; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SnakingSliderBody.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SnakingSliderBody.cs index 3d02f9a92d..0e6f3ad16c 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SnakingSliderBody.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SnakingSliderBody.cs @@ -75,7 +75,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces public void Refresh() { // Generate the entire curve - slider.Curve.GetPathToProgress(CurrentCurve, 0, 1); + slider.Path.GetPathToProgress(CurrentCurve, 0, 1); SetVertices(CurrentCurve); // The body is sized to the full path size to avoid excessive autosize computations @@ -103,7 +103,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces SnakedStart = p0; SnakedEnd = p1; - slider.Curve.GetPathToProgress(CurrentCurve, p0, p1); + slider.Path.GetPathToProgress(CurrentCurve, p0, p1); SetVertices(CurrentCurve); diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index de7ba8451b..b7240991d4 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 ControlPointsChanged; - public double EndTime => StartTime + this.SpanCount() * Curve.Distance / Velocity; + public double EndTime => StartTime + this.SpanCount() * Path.Distance / Velocity; public double Duration => EndTime - StartTime; public Vector2 StackedPositionAt(double t) => StackedPosition + this.CurvePositionAt(t); @@ -52,16 +52,16 @@ namespace osu.Game.Rulesets.Osu.Objects } } - public SliderCurve Curve { get; } = new SliderCurve(); + public SliderPath Path { get; } = new SliderPath(); public Vector2[] ControlPoints { - get => Curve.ControlPoints; + get => Path.ControlPoints; set { - if (Curve.ControlPoints == value) + if (Path.ControlPoints == value) return; - Curve.ControlPoints = value; + Path.ControlPoints = value; ControlPointsChanged?.Invoke(value); @@ -70,16 +70,16 @@ namespace osu.Game.Rulesets.Osu.Objects } } - public CurveType CurveType + public PathType PathType { - get { return Curve.CurveType; } - set { Curve.CurveType = value; } + get { return Path.PathType; } + set { Path.PathType = value; } } public double Distance { - get { return Curve.Distance; } - set { Curve.Distance = value; } + get { return Path.Distance; } + set { Path.Distance = value; } } public override Vector2 Position @@ -189,7 +189,7 @@ namespace osu.Game.Rulesets.Osu.Objects private void createTicks() { - var length = Curve.Distance; + var length = Path.Distance; var tickDistance = MathHelper.Clamp(TickDistance, 0, length); if (tickDistance == 0) return; @@ -228,7 +228,7 @@ namespace osu.Game.Rulesets.Osu.Objects SpanIndex = span, SpanStartTime = spanStartTime, StartTime = spanStartTime + timeProgress * SpanDuration, - Position = Position + Curve.PositionAt(distanceProgress), + Position = Position + Path.PositionAt(distanceProgress), StackHeight = StackHeight, Scale = Scale, Samples = sampleList @@ -246,7 +246,7 @@ namespace osu.Game.Rulesets.Osu.Objects RepeatIndex = repeatIndex, SpanDuration = SpanDuration, StartTime = StartTime + repeat * SpanDuration, - Position = Position + Curve.PositionAt(repeat % 2), + Position = Position + Path.PositionAt(repeat % 2), StackHeight = StackHeight, Scale = Scale, Samples = new List(RepeatSamples[repeatIndex]) diff --git a/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs index 9c9fc2e742..85efdca07b 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs @@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch }; } - protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, CurveType curveType, int repeatCount, List> repeatSamples) + protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, PathType pathType, int repeatCount, List> repeatSamples) { newCombo |= forceNewCombo; comboOffset += extraComboOffset; @@ -52,7 +52,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch ComboOffset = comboOffset, ControlPoints = controlPoints, Distance = length, - CurveType = curveType, + PathType = pathType, RepeatSamples = repeatSamples, RepeatCount = repeatCount }; diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs index 965e76d27a..73f70d414f 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs @@ -70,7 +70,7 @@ namespace osu.Game.Rulesets.Objects.Legacy } else if (type.HasFlag(ConvertHitObjectType.Slider)) { - CurveType curveType = CurveType.Catmull; + PathType pathType = PathType.Catmull; double length = 0; string[] pointSplit = split[5].Split('|'); @@ -90,16 +90,16 @@ namespace osu.Game.Rulesets.Objects.Legacy switch (t) { case @"C": - curveType = CurveType.Catmull; + pathType = PathType.Catmull; break; case @"B": - curveType = CurveType.Bezier; + pathType = PathType.Bezier; break; case @"L": - curveType = CurveType.Linear; + pathType = PathType.Linear; break; case @"P": - curveType = CurveType.PerfectCurve; + pathType = PathType.PerfectCurve; break; } @@ -113,8 +113,8 @@ namespace osu.Game.Rulesets.Objects.Legacy // osu-stable special-cased colinear perfect curves to a CurveType.Linear bool isLinear(Vector2[] p) => Precision.AlmostEquals(0, (p[1].Y - p[0].Y) * (p[2].X - p[0].X) - (p[1].X - p[0].X) * (p[2].Y - p[0].Y)); - if (points.Length == 3 && curveType == CurveType.PerfectCurve && isLinear(points)) - curveType = CurveType.Linear; + if (points.Length == 3 && pathType == PathType.PerfectCurve && isLinear(points)) + pathType = PathType.Linear; int repeatCount = Convert.ToInt32(split[6], CultureInfo.InvariantCulture); @@ -178,7 +178,7 @@ namespace osu.Game.Rulesets.Objects.Legacy for (int i = 0; i < nodes; i++) nodeSamples.Add(convertSoundType(nodeSoundTypes[i], nodeBankInfos[i])); - result = CreateSlider(pos, combo, comboOffset, points, length, curveType, repeatCount, nodeSamples); + result = CreateSlider(pos, combo, comboOffset, points, length, pathType, repeatCount, nodeSamples); } else if (type.HasFlag(ConvertHitObjectType.Spinner)) { @@ -268,11 +268,11 @@ namespace osu.Game.Rulesets.Objects.Legacy /// When starting a new combo, the offset of the new combo relative to the current one. /// The slider control points. /// The slider length. - /// The slider curve type. + /// The slider curve type. /// The slider repeat count. /// The samples to be played when the repeat nodes are hit. This includes the head and tail of the slider. /// The hit object. - protected abstract HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, CurveType curveType, int repeatCount, List> repeatSamples); + protected abstract HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, PathType pathType, int repeatCount, List> repeatSamples); /// /// Creates a legacy Spinner-type hit object. diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs index 93c49ea3ce..6030bff427 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs @@ -20,9 +20,9 @@ namespace osu.Game.Rulesets.Objects.Legacy /// /// s don't need a curve since they're converted to ruleset-specific hitobjects. /// - public SliderCurve Curve { get; } = null; + public SliderPath Path { get; } = null; public Vector2[] ControlPoints { get; set; } - public CurveType CurveType { get; set; } + public PathType PathType { get; set; } public double Distance { get; set; } diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs index 68e05f6223..6f10880aa2 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs @@ -26,14 +26,14 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania }; } - protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, CurveType curveType, int repeatCount, List> repeatSamples) + protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, PathType pathType, int repeatCount, List> repeatSamples) { return new ConvertSlider { X = position.X, ControlPoints = controlPoints, Distance = length, - CurveType = curveType, + PathType = pathType, RepeatSamples = repeatSamples, RepeatCount = repeatCount }; diff --git a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs index f3c815fc32..31c200eddc 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs @@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu }; } - protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, CurveType curveType, int repeatCount, List> repeatSamples) + protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, PathType pathType, int repeatCount, List> repeatSamples) { newCombo |= forceNewCombo; comboOffset += extraComboOffset; @@ -53,7 +53,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu ComboOffset = comboOffset, ControlPoints = controlPoints, Distance = Math.Max(0, length), - CurveType = curveType, + PathType = pathType, RepeatSamples = repeatSamples, RepeatCount = repeatCount }; diff --git a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs index 985a032640..0a244bb6c6 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs @@ -23,13 +23,13 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko return new ConvertHit(); } - protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, CurveType curveType, int repeatCount, List> repeatSamples) + protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, PathType pathType, int repeatCount, List> repeatSamples) { return new ConvertSlider { ControlPoints = controlPoints, Distance = length, - CurveType = curveType, + PathType = pathType, RepeatSamples = repeatSamples, RepeatCount = repeatCount }; diff --git a/osu.Game/Rulesets/Objects/SliderCurve.cs b/osu.Game/Rulesets/Objects/SliderPath.cs similarity index 92% rename from osu.Game/Rulesets/Objects/SliderCurve.cs rename to osu.Game/Rulesets/Objects/SliderPath.cs index 6a8192a4f2..46f8cae8a0 100644 --- a/osu.Game/Rulesets/Objects/SliderCurve.cs +++ b/osu.Game/Rulesets/Objects/SliderPath.cs @@ -10,13 +10,13 @@ using OpenTK; namespace osu.Game.Rulesets.Objects { - public class SliderCurve + public class SliderPath { public double Distance; public Vector2[] ControlPoints; - public CurveType CurveType = CurveType.PerfectCurve; + public PathType PathType = PathType.PerfectCurve; public Vector2 Offset; @@ -25,15 +25,15 @@ namespace osu.Game.Rulesets.Objects private List calculateSubpath(ReadOnlySpan subControlPoints) { - switch (CurveType) + switch (PathType) { - case CurveType.Linear: + case PathType.Linear: var result = new List(subControlPoints.Length); foreach (var c in subControlPoints) result.Add(c); return result; - case CurveType.PerfectCurve: + case PathType.PerfectCurve: //we can only use CircularArc iff we have exactly three control points and no dissection. if (ControlPoints.Length != 3 || subControlPoints.Length != 3) break; @@ -46,7 +46,7 @@ namespace osu.Game.Rulesets.Objects break; return subpath; - case CurveType.Catmull: + case PathType.Catmull: return new CatmullApproximator(subControlPoints).CreateCatmull(); } @@ -93,7 +93,7 @@ namespace osu.Game.Rulesets.Objects Vector2 diff = calculatedPath[i + 1] - calculatedPath[i]; double d = diff.Length; - // Shorten slider curves that are too long compared to what's + // Shorten slider paths that are too long compared to what's // in the .osu file. if (Distance - l < d) { @@ -109,7 +109,7 @@ namespace osu.Game.Rulesets.Objects cumulativeLength.Add(l); } - // Lengthen slider curves that are too short compared to what's + // Lengthen slider paths that are too short compared to what's // in the .osu file. if (l < Distance && calculatedPath.Count > 1) { @@ -191,10 +191,10 @@ namespace osu.Game.Rulesets.Objects } /// - /// Computes the slider curve until a given progress that ranges from 0 (beginning of the slider) + /// 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 curve. + /// 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) @@ -219,10 +219,10 @@ namespace osu.Game.Rulesets.Objects } /// - /// Computes the position on the slider at a given progress that ranges from 0 (beginning of the curve) - /// to 1 (end of the curve). + /// 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 curve) to 1 (end of the curve). + /// Ranges from 0 (beginning of the path) to 1 (end of the path). /// public Vector2 PositionAt(double progress) { diff --git a/osu.Game/Rulesets/Objects/Types/IHasCurve.cs b/osu.Game/Rulesets/Objects/Types/IHasCurve.cs index 69b2f722e7..2a0d495e94 100644 --- a/osu.Game/Rulesets/Objects/Types/IHasCurve.cs +++ b/osu.Game/Rulesets/Objects/Types/IHasCurve.cs @@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Objects.Types /// /// The curve. /// - SliderCurve Curve { get; } + SliderPath Path { get; } /// /// The control points that shape the curve. @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Objects.Types /// /// The type of curve. /// - CurveType CurveType { get; } + PathType PathType { get; } } public static class HasCurveExtensions @@ -35,7 +35,7 @@ namespace osu.Game.Rulesets.Objects.Types /// [0, 1] where 0 is the start time of the and 1 is the end time of the . /// The position on the curve. public static Vector2 CurvePositionAt(this IHasCurve obj, double progress) - => obj.Curve.PositionAt(obj.ProgressAt(progress)); + => obj.Path.PositionAt(obj.ProgressAt(progress)); /// /// Computes the progress along the curve relative to how much of the has been completed. diff --git a/osu.Game/Rulesets/Objects/Types/CurveType.cs b/osu.Game/Rulesets/Objects/Types/PathType.cs similarity index 91% rename from osu.Game/Rulesets/Objects/Types/CurveType.cs rename to osu.Game/Rulesets/Objects/Types/PathType.cs index 1cee6202b6..5156302fe1 100644 --- a/osu.Game/Rulesets/Objects/Types/CurveType.cs +++ b/osu.Game/Rulesets/Objects/Types/PathType.cs @@ -3,7 +3,7 @@ namespace osu.Game.Rulesets.Objects.Types { - public enum CurveType + public enum PathType { Catmull, Bezier, From 1aae123ff5b66365e122cb701f23ddc413b57ff7 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 1 Nov 2018 19:00:14 +0900 Subject: [PATCH 236/333] Make approximators share an interface --- .../Masks/SliderMasks/SliderPlacementMask.cs | 4 +- .../Rulesets/Objects/BezierApproximator.cs | 120 +++++++++--------- .../Rulesets/Objects/CatmullApproximator.cs | 11 +- .../Objects/CircularArcApproximator.cs | 11 +- osu.Game/Rulesets/Objects/IApproximator.cs | 19 +++ .../Rulesets/Objects/LinearApproximator.cs | 11 +- osu.Game/Rulesets/Objects/SliderPath.cs | 8 +- 7 files changed, 88 insertions(+), 96 deletions(-) create mode 100644 osu.Game/Rulesets/Objects/IApproximator.cs diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPlacementMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPlacementMask.cs index 37a5251103..1b79b07b58 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPlacementMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPlacementMask.cs @@ -163,10 +163,10 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks { case 1: case 2: - result = new LinearApproximator(allControlPoints).CreateLinear(); + result = new LinearApproximator().Approximate(allControlPoints); break; default: - result = new BezierApproximator(allControlPoints).CreateBezier(); + result = new BezierApproximator().Approximate(allControlPoints); break; } diff --git a/osu.Game/Rulesets/Objects/BezierApproximator.cs b/osu.Game/Rulesets/Objects/BezierApproximator.cs index a1803e32f7..68833b655a 100644 --- a/osu.Game/Rulesets/Objects/BezierApproximator.cs +++ b/osu.Game/Rulesets/Objects/BezierApproximator.cs @@ -7,23 +7,72 @@ using OpenTK; namespace osu.Game.Rulesets.Objects { - public readonly ref struct BezierApproximator + public struct BezierApproximator : IApproximator { - private readonly int count; - private readonly ReadOnlySpan controlPoints; - private readonly Vector2[] subdivisionBuffer1; - private readonly Vector2[] subdivisionBuffer2; - private const float tolerance = 0.25f; private const float tolerance_sq = tolerance * tolerance; - public BezierApproximator(ReadOnlySpan controlPoints) + private int count; + private Vector2[] subdivisionBuffer1; + private Vector2[] subdivisionBuffer2; + + /// + /// Creates a piecewise-linear approximation of a bezier curve, by adaptively repeatedly subdividing + /// the control points until their approximation error vanishes below a given threshold. + /// + /// A list of vectors representing the piecewise-linear approximation. + public List Approximate(ReadOnlySpan controlPoints) { - this.controlPoints = controlPoints; + List output = new List(); count = controlPoints.Length; + if (count == 0) + return output; + subdivisionBuffer1 = new Vector2[count]; subdivisionBuffer2 = new Vector2[count * 2 - 1]; + + Stack toFlatten = new Stack(); + Stack freeBuffers = new Stack(); + + // "toFlatten" contains all the curves which are not yet approximated well enough. + // We use a stack to emulate recursion without the risk of running into a stack overflow. + // (More specifically, we iteratively and adaptively refine our curve with a + // Depth-first search + // over the tree resulting from the subdivisions we make.) + toFlatten.Push(controlPoints.ToArray()); + + Vector2[] leftChild = subdivisionBuffer2; + + while (toFlatten.Count > 0) + { + Vector2[] parent = toFlatten.Pop(); + if (isFlatEnough(parent)) + { + // If the control points we currently operate on are sufficiently "flat", we use + // an extension to De Casteljau's algorithm to obtain a piecewise-linear approximation + // of the bezier curve represented by our control points, consisting of the same amount + // of points as there are control points. + approximate(parent, output); + freeBuffers.Push(parent); + continue; + } + + // If we do not yet have a sufficiently "flat" (in other words, detailed) approximation we keep + // subdividing the curve we are currently operating on. + Vector2[] rightChild = freeBuffers.Count > 0 ? freeBuffers.Pop() : new Vector2[count]; + subdivide(parent, leftChild, rightChild); + + // We re-use the buffer of the parent for one of the children, so that we save one allocation per iteration. + for (int i = 0; i < count; ++i) + parent[i] = leftChild[i]; + + toFlatten.Push(rightChild); + toFlatten.Push(parent); + } + + output.Add(controlPoints[count - 1]); + return output; } /// @@ -92,60 +141,5 @@ namespace osu.Game.Rulesets.Objects output.Add(p); } } - - /// - /// Creates a piecewise-linear approximation of a bezier curve, by adaptively repeatedly subdividing - /// the control points until their approximation error vanishes below a given threshold. - /// - /// A list of vectors representing the piecewise-linear approximation. - public List CreateBezier() - { - List output = new List(); - - if (count == 0) - return output; - - Stack toFlatten = new Stack(); - Stack freeBuffers = new Stack(); - - // "toFlatten" contains all the curves which are not yet approximated well enough. - // We use a stack to emulate recursion without the risk of running into a stack overflow. - // (More specifically, we iteratively and adaptively refine our curve with a - // Depth-first search - // over the tree resulting from the subdivisions we make.) - toFlatten.Push(controlPoints.ToArray()); - - Vector2[] leftChild = subdivisionBuffer2; - - while (toFlatten.Count > 0) - { - Vector2[] parent = toFlatten.Pop(); - if (isFlatEnough(parent)) - { - // If the control points we currently operate on are sufficiently "flat", we use - // an extension to De Casteljau's algorithm to obtain a piecewise-linear approximation - // of the bezier curve represented by our control points, consisting of the same amount - // of points as there are control points. - approximate(parent, output); - freeBuffers.Push(parent); - continue; - } - - // If we do not yet have a sufficiently "flat" (in other words, detailed) approximation we keep - // subdividing the curve we are currently operating on. - Vector2[] rightChild = freeBuffers.Count > 0 ? freeBuffers.Pop() : new Vector2[count]; - subdivide(parent, leftChild, rightChild); - - // We re-use the buffer of the parent for one of the children, so that we save one allocation per iteration. - for (int i = 0; i < count; ++i) - parent[i] = leftChild[i]; - - toFlatten.Push(rightChild); - toFlatten.Push(parent); - } - - output.Add(controlPoints[count - 1]); - return output; - } } } diff --git a/osu.Game/Rulesets/Objects/CatmullApproximator.cs b/osu.Game/Rulesets/Objects/CatmullApproximator.cs index 78f8e471f3..5712b508c4 100644 --- a/osu.Game/Rulesets/Objects/CatmullApproximator.cs +++ b/osu.Game/Rulesets/Objects/CatmullApproximator.cs @@ -7,25 +7,18 @@ using OpenTK; namespace osu.Game.Rulesets.Objects { - public readonly ref struct CatmullApproximator + public readonly struct CatmullApproximator : IApproximator { /// /// The amount of pieces to calculate for each controlpoint quadruplet. /// private const int detail = 50; - private readonly ReadOnlySpan controlPoints; - - public CatmullApproximator(ReadOnlySpan controlPoints) - { - this.controlPoints = controlPoints; - } - /// /// Creates a piecewise-linear approximation of a Catmull-Rom spline. /// /// A list of vectors representing the piecewise-linear approximation. - public List CreateCatmull() + public List Approximate(ReadOnlySpan controlPoints) { var result = new List((controlPoints.Length - 1) * detail * 2); diff --git a/osu.Game/Rulesets/Objects/CircularArcApproximator.cs b/osu.Game/Rulesets/Objects/CircularArcApproximator.cs index 28d7442aaf..969a98c48f 100644 --- a/osu.Game/Rulesets/Objects/CircularArcApproximator.cs +++ b/osu.Game/Rulesets/Objects/CircularArcApproximator.cs @@ -8,22 +8,15 @@ using OpenTK; namespace osu.Game.Rulesets.Objects { - public readonly ref struct CircularArcApproximator + public readonly struct CircularArcApproximator : IApproximator { private const float tolerance = 0.1f; - private readonly ReadOnlySpan controlPoints; - - public CircularArcApproximator(ReadOnlySpan controlPoints) - { - this.controlPoints = controlPoints; - } - /// /// Creates a piecewise-linear approximation of a circular arc curve. /// /// A list of vectors representing the piecewise-linear approximation. - public List CreateArc() + public List Approximate(ReadOnlySpan controlPoints) { Vector2 a = controlPoints[0]; Vector2 b = controlPoints[1]; diff --git a/osu.Game/Rulesets/Objects/IApproximator.cs b/osu.Game/Rulesets/Objects/IApproximator.cs new file mode 100644 index 0000000000..4f242993bc --- /dev/null +++ b/osu.Game/Rulesets/Objects/IApproximator.cs @@ -0,0 +1,19 @@ +// 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 OpenTK; + +namespace osu.Game.Rulesets.Objects +{ + public interface IApproximator + { + /// + /// Approximates a path by interpolating a sequence of control points. + /// + /// The control points of the path. + /// A set of points that lie on the path. + List Approximate(ReadOnlySpan controlPoints); + } +} diff --git a/osu.Game/Rulesets/Objects/LinearApproximator.cs b/osu.Game/Rulesets/Objects/LinearApproximator.cs index c513d40ad6..1f36881fda 100644 --- a/osu.Game/Rulesets/Objects/LinearApproximator.cs +++ b/osu.Game/Rulesets/Objects/LinearApproximator.cs @@ -7,16 +7,9 @@ using OpenTK; namespace osu.Game.Rulesets.Objects { - public readonly ref struct LinearApproximator + public readonly struct LinearApproximator : IApproximator { - private readonly ReadOnlySpan controlPoints; - - public LinearApproximator(ReadOnlySpan controlPoints) - { - this.controlPoints = controlPoints; - } - - public List CreateLinear() + public List Approximate(ReadOnlySpan controlPoints) { var result = new List(controlPoints.Length); diff --git a/osu.Game/Rulesets/Objects/SliderPath.cs b/osu.Game/Rulesets/Objects/SliderPath.cs index 03df2d0106..a141051308 100644 --- a/osu.Game/Rulesets/Objects/SliderPath.cs +++ b/osu.Game/Rulesets/Objects/SliderPath.cs @@ -28,14 +28,14 @@ namespace osu.Game.Rulesets.Objects switch (PathType) { case PathType.Linear: - return new LinearApproximator(subControlPoints).CreateLinear(); + return new LinearApproximator().Approximate(subControlPoints); case PathType.PerfectCurve: //we can only use CircularArc iff we have exactly three control points and no dissection. if (ControlPoints.Length != 3 || subControlPoints.Length != 3) break; // Here we have exactly 3 control points. Attempt to fit a circular arc. - List subpath = new CircularArcApproximator(subControlPoints).CreateArc(); + List subpath = new CircularArcApproximator().Approximate(subControlPoints); // If for some reason a circular arc could not be fit to the 3 given points, fall back to a numerically stable bezier approximation. if (subpath.Count == 0) @@ -43,10 +43,10 @@ namespace osu.Game.Rulesets.Objects return subpath; case PathType.Catmull: - return new CatmullApproximator(subControlPoints).CreateCatmull(); + return new CatmullApproximator().Approximate(subControlPoints); } - return new BezierApproximator(subControlPoints).CreateBezier(); + return new BezierApproximator().Approximate(subControlPoints); } private void calculatePath() From d78348f178c52ec0405a1fe337f5e1d47fee1991 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 1 Nov 2018 19:23:37 +0900 Subject: [PATCH 237/333] Reduce duplicate code --- .../Edit/Masks/SliderMasks/SliderPlacementMask.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPlacementMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPlacementMask.cs index 1b79b07b58..8b38c25bd4 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPlacementMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPlacementMask.cs @@ -107,17 +107,18 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks private void endCurve() { - 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); - + updateSlider(); EndPlacement(); } protected override void Update() { base.Update(); + updateSlider(); + } + private void updateSlider() + { for (int i = 0; i < segments.Count; i++) segments[i].Calculate(i == segments.Count - 1 ? (Vector2?)cursor : null); From 2ac4f2b6af4c101e968441fd94ed6dcf4ca70e10 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 1 Nov 2018 19:24:58 +0900 Subject: [PATCH 238/333] Lock spinners to centre of screen --- .../Masks/SpinnerMasks/SpinnerPlacementMask.cs | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerPlacementMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerPlacementMask.cs index 97356fa8b6..cd5d6cff04 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerPlacementMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerPlacementMask.cs @@ -6,6 +6,7 @@ using osu.Framework.Input.Events; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks.Components; using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.UI; namespace osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks { @@ -18,19 +19,11 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks private bool isPlacingEnd; public SpinnerPlacementMask() - : base(new Spinner()) + : base(new Spinner { Position = OsuPlayfield.BASE_SIZE / 2 }) { InternalChild = piece = new SpinnerPiece(HitObject) { Alpha = 0.5f }; } - protected override void LoadComplete() - { - base.LoadComplete(); - - // Fixes a 1-frame position discrpancy due to the first mouse move event happening in the next frame - HitObject.Position = GetContainingInputManager().CurrentState.Mouse.Position; - } - protected override bool OnClick(ClickEvent e) { if (isPlacingEnd) @@ -48,12 +41,5 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks return true; } - - protected override bool OnMouseMove(MouseMoveEvent e) - { - if (!isPlacingEnd) - HitObject.Position = e.MousePosition; - return true; - } } } From d9e371ccbbe16666ce915b0553dcf6f97f700cdc Mon Sep 17 00:00:00 2001 From: TPGPL Date: Thu, 1 Nov 2018 18:08:12 +0100 Subject: [PATCH 239/333] Add new specs-checking methods --- .github/ISSUE_TEMPLATE/crash-issues.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/crash-issues.md b/.github/ISSUE_TEMPLATE/crash-issues.md index 6c82fdb1d1..849f042c1f 100644 --- a/.github/ISSUE_TEMPLATE/crash-issues.md +++ b/.github/ISSUE_TEMPLATE/crash-issues.md @@ -13,4 +13,4 @@ about: For issues regarding game crashes or permanent freezes **Logs:** -**Computer Specifications:** \ No newline at end of file +**Computer Specifications:** \ No newline at end of file From 0a0023920fd5268a748134489a87a315b9c02e15 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 2 Nov 2018 04:09:33 +0900 Subject: [PATCH 240/333] Fix not being able to drag control points mid-snake --- .../Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs index 3e33ceefcd..0392cb5952 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs @@ -52,7 +52,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers AddMaskFor(obj); } - protected override bool OnMouseDown(MouseDownEvent e) + protected override bool OnClick(ClickEvent e) { maskContainer.DeselectAll(); return true; From 7f1ee3bcb478303719a2c8f8476e1d33083e16dd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 2 Nov 2018 12:06:53 +0900 Subject: [PATCH 241/333] Disallow spinner movement for now --- osu.Game.Rulesets.Osu/Objects/Spinner.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Objects/Spinner.cs b/osu.Game.Rulesets.Osu/Objects/Spinner.cs index 1c60fd4831..1270685ab5 100644 --- a/osu.Game.Rulesets.Osu/Objects/Spinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Spinner.cs @@ -7,6 +7,7 @@ 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 { @@ -31,5 +32,10 @@ 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. + } } } From e6ee3dc73ee7b784929a5635c8412ea161906be1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 2 Nov 2018 02:43:43 +0900 Subject: [PATCH 242/333] Use framework helper functions for path approximation --- .../Masks/SliderMasks/SliderPlacementMask.cs | 6 +- .../Rulesets/Objects/BezierApproximator.cs | 145 ------------------ .../Rulesets/Objects/CatmullApproximator.cs | 63 -------- .../Objects/CircularArcApproximator.cs | 90 ----------- osu.Game/Rulesets/Objects/IApproximator.cs | 19 --- .../Rulesets/Objects/LinearApproximator.cs | 22 --- osu.Game/Rulesets/Objects/SliderPath.cs | 8 +- osu.Game/osu.Game.csproj | 2 +- 8 files changed, 8 insertions(+), 347 deletions(-) delete mode 100644 osu.Game/Rulesets/Objects/BezierApproximator.cs delete mode 100644 osu.Game/Rulesets/Objects/CatmullApproximator.cs delete mode 100644 osu.Game/Rulesets/Objects/CircularArcApproximator.cs delete mode 100644 osu.Game/Rulesets/Objects/IApproximator.cs delete mode 100644 osu.Game/Rulesets/Objects/LinearApproximator.cs diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPlacementMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPlacementMask.cs index 8b38c25bd4..12e768d58e 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPlacementMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPlacementMask.cs @@ -8,9 +8,9 @@ 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.Masks.SliderMasks.Components; using OpenTK; @@ -164,10 +164,10 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks { case 1: case 2: - result = new LinearApproximator().Approximate(allControlPoints); + result = PathApproximator.ApproximateLinear(allControlPoints); break; default: - result = new BezierApproximator().Approximate(allControlPoints); + result = PathApproximator.ApproximateBezier(allControlPoints); break; } diff --git a/osu.Game/Rulesets/Objects/BezierApproximator.cs b/osu.Game/Rulesets/Objects/BezierApproximator.cs deleted file mode 100644 index 68833b655a..0000000000 --- a/osu.Game/Rulesets/Objects/BezierApproximator.cs +++ /dev/null @@ -1,145 +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 OpenTK; - -namespace osu.Game.Rulesets.Objects -{ - public struct BezierApproximator : IApproximator - { - private const float tolerance = 0.25f; - private const float tolerance_sq = tolerance * tolerance; - - private int count; - private Vector2[] subdivisionBuffer1; - private Vector2[] subdivisionBuffer2; - - /// - /// Creates a piecewise-linear approximation of a bezier curve, by adaptively repeatedly subdividing - /// the control points until their approximation error vanishes below a given threshold. - /// - /// A list of vectors representing the piecewise-linear approximation. - public List Approximate(ReadOnlySpan controlPoints) - { - List output = new List(); - count = controlPoints.Length; - - if (count == 0) - return output; - - subdivisionBuffer1 = new Vector2[count]; - subdivisionBuffer2 = new Vector2[count * 2 - 1]; - - Stack toFlatten = new Stack(); - Stack freeBuffers = new Stack(); - - // "toFlatten" contains all the curves which are not yet approximated well enough. - // We use a stack to emulate recursion without the risk of running into a stack overflow. - // (More specifically, we iteratively and adaptively refine our curve with a - // Depth-first search - // over the tree resulting from the subdivisions we make.) - toFlatten.Push(controlPoints.ToArray()); - - Vector2[] leftChild = subdivisionBuffer2; - - while (toFlatten.Count > 0) - { - Vector2[] parent = toFlatten.Pop(); - if (isFlatEnough(parent)) - { - // If the control points we currently operate on are sufficiently "flat", we use - // an extension to De Casteljau's algorithm to obtain a piecewise-linear approximation - // of the bezier curve represented by our control points, consisting of the same amount - // of points as there are control points. - approximate(parent, output); - freeBuffers.Push(parent); - continue; - } - - // If we do not yet have a sufficiently "flat" (in other words, detailed) approximation we keep - // subdividing the curve we are currently operating on. - Vector2[] rightChild = freeBuffers.Count > 0 ? freeBuffers.Pop() : new Vector2[count]; - subdivide(parent, leftChild, rightChild); - - // We re-use the buffer of the parent for one of the children, so that we save one allocation per iteration. - for (int i = 0; i < count; ++i) - parent[i] = leftChild[i]; - - toFlatten.Push(rightChild); - toFlatten.Push(parent); - } - - output.Add(controlPoints[count - 1]); - return output; - } - - /// - /// Make sure the 2nd order derivative (approximated using finite elements) is within tolerable bounds. - /// NOTE: The 2nd order derivative of a 2d curve represents its curvature, so intuitively this function - /// checks (as the name suggests) whether our approximation is _locally_ "flat". More curvy parts - /// need to have a denser approximation to be more "flat". - /// - /// The control points to check for flatness. - /// Whether the control points are flat enough. - private static bool isFlatEnough(Vector2[] controlPoints) - { - for (int i = 1; i < controlPoints.Length - 1; i++) - if ((controlPoints[i - 1] - 2 * controlPoints[i] + controlPoints[i + 1]).LengthSquared > tolerance_sq * 4) - return false; - - return true; - } - - /// - /// Subdivides n control points representing a bezier curve into 2 sets of n control points, each - /// describing a bezier curve equivalent to a half of the original curve. Effectively this splits - /// the original curve into 2 curves which result in the original curve when pieced back together. - /// - /// The control points to split. - /// Output: The control points corresponding to the left half of the curve. - /// Output: The control points corresponding to the right half of the curve. - private void subdivide(Vector2[] controlPoints, Vector2[] l, Vector2[] r) - { - Vector2[] midpoints = subdivisionBuffer1; - - for (int i = 0; i < count; ++i) - midpoints[i] = controlPoints[i]; - - for (int i = 0; i < count; i++) - { - l[i] = midpoints[0]; - r[count - i - 1] = midpoints[count - i - 1]; - - for (int j = 0; j < count - i - 1; j++) - midpoints[j] = (midpoints[j] + midpoints[j + 1]) / 2; - } - } - - /// - /// This uses De Casteljau's algorithm to obtain an optimal - /// piecewise-linear approximation of the bezier curve with the same amount of points as there are control points. - /// - /// The control points describing the bezier curve to be approximated. - /// The points representing the resulting piecewise-linear approximation. - private void approximate(Vector2[] controlPoints, List output) - { - Vector2[] l = subdivisionBuffer2; - Vector2[] r = subdivisionBuffer1; - - subdivide(controlPoints, l, r); - - for (int i = 0; i < count - 1; ++i) - l[count + i] = r[i + 1]; - - output.Add(controlPoints[0]); - for (int i = 1; i < count - 1; ++i) - { - int index = 2 * i; - Vector2 p = 0.25f * (l[index - 1] + 2 * l[index] + l[index + 1]); - output.Add(p); - } - } - } -} diff --git a/osu.Game/Rulesets/Objects/CatmullApproximator.cs b/osu.Game/Rulesets/Objects/CatmullApproximator.cs deleted file mode 100644 index 5712b508c4..0000000000 --- a/osu.Game/Rulesets/Objects/CatmullApproximator.cs +++ /dev/null @@ -1,63 +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 OpenTK; - -namespace osu.Game.Rulesets.Objects -{ - public readonly struct CatmullApproximator : IApproximator - { - /// - /// The amount of pieces to calculate for each controlpoint quadruplet. - /// - private const int detail = 50; - - /// - /// Creates a piecewise-linear approximation of a Catmull-Rom spline. - /// - /// A list of vectors representing the piecewise-linear approximation. - public List Approximate(ReadOnlySpan controlPoints) - { - var result = new List((controlPoints.Length - 1) * detail * 2); - - for (int i = 0; i < controlPoints.Length - 1; i++) - { - var v1 = i > 0 ? controlPoints[i - 1] : controlPoints[i]; - var v2 = controlPoints[i]; - var v3 = i < controlPoints.Length - 1 ? controlPoints[i + 1] : v2 + v2 - v1; - var v4 = i < controlPoints.Length - 2 ? controlPoints[i + 2] : v3 + v3 - v2; - - for (int c = 0; c < detail; c++) - { - result.Add(findPoint(ref v1, ref v2, ref v3, ref v4, (float)c / detail)); - result.Add(findPoint(ref v1, ref v2, ref v3, ref v4, (float)(c + 1) / detail)); - } - } - - return result; - } - - /// - /// Finds a point on the spline at the position of a parameter. - /// - /// The first vector. - /// The second vector. - /// The third vector. - /// The fourth vector. - /// The parameter at which to find the point on the spline, in the range [0, 1]. - /// The point on the spline at . - private Vector2 findPoint(ref Vector2 vec1, ref Vector2 vec2, ref Vector2 vec3, ref Vector2 vec4, float t) - { - float t2 = t * t; - float t3 = t * t2; - - Vector2 result; - result.X = 0.5f * (2f * vec2.X + (-vec1.X + vec3.X) * t + (2f * vec1.X - 5f * vec2.X + 4f * vec3.X - vec4.X) * t2 + (-vec1.X + 3f * vec2.X - 3f * vec3.X + vec4.X) * t3); - result.Y = 0.5f * (2f * vec2.Y + (-vec1.Y + vec3.Y) * t + (2f * vec1.Y - 5f * vec2.Y + 4f * vec3.Y - vec4.Y) * t2 + (-vec1.Y + 3f * vec2.Y - 3f * vec3.Y + vec4.Y) * t3); - - return result; - } - } -} diff --git a/osu.Game/Rulesets/Objects/CircularArcApproximator.cs b/osu.Game/Rulesets/Objects/CircularArcApproximator.cs deleted file mode 100644 index 969a98c48f..0000000000 --- a/osu.Game/Rulesets/Objects/CircularArcApproximator.cs +++ /dev/null @@ -1,90 +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 osu.Framework.MathUtils; -using OpenTK; - -namespace osu.Game.Rulesets.Objects -{ - public readonly struct CircularArcApproximator : IApproximator - { - private const float tolerance = 0.1f; - - /// - /// Creates a piecewise-linear approximation of a circular arc curve. - /// - /// A list of vectors representing the piecewise-linear approximation. - public List Approximate(ReadOnlySpan controlPoints) - { - Vector2 a = controlPoints[0]; - Vector2 b = controlPoints[1]; - Vector2 c = controlPoints[2]; - - float aSq = (b - c).LengthSquared; - float bSq = (a - c).LengthSquared; - float cSq = (a - b).LengthSquared; - - // If we have a degenerate triangle where a side-length is almost zero, then give up and fall - // back to a more numerically stable method. - if (Precision.AlmostEquals(aSq, 0) || Precision.AlmostEquals(bSq, 0) || Precision.AlmostEquals(cSq, 0)) - return new List(); - - float s = aSq * (bSq + cSq - aSq); - float t = bSq * (aSq + cSq - bSq); - float u = cSq * (aSq + bSq - cSq); - - float sum = s + t + u; - - // If we have a degenerate triangle with an almost-zero size, then give up and fall - // back to a more numerically stable method. - if (Precision.AlmostEquals(sum, 0)) - return new List(); - - Vector2 centre = (s * a + t * b + u * c) / sum; - Vector2 dA = a - centre; - Vector2 dC = c - centre; - - float r = dA.Length; - - double thetaStart = Math.Atan2(dA.Y, dA.X); - double thetaEnd = Math.Atan2(dC.Y, dC.X); - - while (thetaEnd < thetaStart) - thetaEnd += 2 * Math.PI; - - double dir = 1; - double thetaRange = thetaEnd - thetaStart; - - // Decide in which direction to draw the circle, depending on which side of - // AC B lies. - Vector2 orthoAtoC = c - a; - orthoAtoC = new Vector2(orthoAtoC.Y, -orthoAtoC.X); - if (Vector2.Dot(orthoAtoC, b - a) < 0) - { - dir = -dir; - thetaRange = 2 * Math.PI - thetaRange; - } - - // We select the amount of points for the approximation by requiring the discrete curvature - // to be smaller than the provided tolerance. The exact angle required to meet the tolerance - // is: 2 * Math.Acos(1 - TOLERANCE / r) - // The special case is required for extremely short sliders where the radius is smaller than - // the tolerance. This is a pathological rather than a realistic case. - int amountPoints = 2 * r <= tolerance ? 2 : Math.Max(2, (int)Math.Ceiling(thetaRange / (2 * Math.Acos(1 - tolerance / r)))); - - List output = new List(amountPoints); - - for (int i = 0; i < amountPoints; ++i) - { - double fract = (double)i / (amountPoints - 1); - double theta = thetaStart + dir * fract * thetaRange; - Vector2 o = new Vector2((float)Math.Cos(theta), (float)Math.Sin(theta)) * r; - output.Add(centre + o); - } - - return output; - } - } -} diff --git a/osu.Game/Rulesets/Objects/IApproximator.cs b/osu.Game/Rulesets/Objects/IApproximator.cs deleted file mode 100644 index 4f242993bc..0000000000 --- a/osu.Game/Rulesets/Objects/IApproximator.cs +++ /dev/null @@ -1,19 +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 OpenTK; - -namespace osu.Game.Rulesets.Objects -{ - public interface IApproximator - { - /// - /// Approximates a path by interpolating a sequence of control points. - /// - /// The control points of the path. - /// A set of points that lie on the path. - List Approximate(ReadOnlySpan controlPoints); - } -} diff --git a/osu.Game/Rulesets/Objects/LinearApproximator.cs b/osu.Game/Rulesets/Objects/LinearApproximator.cs deleted file mode 100644 index 1f36881fda..0000000000 --- a/osu.Game/Rulesets/Objects/LinearApproximator.cs +++ /dev/null @@ -1,22 +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 OpenTK; - -namespace osu.Game.Rulesets.Objects -{ - public readonly struct LinearApproximator : IApproximator - { - public List Approximate(ReadOnlySpan controlPoints) - { - var result = new List(controlPoints.Length); - - foreach (var c in controlPoints) - result.Add(c); - - return result; - } - } -} diff --git a/osu.Game/Rulesets/Objects/SliderPath.cs b/osu.Game/Rulesets/Objects/SliderPath.cs index a141051308..423cd3b069 100644 --- a/osu.Game/Rulesets/Objects/SliderPath.cs +++ b/osu.Game/Rulesets/Objects/SliderPath.cs @@ -28,14 +28,14 @@ namespace osu.Game.Rulesets.Objects switch (PathType) { case PathType.Linear: - return new LinearApproximator().Approximate(subControlPoints); + return PathApproximator.ApproximateLinear(subControlPoints); case PathType.PerfectCurve: //we can only use CircularArc iff we have exactly three control points and no dissection. if (ControlPoints.Length != 3 || subControlPoints.Length != 3) break; // Here we have exactly 3 control points. Attempt to fit a circular arc. - List subpath = new CircularArcApproximator().Approximate(subControlPoints); + List subpath = PathApproximator.ApproximateCircularArc(subControlPoints); // If for some reason a circular arc could not be fit to the 3 given points, fall back to a numerically stable bezier approximation. if (subpath.Count == 0) @@ -43,10 +43,10 @@ namespace osu.Game.Rulesets.Objects return subpath; case PathType.Catmull: - return new CatmullApproximator().Approximate(subControlPoints); + return PathApproximator.ApproximateCatmull(subControlPoints); } - return new BezierApproximator().Approximate(subControlPoints); + return PathApproximator.ApproximateBezier(subControlPoints); } private void calculatePath() diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 2f8c743bee..b4cd8f9b66 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -18,7 +18,7 @@ - + From 4c9dcdf156afc9ab1b45c05db1cbe949311a3b37 Mon Sep 17 00:00:00 2001 From: gotopie Date: Fri, 2 Nov 2018 19:04:30 -0400 Subject: [PATCH 243/333] 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 56ff2686acdd03aa6522106dee9f878d71f2b54c Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Sat, 3 Nov 2018 18:09:11 +0100 Subject: [PATCH 244/333] Update osu-resources and osu-framework to use binary fonts --- 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 c3848d8b1c..9ee64e369f 160000 --- a/osu-resources +++ b/osu-resources @@ -1 +1 @@ -Subproject commit c3848d8b1c84966abe851d915bcca878415614b4 +Subproject commit 9ee64e369fe6fdafc6aed40f5a35b5f01eb82c53 diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index b4cd8f9b66..d953bfd63c 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -18,7 +18,7 @@ - + From 292415140bc8a0e578f9314776c8c8e054c2c43f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 5 Nov 2018 09:45:15 +0900 Subject: [PATCH 245/333] Update template --- .github/ISSUE_TEMPLATE/missing-for-live-issues.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/missing-for-live-issues.md b/.github/ISSUE_TEMPLATE/missing-for-live-issues.md index 929399d192..ae3cf20a8c 100644 --- a/.github/ISSUE_TEMPLATE/missing-for-live-issues.md +++ b/.github/ISSUE_TEMPLATE/missing-for-live-issues.md @@ -1,10 +1,10 @@ --- name: Missing for Live -about: For issues regarding game features required for live +about: Let us know the features you need which are available in osu-stable but not lazer --- **Describe the feature:** -**Designs:** +**Designs:** From 1fffa48aa06b2d593fa18d97e9c04da4948dc9b9 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 5 Nov 2018 12:15:45 +0900 Subject: [PATCH 246/333] Sort nested hitobjects post-creation --- osu.Game/Rulesets/Objects/HitObject.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index f5613e927f..67a3db7a00 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using Newtonsoft.Json; -using osu.Framework.Lists; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; @@ -56,7 +55,7 @@ namespace osu.Game.Rulesets.Objects /// public HitWindows HitWindows { get; set; } - private readonly SortedList nestedHitObjects = new SortedList(compareObjects); + private readonly List nestedHitObjects = new List(); [JsonIgnore] public IReadOnlyList NestedHitObjects => nestedHitObjects; @@ -74,6 +73,8 @@ namespace osu.Game.Rulesets.Objects CreateNestedHitObjects(); + nestedHitObjects.Sort((h1, h2) => h1.StartTime.CompareTo(h2.StartTime)); + foreach (var h in nestedHitObjects) { h.HitWindows = HitWindows; @@ -114,7 +115,5 @@ namespace osu.Game.Rulesets.Objects /// /// protected virtual HitWindows CreateHitWindows() => new HitWindows(); - - private static int compareObjects(HitObject first, HitObject second) => first.StartTime.CompareTo(second.StartTime); } } From 171700cb9117f39598c980d67b563ec81346a45b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 5 Nov 2018 15:59:40 +0900 Subject: [PATCH 247/333] Debounce editor summary timeline seeks --- .../Timelines/Summary/Parts/MarkerPart.cs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs index 4b57e1e92d..11e9ecddc6 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; +using osu.Framework.Threading; using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Graphics; @@ -43,17 +44,23 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts return true; } + private ScheduledDelegate scheduledSeek; + /// /// Seeks the to the time closest to a position on the screen relative to the . /// /// The position in screen coordinates. private void seekToPosition(Vector2 screenPosition) { - if (Beatmap.Value == null) - return; + scheduledSeek?.Cancel(); + scheduledSeek = Schedule(() => + { + if (Beatmap.Value == null) + return; - float markerPos = MathHelper.Clamp(ToLocalSpace(screenPosition).X, 0, DrawWidth); - adjustableClock.Seek(markerPos / DrawWidth * Beatmap.Value.Track.Length); + float markerPos = MathHelper.Clamp(ToLocalSpace(screenPosition).X, 0, DrawWidth); + adjustableClock.Seek(markerPos / DrawWidth * Beatmap.Value.Track.Length); + }); } protected override void Update() From 92d570342c2f1d2bafcae6f7666cfb1564486c0a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 5 Nov 2018 17:35:24 +0900 Subject: [PATCH 248/333] Fix sample additions not falling back to non-addition bank --- .../Beatmaps/Formats/LegacyBeatmapDecoderTest.cs | 13 +++++++++++++ .../Resources/hitobject-no-addition-bank.osu | 4 ++++ .../Objects/Legacy/ConvertHitObjectParser.cs | 2 +- 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Tests/Resources/hitobject-no-addition-bank.osu diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index f1ae366ee1..bd50043ea1 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -333,5 +333,18 @@ namespace osu.Game.Tests.Beatmaps.Formats SampleInfo getTestableSampleInfo(HitObject hitObject) => hitObject.SampleControlPoint.ApplyTo(hitObject.Samples[0]); } + + [Test] + public void TestDecodeHitObjectNullAdditionBank() + { + var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false }; + using (var resStream = Resource.OpenResource("hitobject-no-addition-bank.osu")) + using (var stream = new StreamReader(resStream)) + { + var hitObjects = decoder.Decode(stream).HitObjects; + + Assert.AreEqual(hitObjects[0].Samples[0].Bank, hitObjects[0].Samples[1].Bank); + } + } } } diff --git a/osu.Game.Tests/Resources/hitobject-no-addition-bank.osu b/osu.Game.Tests/Resources/hitobject-no-addition-bank.osu new file mode 100644 index 0000000000..43d0b8cc16 --- /dev/null +++ b/osu.Game.Tests/Resources/hitobject-no-addition-bank.osu @@ -0,0 +1,4 @@ +osu file format v14 + +[HitObjects] +444,320,1000,5,2,3:0:1:0: \ No newline at end of file diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs index 73f70d414f..f109be538b 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs @@ -240,7 +240,7 @@ namespace osu.Game.Rulesets.Objects.Legacy stringAddBank = null; bankInfo.Normal = stringBank; - bankInfo.Add = stringAddBank; + bankInfo.Add = string.IsNullOrEmpty(stringAddBank) ? stringBank : stringAddBank; if (split.Length > 2) bankInfo.CustomSampleBank = int.Parse(split[2]); From 4554fc2c7bb8db588a665ae5a8e0ddd0a088f100 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 5 Nov 2018 18:22:16 +0900 Subject: [PATCH 249/333] Update framework and other dependencies --- .../osu.Game.Rulesets.Catch.Tests.csproj | 2 +- .../osu.Game.Rulesets.Mania.Tests.csproj | 2 +- osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj | 2 +- .../osu.Game.Rulesets.Taiko.Tests.csproj | 2 +- osu.Game.Tests/osu.Game.Tests.csproj | 2 +- osu.Game/osu.Game.csproj | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj index 326791f506..b76f591239 100644 --- a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj +++ b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj @@ -4,7 +4,7 @@ - + diff --git a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj index bf75ebbff8..98ad086c66 100644 --- a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj +++ b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj @@ -4,7 +4,7 @@ - + diff --git a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj index 23c6150b6a..6117812f45 100644 --- a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj +++ b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj @@ -4,7 +4,7 @@ - + diff --git a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj index 6ae9a018c5..3ba64398f3 100644 --- a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj +++ b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj @@ -4,7 +4,7 @@ - + diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 520e0b8940..c0f0695ff8 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -5,7 +5,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index d953bfd63c..c9461ea504 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -18,7 +18,7 @@ - + From 2c4aa5af65cab016729e60aad050dff25af4282a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 6 Nov 2018 16:16:15 +0900 Subject: [PATCH 250/333] Add executable flag to build.sh --- build.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 build.sh diff --git a/build.sh b/build.sh old mode 100644 new mode 100755 From 779e57f0cab8a91c18e4c40c38acb70067ae2a47 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 6 Nov 2018 16:32:11 +0900 Subject: [PATCH 251/333] 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 252/333] 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 253/333] 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 254/333] 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 255/333] 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 256/333] 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 257/333] 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 258/333] 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 259/333] 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 260/333] 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 261/333] 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 262/333] 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 263/333] 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 264/333] 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 265/333] 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 2cffce805aef4f2430328b8c39f6262c94cfe362 Mon Sep 17 00:00:00 2001 From: jorolf Date: Wed, 7 Nov 2018 00:48:54 +0100 Subject: [PATCH 266/333] add flashlight mod --- .../Mods/OsuModFlashlight.cs | 84 ++++++++++++++++++- 1 file changed, 83 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs index a337439593..b6e16ff537 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs @@ -1,12 +1,94 @@ // 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.Graphics; +using osu.Framework.Graphics.OpenGL.Vertices; +using osu.Framework.Graphics.Primitives; +using osu.Framework.Graphics.Shaders; +using osu.Framework.Graphics.Textures; +using osu.Framework.Input; +using osu.Framework.Input.Events; using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.UI; +using OpenTK; namespace osu.Game.Rulesets.Osu.Mods { - public class OsuModFlashlight : ModFlashlight + public class OsuModFlashlight : ModFlashlight, IApplicableToRulesetContainer { public override double ScoreMultiplier => 1.12; + + public void ApplyToRulesetContainer(RulesetContainer rulesetContainer) + { + rulesetContainer.KeyBindingInputManager.Add(new Flashlight + { + RelativeSizeAxes = Axes.Both, + }); + } + + private class Flashlight : Drawable, IRequireHighFrequencyMousePosition + { + private Shader shader; + private readonly MousePositionWrapper mousePosWrapper = new MousePositionWrapper(); + + protected override DrawNode CreateDrawNode() => new FlashlightDrawNode(); + + protected override void ApplyDrawNode(DrawNode node) + { + base.ApplyDrawNode(node); + + var flashNode = (FlashlightDrawNode)node; + + flashNode.Shader = shader; + flashNode.ScreenSpaceDrawQuad = ScreenSpaceDrawQuad; + flashNode.MousePosWrapper = mousePosWrapper; + flashNode.FlashlightSize = 100f; + } + + [BackgroundDependencyLoader] + private void load(ShaderManager shaderManager) + { + shader = shaderManager.Load(VertexShaderDescriptor.POSITION, "Flashlight"); + } + + protected override bool OnMouseMove(MouseMoveEvent e) + { + mousePosWrapper.MousePosition = e.ScreenSpaceMousePosition; + return base.OnMouseMove(e); + } + } + + private class MousePositionWrapper + { + public Vector2 MousePosition; + } + + private class FlashlightDrawNode : DrawNode + { + public Shader Shader; + public Quad ScreenSpaceDrawQuad; + public MousePositionWrapper MousePosWrapper; + public float FlashlightSize; + private bool sizeSet; + + public override void Draw(Action vertexAction) + { + base.Draw(vertexAction); + + Shader.Bind(); + // ReSharper disable once AssignmentInConditionalExpression + if(sizeSet = !sizeSet) + Shader.GetUniform("flashlightSize").UpdateValue(ref FlashlightSize); + + Shader.GetUniform("mousePos").UpdateValue(ref MousePosWrapper.MousePosition); + + Texture.WhitePixel.DrawQuad(ScreenSpaceDrawQuad, DrawColourInfo.Colour, vertexAction: vertexAction); + + Shader.Unbind(); + } + } } } From e9e50f41fbb0f9183d3683050dd0c3292cc9572c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 7 Nov 2018 13:04:17 +0900 Subject: [PATCH 267/333] 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 268/333] 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 269/333] 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 270/333] 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 271/333] 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 5c09662c14640543616937680b00a4da7427f75c Mon Sep 17 00:00:00 2001 From: jorolf Date: Wed, 7 Nov 2018 23:40:33 +0100 Subject: [PATCH 272/333] Allow flashlight size to be variant --- osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs index b6e16ff537..c6b6d67ce6 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs @@ -32,7 +32,10 @@ namespace osu.Game.Rulesets.Osu.Mods private class Flashlight : Drawable, IRequireHighFrequencyMousePosition { private Shader shader; - private readonly MousePositionWrapper mousePosWrapper = new MousePositionWrapper(); + private readonly MousePositionWrapper mousePosWrapper = new MousePositionWrapper + { + FlashlightSize = 300f + }; protected override DrawNode CreateDrawNode() => new FlashlightDrawNode(); @@ -45,7 +48,6 @@ namespace osu.Game.Rulesets.Osu.Mods flashNode.Shader = shader; flashNode.ScreenSpaceDrawQuad = ScreenSpaceDrawQuad; flashNode.MousePosWrapper = mousePosWrapper; - flashNode.FlashlightSize = 100f; } [BackgroundDependencyLoader] @@ -64,6 +66,8 @@ namespace osu.Game.Rulesets.Osu.Mods private class MousePositionWrapper { public Vector2 MousePosition; + public float FlashlightSize; + public bool FlashlightUniformUpdated; } private class FlashlightDrawNode : DrawNode @@ -71,8 +75,6 @@ namespace osu.Game.Rulesets.Osu.Mods public Shader Shader; public Quad ScreenSpaceDrawQuad; public MousePositionWrapper MousePosWrapper; - public float FlashlightSize; - private bool sizeSet; public override void Draw(Action vertexAction) { @@ -80,8 +82,8 @@ namespace osu.Game.Rulesets.Osu.Mods Shader.Bind(); // ReSharper disable once AssignmentInConditionalExpression - if(sizeSet = !sizeSet) - Shader.GetUniform("flashlightSize").UpdateValue(ref FlashlightSize); + if(MousePosWrapper.FlashlightUniformUpdated = !MousePosWrapper.FlashlightUniformUpdated) + Shader.GetUniform("flashlightSize").UpdateValue(ref MousePosWrapper.FlashlightSize); Shader.GetUniform("mousePos").UpdateValue(ref MousePosWrapper.MousePosition); From c6350c6efd20334056406fa2c5c5facb245a7c6b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 7 Nov 2018 16:21:52 +0900 Subject: [PATCH 273/333] 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 274/333] 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 275/333] 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 276/333] 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 277/333] 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 278/333] 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 279/333] 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 280/333] 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 281/333] 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 282/333] 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 283/333] 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 284/333] 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 285/333] 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 286/333] 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 023924396d0005e6acc560014d4c64363e645368 Mon Sep 17 00:00:00 2001 From: jorolf Date: Sun, 11 Nov 2018 18:38:12 +0100 Subject: [PATCH 287/333] Move flashlight code from OsuModFlashlight to ModFlashlight and implement other modes and break time --- .../Mods/CatchModFlashlight.cs | 68 ++++++++- osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs | 8 +- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 2 +- .../Mods/ManiaModFadeIn.cs | 3 +- .../Mods/ManiaModFlashlight.cs | 48 +++++- .../Mods/ManiaModHidden.cs | 3 +- .../Mods/OsuModFlashlight.cs | 98 +++++------- .../Difficulty/TaikoPerformanceCalculator.cs | 4 +- .../Mods/TaikoModFlashlight.cs | 83 +++++++++- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 8 +- osu.Game/Rulesets/Mods/ModFlashlight.cs | 143 +++++++++++++++++- 11 files changed, 388 insertions(+), 80 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs b/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs index 21e09f991c..93e8257913 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs @@ -1,12 +1,78 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using JetBrains.Annotations; +using osu.Framework.Graphics; +using osu.Game.Rulesets.Catch.Objects; +using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Catch.Mods { - public class CatchModFlashlight : ModFlashlight + public class CatchModFlashlight : ModFlashlight { public override double ScoreMultiplier => 1.12; + + private const float default_flashlight_size = 350; + + public override Flashlight CreateFlashlight() => new CatchFlashlight(playfield); + + private CatchPlayfield playfield; + + public override void ApplyToRulesetContainer(RulesetContainer rulesetContainer) + { + playfield = (CatchPlayfield)rulesetContainer.Playfield; + base.ApplyToRulesetContainer(rulesetContainer); + } + + private class CatchFlashlight : Flashlight + { + private readonly CatchPlayfield playfield; + + public CatchFlashlight(CatchPlayfield playfield) + { + this.playfield = playfield; + MousePosWrapper.CircularFlashlightSize = getSizeFor(0); + MousePosWrapper.Rectangular = false; + } + + protected override void Update() + { + base.Update(); + + MousePosWrapper.FlashlightPosition = (playfield.CatcherArea.MovableCatcher.ScreenSpaceDrawQuad.TopLeft + playfield.CatcherArea.MovableCatcher.ScreenSpaceDrawQuad.TopRight) / 2; + MousePosWrapper.FlashlightPositionChanged = true; + } + + [UsedImplicitly] + private float flashlightSize + { + set + { + if (MousePosWrapper.CircularFlashlightSize == value) return; + + MousePosWrapper.CircularFlashlightSize = value; + MousePosWrapper.CircularFlashlightSizeChanged = true; + } + + get => MousePosWrapper.CircularFlashlightSize; + } + + private float getSizeFor(int combo) + { + if (combo > 200) + return default_flashlight_size * 0.8f; + else if (combo > 100) + return default_flashlight_size * 0.9f; + else + return default_flashlight_size; + } + + protected override void OnComboChange(int newCombo) + { + this.TransformTo(nameof(flashlightSize), getSizeFor(newCombo), FLASHLIGHT_FADE_DURATION); + } + } } } diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs index 925e7aaac9..b121d6814b 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Catch.UI { public const float BASE_WIDTH = 512; - private readonly CatcherArea catcherArea; + internal readonly CatcherArea CatcherArea; protected override bool UserScrollSpeedAdjustment => false; @@ -45,7 +45,7 @@ namespace osu.Game.Rulesets.Catch.UI { RelativeSizeAxes = Axes.Both, }, - catcherArea = new CatcherArea(difficulty) + CatcherArea = new CatcherArea(difficulty) { GetVisualRepresentation = getVisualRepresentation, ExplodingFruitTarget = explodingFruitContainer, @@ -59,7 +59,7 @@ namespace osu.Game.Rulesets.Catch.UI VisibleTimeRange.Value = BeatmapDifficulty.DifficultyRange(difficulty.ApproachRate, 1800, 1200, 450); } - public bool CheckIfWeCanCatch(CatchHitObject obj) => catcherArea.AttemptCatch(obj); + public bool CheckIfWeCanCatch(CatchHitObject obj) => CatcherArea.AttemptCatch(obj); public override void Add(DrawableHitObject h) { @@ -72,6 +72,6 @@ namespace osu.Game.Rulesets.Catch.UI } private void onNewResult(DrawableHitObject judgedObject, JudgementResult result) - => catcherArea.OnResult((DrawableCatchHitObject)judgedObject, result); + => CatcherArea.OnResult((DrawableCatchHitObject)judgedObject, result); } } diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index 06453ac32d..8661a3c162 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Catch.UI { public const float CATCHER_SIZE = 100; - protected readonly Catcher MovableCatcher; + protected internal readonly Catcher MovableCatcher; public Func> GetVisualRepresentation; diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs index 08815ede09..73942cbb53 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs @@ -3,6 +3,7 @@ using System; using osu.Game.Graphics; +using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mods; namespace osu.Game.Rulesets.Mania.Mods @@ -16,6 +17,6 @@ namespace osu.Game.Rulesets.Mania.Mods public override string Description => @"Keys appear out of nowhere!"; public override double ScoreMultiplier => 1; public override bool Ranked => true; - public override Type[] IncompatibleMods => new[] { typeof(ModFlashlight) }; + public override Type[] IncompatibleMods => new[] { typeof(ModFlashlight) }; } } diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs index d7a1bc4fbe..be45bb7296 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs @@ -2,13 +2,59 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using osu.Framework.Graphics; +using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mods; +using OpenTK; namespace osu.Game.Rulesets.Mania.Mods { - public class ManiaModFlashlight : ModFlashlight + public class ManiaModFlashlight : ModFlashlight { public override double ScoreMultiplier => 1; public override Type[] IncompatibleMods => new[] { typeof(ModHidden) }; + + private const float default_flashlight_size = 180; + + public override Flashlight CreateFlashlight() => new ManiaFlashlight(); + + private class ManiaFlashlight : Flashlight + { + public ManiaFlashlight() + { + MousePosWrapper.Rectangular = true; + MousePosWrapper.RectangularFlashlightSize = new Vector2(0, default_flashlight_size); + } + + public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true) + { + if ((invalidation & Invalidation.DrawSize) > 0) + { + Schedule(() => + { + MousePosWrapper.RectangularFlashlightSize.X = DrawWidth; + MousePosWrapper.RectangularFlashlightSizeChanged = true; + + MousePosWrapper.FlashlightPosition = ScreenSpaceDrawQuad.Centre; + MousePosWrapper.FlashlightPositionChanged = true; + }); + } + + return base.Invalidate(invalidation, source, shallPropagate); + } + + protected override void OnComboChange(int newCombo) + { + } + + protected override void LoadComplete() + { + MousePosWrapper.RectangularFlashlightSize.X = DrawWidth; + MousePosWrapper.RectangularFlashlightSizeChanged = true; + + MousePosWrapper.FlashlightPosition = ScreenSpaceDrawQuad.Centre; + MousePosWrapper.FlashlightPositionChanged = true; + } + } } } diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs index 2ef68a35fa..9bc2502a8f 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mods; namespace osu.Game.Rulesets.Mania.Mods @@ -10,6 +11,6 @@ namespace osu.Game.Rulesets.Mania.Mods { public override string Description => @"Keys fade out before you hit them!"; public override double ScoreMultiplier => 1; - public override Type[] IncompatibleMods => new[] { typeof(ModFlashlight) }; + public override Type[] IncompatibleMods => new[] { typeof(ModFlashlight) }; } } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs index c6b6d67ce6..a5f803f726 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs @@ -1,95 +1,65 @@ // 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 JetBrains.Annotations; using osu.Framework.Graphics; -using osu.Framework.Graphics.OpenGL.Vertices; -using osu.Framework.Graphics.Primitives; -using osu.Framework.Graphics.Shaders; -using osu.Framework.Graphics.Textures; using osu.Framework.Input; using osu.Framework.Input.Events; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Objects; -using osu.Game.Rulesets.UI; -using OpenTK; namespace osu.Game.Rulesets.Osu.Mods { - public class OsuModFlashlight : ModFlashlight, IApplicableToRulesetContainer + public class OsuModFlashlight : ModFlashlight { public override double ScoreMultiplier => 1.12; - public void ApplyToRulesetContainer(RulesetContainer rulesetContainer) + private const float default_flashlight_size = 180; + + public override Flashlight CreateFlashlight() => new OsuFlashlight(); + + private class OsuFlashlight : Flashlight, IRequireHighFrequencyMousePosition { - rulesetContainer.KeyBindingInputManager.Add(new Flashlight + public OsuFlashlight() { - RelativeSizeAxes = Axes.Both, - }); - } - - private class Flashlight : Drawable, IRequireHighFrequencyMousePosition - { - private Shader shader; - private readonly MousePositionWrapper mousePosWrapper = new MousePositionWrapper - { - FlashlightSize = 300f - }; - - protected override DrawNode CreateDrawNode() => new FlashlightDrawNode(); - - protected override void ApplyDrawNode(DrawNode node) - { - base.ApplyDrawNode(node); - - var flashNode = (FlashlightDrawNode)node; - - flashNode.Shader = shader; - flashNode.ScreenSpaceDrawQuad = ScreenSpaceDrawQuad; - flashNode.MousePosWrapper = mousePosWrapper; - } - - [BackgroundDependencyLoader] - private void load(ShaderManager shaderManager) - { - shader = shaderManager.Load(VertexShaderDescriptor.POSITION, "Flashlight"); + MousePosWrapper.CircularFlashlightSize = getSizeFor(0); + MousePosWrapper.Rectangular = false; } protected override bool OnMouseMove(MouseMoveEvent e) { - mousePosWrapper.MousePosition = e.ScreenSpaceMousePosition; + MousePosWrapper.FlashlightPosition = e.ScreenSpaceMousePosition; + MousePosWrapper.FlashlightPositionChanged = true; return base.OnMouseMove(e); } - } - private class MousePositionWrapper - { - public Vector2 MousePosition; - public float FlashlightSize; - public bool FlashlightUniformUpdated; - } - - private class FlashlightDrawNode : DrawNode - { - public Shader Shader; - public Quad ScreenSpaceDrawQuad; - public MousePositionWrapper MousePosWrapper; - - public override void Draw(Action vertexAction) + [UsedImplicitly] + private float flashlightSize { - base.Draw(vertexAction); + set + { + if (MousePosWrapper.CircularFlashlightSize == value) return; - Shader.Bind(); - // ReSharper disable once AssignmentInConditionalExpression - if(MousePosWrapper.FlashlightUniformUpdated = !MousePosWrapper.FlashlightUniformUpdated) - Shader.GetUniform("flashlightSize").UpdateValue(ref MousePosWrapper.FlashlightSize); + MousePosWrapper.CircularFlashlightSize = value; + MousePosWrapper.CircularFlashlightSizeChanged = true; + } - Shader.GetUniform("mousePos").UpdateValue(ref MousePosWrapper.MousePosition); + get => MousePosWrapper.CircularFlashlightSize; + } - Texture.WhitePixel.DrawQuad(ScreenSpaceDrawQuad, DrawColourInfo.Colour, vertexAction: vertexAction); + private float getSizeFor(int combo) + { + if (combo > 200) + return default_flashlight_size * 0.8f; + else if (combo > 100) + return default_flashlight_size * 0.9f; + else + return default_flashlight_size; + } - Shader.Unbind(); + protected override void OnComboChange(int newCombo) + { + this.TransformTo(nameof(flashlightSize), getSizeFor(newCombo), FLASHLIGHT_FADE_DURATION); } } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs index f530b6725c..86dd37b476 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs @@ -8,6 +8,8 @@ using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.Taiko.Mods; +using osu.Game.Rulesets.Taiko.Objects; namespace osu.Game.Rulesets.Taiko.Difficulty { @@ -82,7 +84,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty if (mods.Any(m => m is ModHidden)) strainValue *= 1.025; - if (mods.Any(m => m is ModFlashlight)) + if (mods.Any(m => m is ModFlashlight)) // Apply length bonus again if flashlight is on simply because it becomes a lot harder on longer maps. strainValue *= 1.05 * lengthBonus; diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs index 49f7786f59..8e14f24bb3 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs @@ -1,12 +1,93 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using JetBrains.Annotations; +using osu.Framework.Graphics; +using osu.Framework.Input; using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.Taiko.UI; +using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Taiko.Mods { - public class TaikoModFlashlight : ModFlashlight + public class TaikoModFlashlight : ModFlashlight { public override double ScoreMultiplier => 1.12; + + private const float default_flashlight_size = 250; + + public override Flashlight CreateFlashlight() => new TaikoFlashlight(playfield); + + private TaikoPlayfield playfield; + + public override void ApplyToRulesetContainer(RulesetContainer rulesetContainer) + { + playfield = (TaikoPlayfield)rulesetContainer.Playfield; + base.ApplyToRulesetContainer(rulesetContainer); + } + + private class TaikoFlashlight : Flashlight + { + private readonly TaikoPlayfield taikoPlayfield; + + public TaikoFlashlight(TaikoPlayfield taikoPlayfield) + { + this.taikoPlayfield = taikoPlayfield; + MousePosWrapper.CircularFlashlightSize = getSizeFor(0); + MousePosWrapper.Rectangular = false; + } + + [UsedImplicitly] + private float flashlightSize + { + set + { + if (MousePosWrapper.CircularFlashlightSize == value) return; + + MousePosWrapper.CircularFlashlightSize = value; + MousePosWrapper.CircularFlashlightSizeChanged = true; + } + + get => MousePosWrapper.CircularFlashlightSize; + } + + private float getSizeFor(int combo) + { + if (combo > 200) + return default_flashlight_size * 0.8f; + else if (combo > 100) + return default_flashlight_size * 0.9f; + else + return default_flashlight_size; + } + + protected override void OnComboChange(int newCombo) + { + this.TransformTo(nameof(flashlightSize), getSizeFor(newCombo), FLASHLIGHT_FADE_DURATION); + } + + public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true) + { + if ((invalidation & Invalidation.DrawSize) > 0) + { + Schedule(() => + { + MousePosWrapper.FlashlightPosition = taikoPlayfield.HitExplosionContainer.ScreenSpaceDrawQuad.Centre; + MousePosWrapper.FlashlightPositionChanged = true; + }); + } + + return base.Invalidate(invalidation, source, shallPropagate); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + MousePosWrapper.FlashlightPosition = taikoPlayfield.HitExplosionContainer.ScreenSpaceDrawQuad.Centre; + MousePosWrapper.FlashlightPositionChanged = true; + } + } } } diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 40ed659bd6..5e1593638c 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -43,7 +43,7 @@ namespace osu.Game.Rulesets.Taiko.UI protected override SpeedChangeVisualisationMethod VisualisationMethod => SpeedChangeVisualisationMethod.Overlapping; - private readonly Container hitExplosionContainer; + internal readonly Container HitExplosionContainer; private readonly Container kiaiExplosionContainer; private readonly JudgementContainer judgementContainer; @@ -103,7 +103,7 @@ namespace osu.Game.Rulesets.Taiko.UI Masking = true, Children = new Drawable[] { - hitExplosionContainer = new Container + HitExplosionContainer = new Container { RelativeSizeAxes = Axes.Both, FillMode = FillMode.Fit, @@ -243,7 +243,7 @@ namespace osu.Game.Rulesets.Taiko.UI { case TaikoStrongJudgement _: if (result.IsHit) - hitExplosionContainer.Children.FirstOrDefault(e => e.JudgedObject == ((DrawableStrongNestedHit)judgedObject).MainObject)?.VisualiseSecondHit(); + HitExplosionContainer.Children.FirstOrDefault(e => e.JudgedObject == ((DrawableStrongNestedHit)judgedObject).MainObject)?.VisualiseSecondHit(); break; default: judgementContainer.Add(new DrawableTaikoJudgement(result, judgedObject) @@ -259,7 +259,7 @@ namespace osu.Game.Rulesets.Taiko.UI bool isRim = judgedObject.HitObject is RimHit; - hitExplosionContainer.Add(new HitExplosion(judgedObject, isRim)); + HitExplosionContainer.Add(new HitExplosion(judgedObject, isRim)); if (judgedObject.HitObject.Kiai) kiaiExplosionContainer.Add(new KiaiHitExplosion(judgedObject, isRim)); diff --git a/osu.Game/Rulesets/Mods/ModFlashlight.cs b/osu.Game/Rulesets/Mods/ModFlashlight.cs index 223263195c..a99f4e81fb 100644 --- a/osu.Game/Rulesets/Mods/ModFlashlight.cs +++ b/osu.Game/Rulesets/Mods/ModFlashlight.cs @@ -1,11 +1,27 @@ // 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.Allocation; +using osu.Framework.Configuration; +using osu.Framework.Graphics; +using osu.Framework.Graphics.OpenGL.Vertices; +using osu.Framework.Graphics.Primitives; +using osu.Framework.Graphics.Shaders; +using osu.Framework.Graphics.Textures; +using osu.Game.Beatmaps.Timing; using osu.Game.Graphics; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.UI; +using OpenTK; +using OpenTK.Graphics; namespace osu.Game.Rulesets.Mods { - public abstract class ModFlashlight : Mod + public abstract class ModFlashlight : Mod, IApplicableToRulesetContainer, IApplicableToScoreProcessor + where T : HitObject { public override string Name => "Flashlight"; public override string ShortenedName => "FL"; @@ -13,5 +29,130 @@ namespace osu.Game.Rulesets.Mods public override ModType Type => ModType.DifficultyIncrease; public override string Description => "Restricted view area."; public override bool Ranked => true; + + public const double FLASHLIGHT_FADE_DURATION = 800; + protected readonly BindableInt Combo = new BindableInt(); + + public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor) + { + Combo.BindTo(scoreProcessor.Combo); + } + + public virtual void ApplyToRulesetContainer(RulesetContainer rulesetContainer) + { + var flashlight = CreateFlashlight(); + flashlight.Combo = Combo; + flashlight.RelativeSizeAxes = Axes.Both; + flashlight.Colour = Color4.Black; + rulesetContainer.KeyBindingInputManager.Add(flashlight); + + flashlight.Breaks = rulesetContainer.Beatmap.Breaks; + } + + public abstract Flashlight CreateFlashlight(); + + public abstract class Flashlight : Drawable + { + internal BindableInt Combo; + private Shader shader; + protected readonly FlashlightUniformWrapper MousePosWrapper = new FlashlightUniformWrapper(); + + protected override DrawNode CreateDrawNode() => new FlashlightDrawNode(); + + public override bool RemoveCompletedTransforms => false; + + public List Breaks; + + protected override void ApplyDrawNode(DrawNode node) + { + base.ApplyDrawNode(node); + + var flashNode = (FlashlightDrawNode)node; + + flashNode.Shader = shader; + flashNode.ScreenSpaceDrawQuad = ScreenSpaceDrawQuad; + flashNode.MousePosWrapper = MousePosWrapper; + } + + [BackgroundDependencyLoader] + private void load(ShaderManager shaderManager) + { + shader = shaderManager.Load("PositionAndColour", "Flashlight"); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + Combo.ValueChanged += OnComboChange; + + this.FadeInFromZero(FLASHLIGHT_FADE_DURATION); + + foreach (var breakPeriod in Breaks) + { + this.Delay(breakPeriod.StartTime + FLASHLIGHT_FADE_DURATION).FadeOutFromOne(FLASHLIGHT_FADE_DURATION); + this.Delay(breakPeriod.EndTime - FLASHLIGHT_FADE_DURATION).FadeInFromZero(FLASHLIGHT_FADE_DURATION); + } + } + + protected abstract void OnComboChange(int newCombo); + } + + public class FlashlightUniformWrapper + { + public bool Rectangular; + public bool RectangularChanged = true; + + public Vector2 FlashlightPosition; + public bool FlashlightPositionChanged = true; + + public float CircularFlashlightSize; + public bool CircularFlashlightSizeChanged = true; + + public Vector2 RectangularFlashlightSize; + public bool RectangularFlashlightSizeChanged = true; + } + + private class FlashlightDrawNode : DrawNode + { + public Shader Shader; + public Quad ScreenSpaceDrawQuad; + public FlashlightUniformWrapper MousePosWrapper; + + public override void Draw(Action vertexAction) + { + base.Draw(vertexAction); + + Shader.Bind(); + + if (MousePosWrapper.RectangularChanged) + { + Shader.GetUniform("rectangular").UpdateValue(ref MousePosWrapper.Rectangular); + MousePosWrapper.RectangularChanged = false; + } + + if (MousePosWrapper.FlashlightPositionChanged) + { + Shader.GetUniform("flashlightPos").UpdateValue(ref MousePosWrapper.FlashlightPosition); + MousePosWrapper.FlashlightPositionChanged = false; + } + + if (MousePosWrapper.CircularFlashlightSizeChanged) + { + Shader.GetUniform("circularFlashlightSize").UpdateValue(ref MousePosWrapper.CircularFlashlightSize); + MousePosWrapper.CircularFlashlightSizeChanged = false; + } + + if (MousePosWrapper.RectangularFlashlightSizeChanged) + { + Shader.GetUniform("rectangularFlashlightSize").UpdateValue(ref MousePosWrapper.RectangularFlashlightSize); + MousePosWrapper.RectangularFlashlightSizeChanged = false; + } + + Texture.WhitePixel.DrawQuad(ScreenSpaceDrawQuad, DrawColourInfo.Colour, vertexAction: vertexAction); + + Shader.Unbind(); + } + } } } From 54ab256c8e01e369ae664408e29e25f5161e12e5 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 1 Nov 2018 15:38:19 +0900 Subject: [PATCH 288/333] 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 289/333] 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 290/333] 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 291/333] 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 292/333] 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 293/333] 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 294/333] 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 295/333] 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 296/333] 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 297/333] 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 298/333] 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 299/333] 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 300/333] 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 301/333] 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 302/333] 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 303/333] 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 304/333] 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 305/333] 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 306/333] 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 307/333] 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 308/333] 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 309/333] 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 310/333] 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 311/333] 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 312/333] 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 313/333] 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 314/333] 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 315/333] 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 316/333] 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 317/333] 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 318/333] 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 319/333] 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 320/333] 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 321/333] 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 322/333] 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 323/333] 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 324/333] 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 325/333] 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 326/333] 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 327/333] 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 328/333] 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 @@ - + From 9dd3d28436e9b2fd44b3de3117654e7d89f3d0d9 Mon Sep 17 00:00:00 2001 From: HoLLy Date: Wed, 14 Nov 2018 22:29:11 +0100 Subject: [PATCH 329/333] Fix SettingsTextBox having width of 0 --- osu.Game/Overlays/Settings/SettingsTextBox.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Settings/SettingsTextBox.cs b/osu.Game/Overlays/Settings/SettingsTextBox.cs index ce9218bbe7..fbfb5481c5 100644 --- a/osu.Game/Overlays/Settings/SettingsTextBox.cs +++ b/osu.Game/Overlays/Settings/SettingsTextBox.cs @@ -8,6 +8,10 @@ namespace osu.Game.Overlays.Settings { public class SettingsTextBox : SettingsItem { - protected override Drawable CreateControl() => new OsuTextBox(); + protected override Drawable CreateControl() => new OsuTextBox + { + Margin = new MarginPadding { Top = 5 }, + RelativeSizeAxes = Axes.X, + }; } } From 7d2958b7b0f35cce6655dc7248909c7d9278d687 Mon Sep 17 00:00:00 2001 From: jorolf Date: Thu, 15 Nov 2018 00:33:13 +0100 Subject: [PATCH 330/333] split shader, remove unnecessary clutter and fix some bugs --- .../Mods/CatchModFlashlight.cs | 26 ++----- .../Mods/ManiaModFlashlight.cs | 17 ++--- .../Mods/OsuModFlashlight.cs | 26 ++----- .../Mods/TaikoModFlashlight.cs | 30 ++------ osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 11 +-- osu.Game/Rulesets/Mods/ModFlashlight.cs | 74 +++++++++---------- 6 files changed, 70 insertions(+), 114 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs b/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs index 93e8257913..8645730d09 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.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 JetBrains.Annotations; using osu.Framework.Graphics; using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.UI; +using OpenTK; namespace osu.Game.Rulesets.Catch.Mods { @@ -33,30 +33,16 @@ namespace osu.Game.Rulesets.Catch.Mods public CatchFlashlight(CatchPlayfield playfield) { this.playfield = playfield; - MousePosWrapper.CircularFlashlightSize = getSizeFor(0); - MousePosWrapper.Rectangular = false; + FlashlightSize = new Vector2(0, getSizeFor(0)); } protected override void Update() { base.Update(); - MousePosWrapper.FlashlightPosition = (playfield.CatcherArea.MovableCatcher.ScreenSpaceDrawQuad.TopLeft + playfield.CatcherArea.MovableCatcher.ScreenSpaceDrawQuad.TopRight) / 2; - MousePosWrapper.FlashlightPositionChanged = true; - } + var catcher = playfield.CatcherArea.MovableCatcher; - [UsedImplicitly] - private float flashlightSize - { - set - { - if (MousePosWrapper.CircularFlashlightSize == value) return; - - MousePosWrapper.CircularFlashlightSize = value; - MousePosWrapper.CircularFlashlightSizeChanged = true; - } - - get => MousePosWrapper.CircularFlashlightSize; + FlashlightPosition = catcher.ToSpaceOfOtherDrawable(catcher.Position, this); } private float getSizeFor(int combo) @@ -71,8 +57,10 @@ namespace osu.Game.Rulesets.Catch.Mods protected override void OnComboChange(int newCombo) { - this.TransformTo(nameof(flashlightSize), getSizeFor(newCombo), FLASHLIGHT_FADE_DURATION); + this.TransformTo(nameof(FlashlightSize), new Vector2(0, getSizeFor(newCombo)), FLASHLIGHT_FADE_DURATION); } + + protected override string FragmentShader => "CircularFlashlight"; } } } diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs index be45bb7296..32ac668f69 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs @@ -22,8 +22,7 @@ namespace osu.Game.Rulesets.Mania.Mods { public ManiaFlashlight() { - MousePosWrapper.Rectangular = true; - MousePosWrapper.RectangularFlashlightSize = new Vector2(0, default_flashlight_size); + FlashlightSize = new Vector2(0, default_flashlight_size); } public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true) @@ -32,11 +31,9 @@ namespace osu.Game.Rulesets.Mania.Mods { Schedule(() => { - MousePosWrapper.RectangularFlashlightSize.X = DrawWidth; - MousePosWrapper.RectangularFlashlightSizeChanged = true; + FlashlightSize = new Vector2(DrawWidth, FlashlightSize.Y); - MousePosWrapper.FlashlightPosition = ScreenSpaceDrawQuad.Centre; - MousePosWrapper.FlashlightPositionChanged = true; + FlashlightPosition = DrawPosition + DrawSize / 2; }); } @@ -47,13 +44,13 @@ namespace osu.Game.Rulesets.Mania.Mods { } + protected override string FragmentShader => "RectangularFlashlight"; + protected override void LoadComplete() { - MousePosWrapper.RectangularFlashlightSize.X = DrawWidth; - MousePosWrapper.RectangularFlashlightSizeChanged = true; + FlashlightSize = new Vector2(DrawWidth, FlashlightSize.Y); - MousePosWrapper.FlashlightPosition = ScreenSpaceDrawQuad.Centre; - MousePosWrapper.FlashlightPositionChanged = true; + FlashlightPosition = DrawPosition + DrawSize / 2; } } } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs index a5f803f726..f425b3c53d 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.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 JetBrains.Annotations; using osu.Framework.Graphics; using osu.Framework.Input; using osu.Framework.Input.Events; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Objects; +using OpenTK; namespace osu.Game.Rulesets.Osu.Mods { @@ -22,31 +22,15 @@ namespace osu.Game.Rulesets.Osu.Mods { public OsuFlashlight() { - MousePosWrapper.CircularFlashlightSize = getSizeFor(0); - MousePosWrapper.Rectangular = false; + FlashlightSize = new Vector2(0, getSizeFor(0)); } protected override bool OnMouseMove(MouseMoveEvent e) { - MousePosWrapper.FlashlightPosition = e.ScreenSpaceMousePosition; - MousePosWrapper.FlashlightPositionChanged = true; + FlashlightPosition = e.MousePosition; return base.OnMouseMove(e); } - [UsedImplicitly] - private float flashlightSize - { - set - { - if (MousePosWrapper.CircularFlashlightSize == value) return; - - MousePosWrapper.CircularFlashlightSize = value; - MousePosWrapper.CircularFlashlightSizeChanged = true; - } - - get => MousePosWrapper.CircularFlashlightSize; - } - private float getSizeFor(int combo) { if (combo > 200) @@ -59,8 +43,10 @@ namespace osu.Game.Rulesets.Osu.Mods protected override void OnComboChange(int newCombo) { - this.TransformTo(nameof(flashlightSize), getSizeFor(newCombo), FLASHLIGHT_FADE_DURATION); + this.TransformTo(nameof(FlashlightSize), new Vector2(0, getSizeFor(newCombo)), FLASHLIGHT_FADE_DURATION); } + + protected override string FragmentShader => "CircularFlashlight"; } } } diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs index 8e14f24bb3..a58d55f904 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs @@ -1,13 +1,12 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using JetBrains.Annotations; using osu.Framework.Graphics; -using osu.Framework.Input; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Rulesets.Taiko.UI; using osu.Game.Rulesets.UI; +using OpenTK; namespace osu.Game.Rulesets.Taiko.Mods { @@ -34,22 +33,7 @@ namespace osu.Game.Rulesets.Taiko.Mods public TaikoFlashlight(TaikoPlayfield taikoPlayfield) { this.taikoPlayfield = taikoPlayfield; - MousePosWrapper.CircularFlashlightSize = getSizeFor(0); - MousePosWrapper.Rectangular = false; - } - - [UsedImplicitly] - private float flashlightSize - { - set - { - if (MousePosWrapper.CircularFlashlightSize == value) return; - - MousePosWrapper.CircularFlashlightSize = value; - MousePosWrapper.CircularFlashlightSizeChanged = true; - } - - get => MousePosWrapper.CircularFlashlightSize; + FlashlightSize = new Vector2(0, getSizeFor(0)); } private float getSizeFor(int combo) @@ -64,17 +48,18 @@ namespace osu.Game.Rulesets.Taiko.Mods protected override void OnComboChange(int newCombo) { - this.TransformTo(nameof(flashlightSize), getSizeFor(newCombo), FLASHLIGHT_FADE_DURATION); + this.TransformTo(nameof(FlashlightSize), new Vector2(0, getSizeFor(newCombo)), FLASHLIGHT_FADE_DURATION); } + protected override string FragmentShader => "CircularFlashlight"; + public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true) { if ((invalidation & Invalidation.DrawSize) > 0) { Schedule(() => { - MousePosWrapper.FlashlightPosition = taikoPlayfield.HitExplosionContainer.ScreenSpaceDrawQuad.Centre; - MousePosWrapper.FlashlightPositionChanged = true; + FlashlightPosition = taikoPlayfield.HitTarget.ToSpaceOfOtherDrawable(taikoPlayfield.HitTarget.OriginPosition, this); }); } @@ -85,8 +70,7 @@ namespace osu.Game.Rulesets.Taiko.Mods { base.LoadComplete(); - MousePosWrapper.FlashlightPosition = taikoPlayfield.HitExplosionContainer.ScreenSpaceDrawQuad.Centre; - MousePosWrapper.FlashlightPositionChanged = true; + FlashlightPosition = taikoPlayfield.HitTarget.ToSpaceOfOtherDrawable(taikoPlayfield.HitTarget.OriginPosition, this); } } } diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 5e1593638c..a1a2b1b88e 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -43,9 +43,10 @@ namespace osu.Game.Rulesets.Taiko.UI protected override SpeedChangeVisualisationMethod VisualisationMethod => SpeedChangeVisualisationMethod.Overlapping; - internal readonly Container HitExplosionContainer; + private readonly Container hitExplosionContainer; private readonly Container kiaiExplosionContainer; private readonly JudgementContainer judgementContainer; + internal readonly HitTarget HitTarget; private readonly Container topLevelHitContainer; @@ -103,13 +104,13 @@ namespace osu.Game.Rulesets.Taiko.UI Masking = true, Children = new Drawable[] { - HitExplosionContainer = new Container + hitExplosionContainer = new Container { RelativeSizeAxes = Axes.Both, FillMode = FillMode.Fit, Blending = BlendingMode.Additive, }, - new HitTarget + HitTarget = new HitTarget { Anchor = Anchor.CentreLeft, Origin = Anchor.Centre, @@ -243,7 +244,7 @@ namespace osu.Game.Rulesets.Taiko.UI { case TaikoStrongJudgement _: if (result.IsHit) - HitExplosionContainer.Children.FirstOrDefault(e => e.JudgedObject == ((DrawableStrongNestedHit)judgedObject).MainObject)?.VisualiseSecondHit(); + hitExplosionContainer.Children.FirstOrDefault(e => e.JudgedObject == ((DrawableStrongNestedHit)judgedObject).MainObject)?.VisualiseSecondHit(); break; default: judgementContainer.Add(new DrawableTaikoJudgement(result, judgedObject) @@ -259,7 +260,7 @@ namespace osu.Game.Rulesets.Taiko.UI bool isRim = judgedObject.HitObject is RimHit; - HitExplosionContainer.Add(new HitExplosion(judgedObject, isRim)); + hitExplosionContainer.Add(new HitExplosion(judgedObject, isRim)); if (judgedObject.HitObject.Kiai) kiaiExplosionContainer.Add(new KiaiHitExplosion(judgedObject, isRim)); diff --git a/osu.Game/Rulesets/Mods/ModFlashlight.cs b/osu.Game/Rulesets/Mods/ModFlashlight.cs index a99f4e81fb..2063f5cf88 100644 --- a/osu.Game/Rulesets/Mods/ModFlashlight.cs +++ b/osu.Game/Rulesets/Mods/ModFlashlight.cs @@ -55,7 +55,6 @@ namespace osu.Game.Rulesets.Mods { internal BindableInt Combo; private Shader shader; - protected readonly FlashlightUniformWrapper MousePosWrapper = new FlashlightUniformWrapper(); protected override DrawNode CreateDrawNode() => new FlashlightDrawNode(); @@ -71,13 +70,14 @@ namespace osu.Game.Rulesets.Mods flashNode.Shader = shader; flashNode.ScreenSpaceDrawQuad = ScreenSpaceDrawQuad; - flashNode.MousePosWrapper = MousePosWrapper; + flashNode.MousePosWrapper.FlashlightPosition = Vector2Extensions.Transform(FlashlightPosition, DrawInfo.Matrix); + flashNode.MousePosWrapper.FlashlightSize = Vector2Extensions.Transform(FlashlightSize, DrawInfo.Matrix); } [BackgroundDependencyLoader] private void load(ShaderManager shaderManager) { - shader = shaderManager.Load("PositionAndColour", "Flashlight"); + shader = shaderManager.Load("PositionAndColour", FragmentShader); } protected override void LoadComplete() @@ -90,27 +90,48 @@ namespace osu.Game.Rulesets.Mods foreach (var breakPeriod in Breaks) { + if (breakPeriod.Duration < FLASHLIGHT_FADE_DURATION * 2) continue; + this.Delay(breakPeriod.StartTime + FLASHLIGHT_FADE_DURATION).FadeOutFromOne(FLASHLIGHT_FADE_DURATION); this.Delay(breakPeriod.EndTime - FLASHLIGHT_FADE_DURATION).FadeInFromZero(FLASHLIGHT_FADE_DURATION); } } protected abstract void OnComboChange(int newCombo); + + protected abstract string FragmentShader { get; } + + private Vector2 flashlightPosition; + protected Vector2 FlashlightPosition + { + get => flashlightPosition; + set + { + if (flashlightPosition == value) return; + + flashlightPosition = value; + Invalidate(Invalidation.DrawNode); + } + } + + private Vector2 flashlightSize; + protected Vector2 FlashlightSize + { + get => flashlightSize; + set + { + if (flashlightSize == value) return; + + flashlightSize = value; + Invalidate(Invalidation.DrawNode); + } + } } - public class FlashlightUniformWrapper + public struct FlashlightUniformWrapper { - public bool Rectangular; - public bool RectangularChanged = true; - public Vector2 FlashlightPosition; - public bool FlashlightPositionChanged = true; - - public float CircularFlashlightSize; - public bool CircularFlashlightSizeChanged = true; - - public Vector2 RectangularFlashlightSize; - public bool RectangularFlashlightSizeChanged = true; + public Vector2 FlashlightSize; } private class FlashlightDrawNode : DrawNode @@ -125,29 +146,8 @@ namespace osu.Game.Rulesets.Mods Shader.Bind(); - if (MousePosWrapper.RectangularChanged) - { - Shader.GetUniform("rectangular").UpdateValue(ref MousePosWrapper.Rectangular); - MousePosWrapper.RectangularChanged = false; - } - - if (MousePosWrapper.FlashlightPositionChanged) - { - Shader.GetUniform("flashlightPos").UpdateValue(ref MousePosWrapper.FlashlightPosition); - MousePosWrapper.FlashlightPositionChanged = false; - } - - if (MousePosWrapper.CircularFlashlightSizeChanged) - { - Shader.GetUniform("circularFlashlightSize").UpdateValue(ref MousePosWrapper.CircularFlashlightSize); - MousePosWrapper.CircularFlashlightSizeChanged = false; - } - - if (MousePosWrapper.RectangularFlashlightSizeChanged) - { - Shader.GetUniform("rectangularFlashlightSize").UpdateValue(ref MousePosWrapper.RectangularFlashlightSize); - MousePosWrapper.RectangularFlashlightSizeChanged = false; - } + Shader.GetUniform("flashlightPos").UpdateValue(ref MousePosWrapper.FlashlightPosition); + Shader.GetUniform("flashlightSize").UpdateValue(ref MousePosWrapper.FlashlightSize); Texture.WhitePixel.DrawQuad(ScreenSpaceDrawQuad, DrawColourInfo.Colour, vertexAction: vertexAction); From f0f7b15edcd1a7715ec7aeb7baf14fa737543cd3 Mon Sep 17 00:00:00 2001 From: jorolf Date: Thu, 15 Nov 2018 00:45:27 +0100 Subject: [PATCH 331/333] remove unused using --- osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs index 86dd37b476..734d5d0ad7 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs @@ -8,7 +8,6 @@ using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; -using osu.Game.Rulesets.Taiko.Mods; using osu.Game.Rulesets.Taiko.Objects; namespace osu.Game.Rulesets.Taiko.Difficulty From 80bd98bb9d1e0d1824cca8862caec6203272a17b Mon Sep 17 00:00:00 2001 From: jorolf Date: Thu, 15 Nov 2018 17:38:38 +0100 Subject: [PATCH 332/333] apply suggestions --- .../Mods/CatchModFlashlight.cs | 4 +-- .../Mods/ManiaModFlashlight.cs | 30 +++++++++++-------- .../Mods/TaikoModFlashlight.cs | 17 ++++++----- osu.Game/Rulesets/Mods/ModFlashlight.cs | 17 ++++------- 4 files changed, 35 insertions(+), 33 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs b/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs index 8645730d09..6592b8b313 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs @@ -40,9 +40,9 @@ namespace osu.Game.Rulesets.Catch.Mods { base.Update(); - var catcher = playfield.CatcherArea.MovableCatcher; + var catcherArea = playfield.CatcherArea; - FlashlightPosition = catcher.ToSpaceOfOtherDrawable(catcher.Position, this); + FlashlightPosition = catcherArea.ToSpaceOfOtherDrawable(catcherArea.MovableCatcher.DrawPosition, this); } private float getSizeFor(int combo) diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs index 32ac668f69..e0e395ce55 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using osu.Framework.Caching; using osu.Framework.Graphics; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mods; @@ -20,6 +21,8 @@ namespace osu.Game.Rulesets.Mania.Mods private class ManiaFlashlight : Flashlight { + private readonly Cached flashlightProperties = new Cached(); + public ManiaFlashlight() { FlashlightSize = new Vector2(0, default_flashlight_size); @@ -29,29 +32,30 @@ namespace osu.Game.Rulesets.Mania.Mods { if ((invalidation & Invalidation.DrawSize) > 0) { - Schedule(() => - { - FlashlightSize = new Vector2(DrawWidth, FlashlightSize.Y); - - FlashlightPosition = DrawPosition + DrawSize / 2; - }); + flashlightProperties.Invalidate(); } return base.Invalidate(invalidation, source, shallPropagate); } + protected override void Update() + { + base.Update(); + + if (!flashlightProperties.IsValid) + { + FlashlightSize = new Vector2(DrawWidth, FlashlightSize.Y); + + FlashlightPosition = DrawPosition + DrawSize / 2; + flashlightProperties.Validate(); + } + } + protected override void OnComboChange(int newCombo) { } protected override string FragmentShader => "RectangularFlashlight"; - - protected override void LoadComplete() - { - FlashlightSize = new Vector2(DrawWidth, FlashlightSize.Y); - - FlashlightPosition = DrawPosition + DrawSize / 2; - } } } } diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs index a58d55f904..5e865d7727 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.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.Caching; using osu.Framework.Graphics; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Taiko.Objects; @@ -28,6 +29,7 @@ namespace osu.Game.Rulesets.Taiko.Mods private class TaikoFlashlight : Flashlight { + private readonly Cached flashlightProperties = new Cached(); private readonly TaikoPlayfield taikoPlayfield; public TaikoFlashlight(TaikoPlayfield taikoPlayfield) @@ -57,20 +59,21 @@ namespace osu.Game.Rulesets.Taiko.Mods { if ((invalidation & Invalidation.DrawSize) > 0) { - Schedule(() => - { - FlashlightPosition = taikoPlayfield.HitTarget.ToSpaceOfOtherDrawable(taikoPlayfield.HitTarget.OriginPosition, this); - }); + flashlightProperties.Invalidate(); } return base.Invalidate(invalidation, source, shallPropagate); } - protected override void LoadComplete() + protected override void Update() { - base.LoadComplete(); + base.Update(); - FlashlightPosition = taikoPlayfield.HitTarget.ToSpaceOfOtherDrawable(taikoPlayfield.HitTarget.OriginPosition, this); + if (!flashlightProperties.IsValid) + { + FlashlightPosition = taikoPlayfield.HitTarget.ToSpaceOfOtherDrawable(taikoPlayfield.HitTarget.OriginPosition, this); + flashlightProperties.Validate(); + } } } } diff --git a/osu.Game/Rulesets/Mods/ModFlashlight.cs b/osu.Game/Rulesets/Mods/ModFlashlight.cs index 2063f5cf88..5e5353bfdd 100644 --- a/osu.Game/Rulesets/Mods/ModFlashlight.cs +++ b/osu.Game/Rulesets/Mods/ModFlashlight.cs @@ -70,8 +70,8 @@ namespace osu.Game.Rulesets.Mods flashNode.Shader = shader; flashNode.ScreenSpaceDrawQuad = ScreenSpaceDrawQuad; - flashNode.MousePosWrapper.FlashlightPosition = Vector2Extensions.Transform(FlashlightPosition, DrawInfo.Matrix); - flashNode.MousePosWrapper.FlashlightSize = Vector2Extensions.Transform(FlashlightSize, DrawInfo.Matrix); + flashNode.FlashlightPosition = Vector2Extensions.Transform(FlashlightPosition, DrawInfo.Matrix); + flashNode.FlashlightSize = Vector2Extensions.Transform(FlashlightSize, DrawInfo.Matrix); } [BackgroundDependencyLoader] @@ -128,17 +128,12 @@ namespace osu.Game.Rulesets.Mods } } - public struct FlashlightUniformWrapper - { - public Vector2 FlashlightPosition; - public Vector2 FlashlightSize; - } - private class FlashlightDrawNode : DrawNode { public Shader Shader; public Quad ScreenSpaceDrawQuad; - public FlashlightUniformWrapper MousePosWrapper; + public Vector2 FlashlightPosition; + public Vector2 FlashlightSize; public override void Draw(Action vertexAction) { @@ -146,8 +141,8 @@ namespace osu.Game.Rulesets.Mods Shader.Bind(); - Shader.GetUniform("flashlightPos").UpdateValue(ref MousePosWrapper.FlashlightPosition); - Shader.GetUniform("flashlightSize").UpdateValue(ref MousePosWrapper.FlashlightSize); + Shader.GetUniform("flashlightPos").UpdateValue(ref FlashlightPosition); + Shader.GetUniform("flashlightSize").UpdateValue(ref FlashlightSize); Texture.WhitePixel.DrawQuad(ScreenSpaceDrawQuad, DrawColourInfo.Colour, vertexAction: vertexAction); From 92b1c56aed4de75b24b02fc809a4a288b17c7271 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 16 Nov 2018 18:31:37 +0900 Subject: [PATCH 333/333] Update osu-resources --- osu-resources | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-resources b/osu-resources index 651e598b01..694cb03f19 160000 --- a/osu-resources +++ b/osu-resources @@ -1 +1 @@ -Subproject commit 651e598b016b43e31ab1c1b29d5b30c92361b8d9 +Subproject commit 694cb03f19c93106ed0f2593f3e506e835fb652a