From 6c8cc9728f6f7adcd02e71063c2c9f9a38dd9f15 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Tue, 25 Jun 2019 19:52:31 +0900 Subject: [PATCH 01/28] fix channel selector not being closed --- .../TestSceneChatOverlayScenarios.cs | 190 ++++++++++++++++++ .../Overlays/Chat/Tabs/ChannelTabControl.cs | 6 +- osu.Game/Overlays/ChatOverlay.cs | 74 +++---- 3 files changed, 231 insertions(+), 39 deletions(-) create mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs new file mode 100644 index 0000000000..b605f5f519 --- /dev/null +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs @@ -0,0 +1,190 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Testing; +using osu.Game.Online.Chat; +using osu.Game.Overlays; +using osu.Game.Overlays.Chat.Tabs; +using osu.Game.Users; +using osuTK; +using osuTK.Input; + +namespace osu.Game.Tests.Visual.UserInterface +{ + public class TestSceneChatOverlayScenarios : ManualInputManagerTestScene + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(ChannelTabControl), + typeof(ChannelTabItem), + typeof(ChatOverlay), + }; + + private TestChatOverlay chatOverlay; + + [Cached] + private ChannelManager channelManager = new ChannelManager(); + + private Channel channel1; + private Channel channel2; + + [BackgroundDependencyLoader] + private void load() + { + var availableChannels = (BindableList)channelManager.AvailableChannels; + + availableChannels.Add(channel1 = new Channel(new User()) { Name = "test1" }); + availableChannels.Add(channel2 = new Channel(new User()) { Name = "test2" }); + + Add(chatOverlay = new TestChatOverlay + { + RelativeSizeAxes = Axes.Both, + Size = new Vector2(1) + }); + } + + [SetUpSteps] + public void SetUpSteps() + { + AddStep("Leave channels", () => + { + channelManager.LeaveChannel(channel1); + channelManager.LeaveChannel(channel2); + }); + AddStep("Hide chat", () => chatOverlay.Hide()); + } + + /// + /// Test that if no maps are added, the channel selector is also toggled when is toggled. + /// Also check that both are properly closed when toggling again. + /// + [Test] + public void TestToggleChatWithNoChannelsJoined() + { + AddStep("Toggle chat overlay", () => chatOverlay.Show()); + AddAssert("Channel selection overlay was toggled", () => chatOverlay.SelectionOverlayState == Visibility.Visible); + AddAssert("Chat overlay was shown", () => chatOverlay.State.Value == Visibility.Visible); + AddStep("Close chat overlay", () => chatOverlay.Hide()); + AddAssert("Channel selection overlay was hidden", () => chatOverlay.SelectionOverlayState == Visibility.Hidden); + AddAssert("Chat overlay was hidden", () => chatOverlay.State.Value == Visibility.Hidden); + } + + [Test] + public void TestToggleChatWithChannelJoined() + { + AddStep("Join channel 1", () => channelManager.JoinChannel(channel1)); + AddStep("Toggle chat overlay", () => chatOverlay.Show()); + AddAssert("Channel selection overlay was not toggled", () => chatOverlay.SelectionOverlayState == Visibility.Hidden); + AddAssert("Chat overlay was shown", () => chatOverlay.State.Value == Visibility.Visible); + AddStep("Close chat overlay", () => chatOverlay.Hide()); + AddAssert("Channel selection overlay was hidden", () => chatOverlay.SelectionOverlayState == Visibility.Hidden); + AddAssert("Chat overlay was hidden", () => chatOverlay.State.Value == Visibility.Hidden); + } + + /// + /// When a channel is joined and no previous channels are joined, the channel that was joined will be selected. + /// Channel selector closes when a new channel is selected. This is blocked for this scenario. + /// This test expects that the channel selection overlay remains open for this reason. + /// + [Test] + public void TestJoinChannelWhileOpen() + { + AddStep("Toggle chat overlay", () => chatOverlay.Show()); + AddStep("Join channel 1", () => channelManager.JoinChannel(channel1)); + AddAssert("Current channel is channel 1", () => channelManager.CurrentChannel.Value == channel1); + AddAssert("Channel selection overlay remained open", () => chatOverlay.SelectionOverlayState == Visibility.Visible); + } + + [Test] + public void TestTabbingAwayClosesSelector() + { + AddStep("Toggle chat overlay", () => chatOverlay.Show()); + AddStep("Join channel 1", () => channelManager.JoinChannel(channel1)); + AddStep("Join channel 2", () => channelManager.JoinChannel(channel2)); + + // There is currently no way to map a tab drawable to its respective value at this level, so this test relies on the tab's location in AvailableTabs + AddStep("Switch to channel 2", () => clickDrawable(chatOverlay.AvailableTabs.First())); + AddAssert("Current channel is channel 2", () => channelManager.CurrentChannel.Value == channel2); + AddAssert("Channel selector was closed", () => chatOverlay.SelectionOverlayState == Visibility.Hidden); + } + + /// + /// When the current channel is closed, the next available channel will be selected. + /// Channel selector closes when a new channel is selected. This is blocked for this scenario. + /// This test expects that the channel selection overlay remains open for this reason. + /// + [Test] + public void TestCloseChannelWhileSelectorOpen() + { + AddStep("Toggle chat overlay", () => chatOverlay.Show()); + AddStep("Join channel 1", () => channelManager.JoinChannel(channel1)); + AddStep("Join channel 2", () => channelManager.JoinChannel(channel2)); + AddAssert("Current channel is channel 1", () => channelManager.CurrentChannel.Value == channel1); + AddStep("Close channel 1", () => clickDrawable(chatOverlay.AvailableTabs.Last().CloseButton.Child)); + AddAssert("Current channel is channel 2", () => channelManager.CurrentChannel.Value == channel2); + AddAssert("Channel selection overlay remained open", () => chatOverlay.SelectionOverlayState == Visibility.Visible); + } + + [Test] + public void TestCloseChannelWhileSelectorClosed() + { + AddStep("Toggle chat overlay", () => chatOverlay.Show()); + AddStep("Join channel 1", () => channelManager.JoinChannel(channel1)); + AddStep("Join channel 2", () => channelManager.JoinChannel(channel2)); + AddStep("Switch to channel 2", () => clickDrawable(chatOverlay.AvailableTabs.First())); + AddStep("Close channel 2", () => clickDrawable(chatOverlay.AvailableTabs.First().CloseButton.Child)); + AddAssert("Selector remained closed", () => chatOverlay.SelectionOverlayState == Visibility.Hidden); + AddAssert("Current channel is channel 2", () => channelManager.CurrentChannel.Value == channel1); + AddStep("Close channel 1", () => clickDrawable(chatOverlay.AvailableTabs.First().CloseButton.Child)); + AddAssert("Channel selection overlay was toggled", () => chatOverlay.SelectionOverlayState == Visibility.Visible); + } + + private void clickDrawable(Drawable d) + { + InputManager.MoveMouseTo(d); + InputManager.Click(MouseButton.Left); + } + + private class TestChatOverlay : ChatOverlay + { + public Visibility SelectionOverlayState => ChannelSelectionOverlay.State.Value; + + protected override ChannelTabControl CreateChannelTabControl() => new TestTabControl(); + + public IEnumerable AvailableTabs => ((TestTabControl)ChannelTabControl).AvailableTabs(); + } + + private class TestTabControl : ChannelTabControl + { + protected override TabItem CreateTabItem(Channel value) => new TestChannelTabItem(value) { OnRequestClose = TabCloseRequested }; + + public IEnumerable AvailableTabs() + { + foreach (var tab in TabContainer) + { + if (!(tab is ChannelSelectorTabItem)) + yield return (TestChannelTabItem)tab; + } + } + } + + private class TestChannelTabItem : PrivateChannelTabItem + { + public TestChannelTabItem(Channel channel) + : base(channel) + { + } + + public new ClickableContainer CloseButton => base.CloseButton; + } + } +} diff --git a/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs b/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs index fafcb0a72d..b96cb27767 100644 --- a/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs +++ b/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs @@ -57,10 +57,10 @@ namespace osu.Game.Overlays.Chat.Tabs switch (value.Type) { default: - return new ChannelTabItem(value) { OnRequestClose = tabCloseRequested }; + return new ChannelTabItem(value) { OnRequestClose = TabCloseRequested }; case ChannelType.PM: - return new PrivateChannelTabItem(value) { OnRequestClose = tabCloseRequested }; + return new PrivateChannelTabItem(value) { OnRequestClose = TabCloseRequested }; } } @@ -103,7 +103,7 @@ namespace osu.Game.Overlays.Chat.Tabs selectorTab.Active.Value = false; } - private void tabCloseRequested(TabItem tab) + protected void TabCloseRequested(TabItem tab) { int totalTabs = TabContainer.Count - 1; // account for selectorTab int currentIndex = MathHelper.Clamp(TabContainer.IndexOf(tab), 1, totalTabs); diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index fce9862e8e..475d691e7c 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -45,7 +45,9 @@ namespace osu.Game.Overlays public const float TAB_AREA_HEIGHT = 50; - private ChannelTabControl channelTabControl; + protected ChannelTabControl ChannelTabControl; + + protected virtual ChannelTabControl CreateChannelTabControl() => new ChannelTabControl(); private Container chatContainer; private TabsArea tabsArea; @@ -55,9 +57,10 @@ namespace osu.Game.Overlays public Bindable ChatHeight { get; set; } private Container channelSelectionContainer; - private ChannelSelectionOverlay channelSelectionOverlay; + protected ChannelSelectionOverlay ChannelSelectionOverlay; - public override bool Contains(Vector2 screenSpacePos) => chatContainer.ReceivePositionalInputAt(screenSpacePos) || (channelSelectionOverlay.State.Value == Visibility.Visible && channelSelectionOverlay.ReceivePositionalInputAt(screenSpacePos)); + public override bool Contains(Vector2 screenSpacePos) => chatContainer.ReceivePositionalInputAt(screenSpacePos) + || (ChannelSelectionOverlay.State.Value == Visibility.Visible && ChannelSelectionOverlay.ReceivePositionalInputAt(screenSpacePos)); public ChatOverlay() { @@ -81,7 +84,7 @@ namespace osu.Game.Overlays Masking = true, Children = new[] { - channelSelectionOverlay = new ChannelSelectionOverlay + ChannelSelectionOverlay = new ChannelSelectionOverlay { RelativeSizeAxes = Axes.Both, }, @@ -154,31 +157,26 @@ namespace osu.Game.Overlays RelativeSizeAxes = Axes.Both, Colour = Color4.Black, }, - channelTabControl = new ChannelTabControl - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - RelativeSizeAxes = Axes.Both, - OnRequestLeave = channelManager.LeaveChannel - }, + ChannelTabControl = CreateChannelTabControl().With(d => + { + d.Anchor = Anchor.BottomLeft; + d.Origin = Anchor.BottomLeft; + d.RelativeSizeAxes = Axes.Both; + d.OnRequestLeave = channelManager.LeaveChannel; + } + ), } }, }, }, }; - channelTabControl.Current.ValueChanged += current => channelManager.CurrentChannel.Value = current.NewValue; - channelTabControl.ChannelSelectorActive.ValueChanged += active => channelSelectionOverlay.State.Value = active.NewValue ? Visibility.Visible : Visibility.Hidden; - channelSelectionOverlay.State.ValueChanged += state => + ChannelTabControl.Current.ValueChanged += current => channelManager.CurrentChannel.Value = current.NewValue; + ChannelTabControl.ChannelSelectorActive.ValueChanged += active => ChannelSelectionOverlay.State.Value = active.NewValue ? Visibility.Visible : Visibility.Hidden; + ChannelSelectionOverlay.State.ValueChanged += state => { - if (state.NewValue == Visibility.Hidden && channelManager.JoinedChannels.Count == 0) - { - channelSelectionOverlay.Show(); - Hide(); - return; - } - - channelTabControl.ChannelSelectorActive.Value = state.NewValue == Visibility.Visible; + // Propagate the visibility state to ChannelSelectorActive + ChannelTabControl.ChannelSelectorActive.Value = state.NewValue == Visibility.Visible; if (state.NewValue == Visibility.Visible) { @@ -190,8 +188,8 @@ namespace osu.Game.Overlays textbox.HoldFocus = true; }; - channelSelectionOverlay.OnRequestJoin = channel => channelManager.JoinChannel(channel); - channelSelectionOverlay.OnRequestLeave = channelManager.LeaveChannel; + ChannelSelectionOverlay.OnRequestJoin = channel => channelManager.JoinChannel(channel); + ChannelSelectionOverlay.OnRequestLeave = channelManager.LeaveChannel; ChatHeight = config.GetBindable(OsuSetting.ChatDisplayHeight); ChatHeight.ValueChanged += height => @@ -217,11 +215,11 @@ namespace osu.Game.Overlays channelManager.JoinedChannels.ItemsAdded += onChannelAddedToJoinedChannels; channelManager.JoinedChannels.ItemsRemoved += onChannelRemovedFromJoinedChannels; foreach (Channel channel in channelManager.JoinedChannels) - channelTabControl.AddChannel(channel); + ChannelTabControl.AddChannel(channel); channelManager.AvailableChannels.ItemsAdded += availableChannelsChanged; channelManager.AvailableChannels.ItemsRemoved += availableChannelsChanged; - channelSelectionOverlay.UpdateAvailableChannels(channelManager.AvailableChannels); + ChannelSelectionOverlay.UpdateAvailableChannels(channelManager.AvailableChannels); currentChannel = channelManager.CurrentChannel.GetBoundCopy(); currentChannel.BindValueChanged(currentChannelChanged, true); @@ -236,7 +234,7 @@ namespace osu.Game.Overlays { textbox.Current.Disabled = true; currentChannelContainer.Clear(false); - channelSelectionOverlay.Show(); + ChannelSelectionOverlay.Show(); return; } @@ -245,8 +243,8 @@ namespace osu.Game.Overlays textbox.Current.Disabled = e.NewValue.ReadOnly; - if (channelTabControl.Current.Value != e.NewValue) - Scheduler.Add(() => channelTabControl.Current.Value = e.NewValue); + if (ChannelTabControl.Current.Value != e.NewValue) + Scheduler.Add(() => ChannelTabControl.Current.Value = e.NewValue); var loaded = loadedChannels.Find(d => d.Channel == e.NewValue); @@ -294,7 +292,7 @@ namespace osu.Game.Overlays double targetChatHeight = startDragChatHeight - (e.MousePosition.Y - e.MouseDownPosition.Y) / Parent.DrawSize.Y; // If the channel selection screen is shown, mind its minimum height - if (channelSelectionOverlay.State.Value == Visibility.Visible && targetChatHeight > 1f - channel_selection_min_height) + if (ChannelSelectionOverlay.State.Value == Visibility.Visible && targetChatHeight > 1f - channel_selection_min_height) targetChatHeight = 1f - channel_selection_min_height; ChatHeight.Value = targetChatHeight; @@ -311,9 +309,9 @@ namespace osu.Game.Overlays private void selectTab(int index) { - var channel = channelTabControl.Items.Skip(index).FirstOrDefault(); + var channel = ChannelTabControl.Items.Skip(index).FirstOrDefault(); if (channel != null && !(channel is ChannelSelectorTabItem.ChannelSelectorTabChannel)) - channelTabControl.Current.Value = channel; + ChannelTabControl.Current.Value = channel; } protected override bool OnKeyDown(KeyDownEvent e) @@ -358,6 +356,10 @@ namespace osu.Game.Overlays this.FadeIn(transition_length, Easing.OutQuint); textbox.HoldFocus = true; + + if (channelManager.CurrentChannel.Value == null || channelManager.CurrentChannel.Value is ChannelSelectorTabItem.ChannelSelectorTabChannel) + ChannelSelectionOverlay.Show(); + base.PopIn(); } @@ -366,7 +368,7 @@ namespace osu.Game.Overlays this.MoveToY(Height, transition_length, Easing.InSine); this.FadeOut(transition_length, Easing.InSine); - channelSelectionOverlay.Hide(); + ChannelSelectionOverlay.Hide(); textbox.HoldFocus = false; base.PopOut(); @@ -375,20 +377,20 @@ namespace osu.Game.Overlays private void onChannelAddedToJoinedChannels(IEnumerable channels) { foreach (Channel channel in channels) - channelTabControl.AddChannel(channel); + ChannelTabControl.AddChannel(channel); } private void onChannelRemovedFromJoinedChannels(IEnumerable channels) { foreach (Channel channel in channels) { - channelTabControl.RemoveChannel(channel); + ChannelTabControl.RemoveChannel(channel); loadedChannels.Remove(loadedChannels.Find(c => c.Channel == channel)); } } private void availableChannelsChanged(IEnumerable channels) - => channelSelectionOverlay.UpdateAvailableChannels(channelManager.AvailableChannels); + => ChannelSelectionOverlay.UpdateAvailableChannels(channelManager.AvailableChannels); protected override void Dispose(bool isDisposing) { From 1ca9717e1364fdc3bddca37f820240710b06aee3 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Wed, 26 Jun 2019 12:05:11 +0900 Subject: [PATCH 02/28] Split out tests --- .../TestSceneChatOverlayScenarios.cs | 31 ------------------- 1 file changed, 31 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs index b605f5f519..ffe52833cf 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs @@ -90,20 +90,6 @@ namespace osu.Game.Tests.Visual.UserInterface AddAssert("Chat overlay was hidden", () => chatOverlay.State.Value == Visibility.Hidden); } - /// - /// When a channel is joined and no previous channels are joined, the channel that was joined will be selected. - /// Channel selector closes when a new channel is selected. This is blocked for this scenario. - /// This test expects that the channel selection overlay remains open for this reason. - /// - [Test] - public void TestJoinChannelWhileOpen() - { - AddStep("Toggle chat overlay", () => chatOverlay.Show()); - AddStep("Join channel 1", () => channelManager.JoinChannel(channel1)); - AddAssert("Current channel is channel 1", () => channelManager.CurrentChannel.Value == channel1); - AddAssert("Channel selection overlay remained open", () => chatOverlay.SelectionOverlayState == Visibility.Visible); - } - [Test] public void TestTabbingAwayClosesSelector() { @@ -117,23 +103,6 @@ namespace osu.Game.Tests.Visual.UserInterface AddAssert("Channel selector was closed", () => chatOverlay.SelectionOverlayState == Visibility.Hidden); } - /// - /// When the current channel is closed, the next available channel will be selected. - /// Channel selector closes when a new channel is selected. This is blocked for this scenario. - /// This test expects that the channel selection overlay remains open for this reason. - /// - [Test] - public void TestCloseChannelWhileSelectorOpen() - { - AddStep("Toggle chat overlay", () => chatOverlay.Show()); - AddStep("Join channel 1", () => channelManager.JoinChannel(channel1)); - AddStep("Join channel 2", () => channelManager.JoinChannel(channel2)); - AddAssert("Current channel is channel 1", () => channelManager.CurrentChannel.Value == channel1); - AddStep("Close channel 1", () => clickDrawable(chatOverlay.AvailableTabs.Last().CloseButton.Child)); - AddAssert("Current channel is channel 2", () => channelManager.CurrentChannel.Value == channel2); - AddAssert("Channel selection overlay remained open", () => chatOverlay.SelectionOverlayState == Visibility.Visible); - } - [Test] public void TestCloseChannelWhileSelectorClosed() { From 7dd1479050e3ecd1b61b3476c5aae69a33b30b67 Mon Sep 17 00:00:00 2001 From: Welsar55 Date: Wed, 26 Jun 2019 00:20:33 -0500 Subject: [PATCH 03/28] Add combobreak sound --- osu.Game/Screens/Play/Player.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index c3e351a0ca..530145a604 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -66,6 +66,7 @@ namespace osu.Game.Screens.Play private IAPIProvider api; private SampleChannel sampleRestart; + private SampleChannel sampleComboBreak; protected ScoreProcessor ScoreProcessor { get; private set; } protected DrawableRuleset DrawableRuleset { get; private set; } @@ -80,6 +81,8 @@ namespace osu.Game.Screens.Play [Cached(Type = typeof(IBindable>))] protected new readonly Bindable> Mods = new Bindable>(Array.Empty()); + protected readonly BindableInt Combo = new BindableInt(); + private readonly bool allowPause; private readonly bool showResults; @@ -107,12 +110,15 @@ namespace osu.Game.Screens.Play return; sampleRestart = audio.Samples.Get(@"Gameplay/restart"); + sampleComboBreak = audio.Samples.Get(@"Gameplay/combobreak"); mouseWheelDisabled = config.GetBindable(OsuSetting.MouseDisableWheel); showStoryboard = config.GetBindable(OsuSetting.ShowStoryboard); ScoreProcessor = DrawableRuleset.CreateScoreProcessor(); ScoreProcessor.Mods.BindTo(Mods); + ScoreProcessor.Combo.BindTo(Combo); + Combo.BindValueChanged(onComboChange); if (!ScoreProcessor.Mode.Disabled) config.BindWith(OsuSetting.ScoreDisplayMode, ScoreProcessor.Mode); @@ -264,6 +270,12 @@ namespace osu.Game.Screens.Play private ScheduledDelegate onCompletionEvent; + private void onComboChange(ValueChangedEvent combo) + { + if (combo.NewValue == 0 && combo.OldValue > 20) + sampleComboBreak?.Play(); + } + private void onCompletion() { // Only show the completion screen if the player hasn't failed From 2394b11f11c13ee2062b77b9a121d1053b454229 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Wed, 26 Jun 2019 17:44:24 +0900 Subject: [PATCH 04/28] fix test --- .../UserInterface/TestSceneChatOverlayScenarios.cs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs index ffe52833cf..79ffef1034 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs @@ -60,7 +60,7 @@ namespace osu.Game.Tests.Visual.UserInterface channelManager.LeaveChannel(channel1); channelManager.LeaveChannel(channel2); }); - AddStep("Hide chat", () => chatOverlay.Hide()); + AddStep("Show chat", () => chatOverlay.Show()); } /// @@ -70,7 +70,6 @@ namespace osu.Game.Tests.Visual.UserInterface [Test] public void TestToggleChatWithNoChannelsJoined() { - AddStep("Toggle chat overlay", () => chatOverlay.Show()); AddAssert("Channel selection overlay was toggled", () => chatOverlay.SelectionOverlayState == Visibility.Visible); AddAssert("Chat overlay was shown", () => chatOverlay.State.Value == Visibility.Visible); AddStep("Close chat overlay", () => chatOverlay.Hide()); @@ -82,18 +81,17 @@ namespace osu.Game.Tests.Visual.UserInterface public void TestToggleChatWithChannelJoined() { AddStep("Join channel 1", () => channelManager.JoinChannel(channel1)); - AddStep("Toggle chat overlay", () => chatOverlay.Show()); - AddAssert("Channel selection overlay was not toggled", () => chatOverlay.SelectionOverlayState == Visibility.Hidden); - AddAssert("Chat overlay was shown", () => chatOverlay.State.Value == Visibility.Visible); AddStep("Close chat overlay", () => chatOverlay.Hide()); AddAssert("Channel selection overlay was hidden", () => chatOverlay.SelectionOverlayState == Visibility.Hidden); AddAssert("Chat overlay was hidden", () => chatOverlay.State.Value == Visibility.Hidden); + AddStep("Close chat overlay", () => chatOverlay.Show()); + AddAssert("Channel selection overlay was not toggled", () => chatOverlay.SelectionOverlayState == Visibility.Hidden); + AddAssert("Chat overlay was shown", () => chatOverlay.State.Value == Visibility.Visible); } [Test] public void TestTabbingAwayClosesSelector() { - AddStep("Toggle chat overlay", () => chatOverlay.Show()); AddStep("Join channel 1", () => channelManager.JoinChannel(channel1)); AddStep("Join channel 2", () => channelManager.JoinChannel(channel2)); @@ -106,7 +104,6 @@ namespace osu.Game.Tests.Visual.UserInterface [Test] public void TestCloseChannelWhileSelectorClosed() { - AddStep("Toggle chat overlay", () => chatOverlay.Show()); AddStep("Join channel 1", () => channelManager.JoinChannel(channel1)); AddStep("Join channel 2", () => channelManager.JoinChannel(channel2)); AddStep("Switch to channel 2", () => clickDrawable(chatOverlay.AvailableTabs.First())); From d1230b4a529269896a0d70ddf6d1ab497fc7596a Mon Sep 17 00:00:00 2001 From: David Zhao Date: Wed, 26 Jun 2019 17:53:35 +0900 Subject: [PATCH 05/28] Use tabmap instead of available tabs --- .../TestSceneChatOverlayScenarios.cs | 21 ++++++------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs index 79ffef1034..c91b33dfb1 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs @@ -94,9 +94,7 @@ namespace osu.Game.Tests.Visual.UserInterface { AddStep("Join channel 1", () => channelManager.JoinChannel(channel1)); AddStep("Join channel 2", () => channelManager.JoinChannel(channel2)); - - // There is currently no way to map a tab drawable to its respective value at this level, so this test relies on the tab's location in AvailableTabs - AddStep("Switch to channel 2", () => clickDrawable(chatOverlay.AvailableTabs.First())); + AddStep("Switch to channel 2", () => clickDrawable(chatOverlay.TabMap[channel2])); AddAssert("Current channel is channel 2", () => channelManager.CurrentChannel.Value == channel2); AddAssert("Channel selector was closed", () => chatOverlay.SelectionOverlayState == Visibility.Hidden); } @@ -106,11 +104,11 @@ namespace osu.Game.Tests.Visual.UserInterface { AddStep("Join channel 1", () => channelManager.JoinChannel(channel1)); AddStep("Join channel 2", () => channelManager.JoinChannel(channel2)); - AddStep("Switch to channel 2", () => clickDrawable(chatOverlay.AvailableTabs.First())); - AddStep("Close channel 2", () => clickDrawable(chatOverlay.AvailableTabs.First().CloseButton.Child)); + AddStep("Switch to channel 2", () => clickDrawable(chatOverlay.TabMap[channel2])); + AddStep("Close channel 2", () => clickDrawable(((TestChannelTabItem)chatOverlay.TabMap[channel2]).CloseButton.Child)); AddAssert("Selector remained closed", () => chatOverlay.SelectionOverlayState == Visibility.Hidden); AddAssert("Current channel is channel 2", () => channelManager.CurrentChannel.Value == channel1); - AddStep("Close channel 1", () => clickDrawable(chatOverlay.AvailableTabs.First().CloseButton.Child)); + AddStep("Close channel 1", () => clickDrawable(((TestChannelTabItem)chatOverlay.TabMap[channel1]).CloseButton.Child)); AddAssert("Channel selection overlay was toggled", () => chatOverlay.SelectionOverlayState == Visibility.Visible); } @@ -126,21 +124,14 @@ namespace osu.Game.Tests.Visual.UserInterface protected override ChannelTabControl CreateChannelTabControl() => new TestTabControl(); - public IEnumerable AvailableTabs => ((TestTabControl)ChannelTabControl).AvailableTabs(); + public IReadOnlyDictionary> TabMap => ((TestTabControl)ChannelTabControl).TabMap; } private class TestTabControl : ChannelTabControl { protected override TabItem CreateTabItem(Channel value) => new TestChannelTabItem(value) { OnRequestClose = TabCloseRequested }; - public IEnumerable AvailableTabs() - { - foreach (var tab in TabContainer) - { - if (!(tab is ChannelSelectorTabItem)) - yield return (TestChannelTabItem)tab; - } - } + public new IReadOnlyDictionary> TabMap => base.TabMap; } private class TestChannelTabItem : PrivateChannelTabItem From 1e8026c3ae9f2db5dc0443175b259c1a2b719981 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Wed, 26 Jun 2019 17:53:57 +0900 Subject: [PATCH 06/28] remove unused using --- .../Visual/UserInterface/TestSceneChatOverlayScenarios.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs index c91b33dfb1..dd7b9298c8 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; From 024d3cc10a5f2f937875a7015897c30a7937efa0 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Wed, 26 Jun 2019 18:00:40 +0900 Subject: [PATCH 07/28] Fix test and add comment --- .../Visual/UserInterface/TestSceneChatOverlayScenarios.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs index dd7b9298c8..3d78e91087 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs @@ -79,7 +79,12 @@ namespace osu.Game.Tests.Visual.UserInterface [Test] public void TestToggleChatWithChannelJoined() { - AddStep("Join channel 1", () => channelManager.JoinChannel(channel1)); + AddStep("Join channel 1", () => + { + channelManager.JoinChannel(channel1); + // Temporarily here to circumvent https://github.com/ppy/osu/issues/5152 + channelManager.OpenChannel(channel1.Name); + }); AddStep("Close chat overlay", () => chatOverlay.Hide()); AddAssert("Channel selection overlay was hidden", () => chatOverlay.SelectionOverlayState == Visibility.Hidden); AddAssert("Chat overlay was hidden", () => chatOverlay.State.Value == Visibility.Hidden); From e92c1ca009aac709464e6ad217a197ba2290234f Mon Sep 17 00:00:00 2001 From: David Zhao Date: Wed, 26 Jun 2019 19:25:54 +0900 Subject: [PATCH 08/28] Fix styling, private tabClosed, remove type check --- .../UserInterface/TestSceneChatOverlayScenarios.cs | 2 +- osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs | 8 +++++--- osu.Game/Overlays/ChatOverlay.cs | 13 ++++++------- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs index 3d78e91087..987d711917 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs @@ -133,7 +133,7 @@ namespace osu.Game.Tests.Visual.UserInterface private class TestTabControl : ChannelTabControl { - protected override TabItem CreateTabItem(Channel value) => new TestChannelTabItem(value) { OnRequestClose = TabCloseRequested }; + protected override TabItem CreateTabItem(Channel value) => new TestChannelTabItem(value); public new IReadOnlyDictionary> TabMap => base.TabMap; } diff --git a/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs b/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs index b96cb27767..612379d339 100644 --- a/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs +++ b/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs @@ -49,6 +49,8 @@ namespace osu.Game.Overlays.Chat.Tabs // performTabSort might've made selectorTab's position wonky, fix it TabContainer.SetLayoutPosition(selectorTab, float.MaxValue); + ((ChannelTabItem)item).OnRequestClose += tabCloseRequested; + base.AddTabItem(item, addToDropdown); } @@ -57,10 +59,10 @@ namespace osu.Game.Overlays.Chat.Tabs switch (value.Type) { default: - return new ChannelTabItem(value) { OnRequestClose = TabCloseRequested }; + return new ChannelTabItem(value); case ChannelType.PM: - return new PrivateChannelTabItem(value) { OnRequestClose = TabCloseRequested }; + return new PrivateChannelTabItem(value); } } @@ -103,7 +105,7 @@ namespace osu.Game.Overlays.Chat.Tabs selectorTab.Active.Value = false; } - protected 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); diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 475d691e7c..bc94fb1cb8 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -158,13 +158,12 @@ namespace osu.Game.Overlays Colour = Color4.Black, }, ChannelTabControl = CreateChannelTabControl().With(d => - { - d.Anchor = Anchor.BottomLeft; - d.Origin = Anchor.BottomLeft; - d.RelativeSizeAxes = Axes.Both; - d.OnRequestLeave = channelManager.LeaveChannel; - } - ), + { + d.Anchor = Anchor.BottomLeft; + d.Origin = Anchor.BottomLeft; + d.RelativeSizeAxes = Axes.Both; + d.OnRequestLeave = channelManager.LeaveChannel; + }), } }, }, From 4510c868f49c6619be45d124d14c5631f5486a00 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Wed, 26 Jun 2019 19:39:47 +0900 Subject: [PATCH 09/28] Remove selector toggling logic for now --- osu.Game/Overlays/ChatOverlay.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index bc94fb1cb8..e223856b27 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -356,9 +356,6 @@ namespace osu.Game.Overlays textbox.HoldFocus = true; - if (channelManager.CurrentChannel.Value == null || channelManager.CurrentChannel.Value is ChannelSelectorTabItem.ChannelSelectorTabChannel) - ChannelSelectionOverlay.Show(); - base.PopIn(); } From b00de0b3a807f457b04b38d1677cd356c11badfd Mon Sep 17 00:00:00 2001 From: David Zhao Date: Wed, 26 Jun 2019 20:04:46 +0900 Subject: [PATCH 10/28] Invert tests for now --- .../TestSceneChatOverlayScenarios.cs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs index 987d711917..5cee05aa2b 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs @@ -12,6 +12,7 @@ using osu.Framework.Graphics.UserInterface; using osu.Framework.Testing; using osu.Game.Online.Chat; using osu.Game.Overlays; +using osu.Game.Overlays.Chat.Selection; using osu.Game.Overlays.Chat.Tabs; using osu.Game.Users; using osuTK; @@ -54,6 +55,7 @@ namespace osu.Game.Tests.Visual.UserInterface [SetUpSteps] public void SetUpSteps() { + AddStep("Hide chat", () => chatOverlay.Hide()); AddStep("Leave channels", () => { channelManager.LeaveChannel(channel1); @@ -69,7 +71,8 @@ namespace osu.Game.Tests.Visual.UserInterface [Test] public void TestToggleChatWithNoChannelsJoined() { - AddAssert("Channel selection overlay was toggled", () => chatOverlay.SelectionOverlayState == Visibility.Visible); + AddAssert("Channel selection overlay hidden", () => chatOverlay.SelectionOverlayState == Visibility.Hidden); + //TODO: Change this to check whether or not the chat overlay was shown once https://github.com/ppy/osu/issues/5161 is fixed AddAssert("Chat overlay was shown", () => chatOverlay.State.Value == Visibility.Visible); AddStep("Close chat overlay", () => chatOverlay.Hide()); AddAssert("Channel selection overlay was hidden", () => chatOverlay.SelectionOverlayState == Visibility.Hidden); @@ -82,7 +85,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("Join channel 1", () => { channelManager.JoinChannel(channel1); - // Temporarily here to circumvent https://github.com/ppy/osu/issues/5152 + // TODO: Temporarily here to circumvent https://github.com/ppy/osu/issues/5152. Remove once fixed. channelManager.OpenChannel(channel1.Name); }); AddStep("Close chat overlay", () => chatOverlay.Hide()); @@ -126,6 +129,8 @@ namespace osu.Game.Tests.Visual.UserInterface { public Visibility SelectionOverlayState => ChannelSelectionOverlay.State.Value; + public new ChannelSelectionOverlay ChannelSelectionOverlay => base.ChannelSelectionOverlay; + protected override ChannelTabControl CreateChannelTabControl() => new TestTabControl(); public IReadOnlyDictionary> TabMap => ((TestTabControl)ChannelTabControl).TabMap; @@ -136,6 +141,12 @@ namespace osu.Game.Tests.Visual.UserInterface protected override TabItem CreateTabItem(Channel value) => new TestChannelTabItem(value); public new IReadOnlyDictionary> TabMap => base.TabMap; + + protected override void LoadComplete() + { + base.LoadComplete(); + SelectTab(null); + } } private class TestChannelTabItem : PrivateChannelTabItem From 826699a7e75d33527da0b723878a47fcabd26e7d Mon Sep 17 00:00:00 2001 From: Welsar55 Date: Wed, 26 Jun 2019 12:16:44 -0500 Subject: [PATCH 11/28] Remove unneeded bindable --- osu.Game/Screens/Play/Player.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 530145a604..f620c790aa 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -81,8 +81,6 @@ namespace osu.Game.Screens.Play [Cached(Type = typeof(IBindable>))] protected new readonly Bindable> Mods = new Bindable>(Array.Empty()); - protected readonly BindableInt Combo = new BindableInt(); - private readonly bool allowPause; private readonly bool showResults; @@ -117,8 +115,7 @@ namespace osu.Game.Screens.Play ScoreProcessor = DrawableRuleset.CreateScoreProcessor(); ScoreProcessor.Mods.BindTo(Mods); - ScoreProcessor.Combo.BindTo(Combo); - Combo.BindValueChanged(onComboChange); + ScoreProcessor.Combo.BindValueChanged(onComboChange); if (!ScoreProcessor.Mode.Disabled) config.BindWith(OsuSetting.ScoreDisplayMode, ScoreProcessor.Mode); From 22ba697abe40ebd978a89bcb1f3e421a81811a1e Mon Sep 17 00:00:00 2001 From: David Zhao Date: Thu, 27 Jun 2019 13:50:02 +0900 Subject: [PATCH 12/28] Recreate channel manager per test, delete broken tests --- .../TestSceneChatOverlayScenarios.cs | 112 ++++++++---------- 1 file changed, 48 insertions(+), 64 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs index 5cee05aa2b..bb7d8df09f 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs @@ -9,7 +9,6 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; -using osu.Framework.Testing; using osu.Game.Online.Chat; using osu.Game.Overlays; using osu.Game.Overlays.Chat.Selection; @@ -30,79 +29,39 @@ namespace osu.Game.Tests.Visual.UserInterface }; private TestChatOverlay chatOverlay; + private ChannelManager channelManager; - [Cached] - private ChannelManager channelManager = new ChannelManager(); + private readonly Channel channel1 = new Channel(new User()) { Name = "test1" }; + private readonly Channel channel2 = new Channel(new User()) { Name = "test2" }; - private Channel channel1; - private Channel channel2; - - [BackgroundDependencyLoader] - private void load() + [SetUp] + public void Setup() { - var availableChannels = (BindableList)channelManager.AvailableChannels; - - availableChannels.Add(channel1 = new Channel(new User()) { Name = "test1" }); - availableChannels.Add(channel2 = new Channel(new User()) { Name = "test2" }); - - Add(chatOverlay = new TestChatOverlay + Schedule(() => { - RelativeSizeAxes = Axes.Both, - Size = new Vector2(1) + ChannelManagerContainer container; + Child = container = new ChannelManagerContainer(new List { channel1, channel2 }) { RelativeSizeAxes = Axes.Both, }; + chatOverlay = container.ChatOverlay; + channelManager = container.ChannelManager; + chatOverlay.Show(); }); } - [SetUpSteps] - public void SetUpSteps() - { - AddStep("Hide chat", () => chatOverlay.Hide()); - AddStep("Leave channels", () => - { - channelManager.LeaveChannel(channel1); - channelManager.LeaveChannel(channel2); - }); - AddStep("Show chat", () => chatOverlay.Show()); - } - - /// - /// Test that if no maps are added, the channel selector is also toggled when is toggled. - /// Also check that both are properly closed when toggling again. - /// - [Test] - public void TestToggleChatWithNoChannelsJoined() - { - AddAssert("Channel selection overlay hidden", () => chatOverlay.SelectionOverlayState == Visibility.Hidden); - //TODO: Change this to check whether or not the chat overlay was shown once https://github.com/ppy/osu/issues/5161 is fixed - AddAssert("Chat overlay was shown", () => chatOverlay.State.Value == Visibility.Visible); - AddStep("Close chat overlay", () => chatOverlay.Hide()); - AddAssert("Channel selection overlay was hidden", () => chatOverlay.SelectionOverlayState == Visibility.Hidden); - AddAssert("Chat overlay was hidden", () => chatOverlay.State.Value == Visibility.Hidden); - } - [Test] - public void TestToggleChatWithChannelJoined() + public void TestHideOverlay() { - AddStep("Join channel 1", () => - { - channelManager.JoinChannel(channel1); - // TODO: Temporarily here to circumvent https://github.com/ppy/osu/issues/5152. Remove once fixed. - channelManager.OpenChannel(channel1.Name); - }); AddStep("Close chat overlay", () => chatOverlay.Hide()); AddAssert("Channel selection overlay was hidden", () => chatOverlay.SelectionOverlayState == Visibility.Hidden); AddAssert("Chat overlay was hidden", () => chatOverlay.State.Value == Visibility.Hidden); - AddStep("Close chat overlay", () => chatOverlay.Show()); - AddAssert("Channel selection overlay was not toggled", () => chatOverlay.SelectionOverlayState == Visibility.Hidden); - AddAssert("Chat overlay was shown", () => chatOverlay.State.Value == Visibility.Visible); } [Test] public void TestTabbingAwayClosesSelector() { + AddAssert("Selector is visible", () => chatOverlay.SelectionOverlayState == Visibility.Visible); AddStep("Join channel 1", () => channelManager.JoinChannel(channel1)); - AddStep("Join channel 2", () => channelManager.JoinChannel(channel2)); - AddStep("Switch to channel 2", () => clickDrawable(chatOverlay.TabMap[channel2])); - AddAssert("Current channel is channel 2", () => channelManager.CurrentChannel.Value == channel2); + AddStep("Switch to channel 1", () => clickDrawable(chatOverlay.TabMap[channel1])); + AddAssert("Current channel is channel 1", () => channelManager.CurrentChannel.Value == channel1); AddAssert("Channel selector was closed", () => chatOverlay.SelectionOverlayState == Visibility.Hidden); } @@ -114,9 +73,9 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("Switch to channel 2", () => clickDrawable(chatOverlay.TabMap[channel2])); AddStep("Close channel 2", () => clickDrawable(((TestChannelTabItem)chatOverlay.TabMap[channel2]).CloseButton.Child)); AddAssert("Selector remained closed", () => chatOverlay.SelectionOverlayState == Visibility.Hidden); - AddAssert("Current channel is channel 2", () => channelManager.CurrentChannel.Value == channel1); + AddAssert("Current channel is channel 1", () => channelManager.CurrentChannel.Value == channel1); AddStep("Close channel 1", () => clickDrawable(((TestChannelTabItem)chatOverlay.TabMap[channel1]).CloseButton.Child)); - AddAssert("Channel selection overlay was toggled", () => chatOverlay.SelectionOverlayState == Visibility.Visible); + AddAssert("Selector is visible", () => chatOverlay.SelectionOverlayState == Visibility.Visible); } private void clickDrawable(Drawable d) @@ -125,6 +84,37 @@ namespace osu.Game.Tests.Visual.UserInterface InputManager.Click(MouseButton.Left); } + private class ChannelManagerContainer : Container + { + [Cached] + private ChannelManager channelManager = new ChannelManager(); + + public TestChatOverlay ChatOverlay { get; private set; } + + public ChannelManager ChannelManager => channelManager; + + private readonly List channels; + + public ChannelManagerContainer(List channels) + { + this.channels = channels; + } + + [BackgroundDependencyLoader] + private void load() + { + var availableChannels = (BindableList)channelManager.AvailableChannels; + + availableChannels.AddRange(channels); + + Child = ChatOverlay = new TestChatOverlay + { + RelativeSizeAxes = Axes.Both, + Size = new Vector2(1) + }; + } + } + private class TestChatOverlay : ChatOverlay { public Visibility SelectionOverlayState => ChannelSelectionOverlay.State.Value; @@ -141,12 +131,6 @@ namespace osu.Game.Tests.Visual.UserInterface protected override TabItem CreateTabItem(Channel value) => new TestChannelTabItem(value); public new IReadOnlyDictionary> TabMap => base.TabMap; - - protected override void LoadComplete() - { - base.LoadComplete(); - SelectTab(null); - } } private class TestChannelTabItem : PrivateChannelTabItem From 9d67a3f6a4fc9ede66ba02d3f51b0be7c41b5366 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Thu, 27 Jun 2019 14:42:04 +0900 Subject: [PATCH 13/28] clean up ChannelManagerContainer --- .../TestSceneChatOverlayScenarios.cs | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs index bb7d8df09f..70b7ba3769 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs @@ -43,7 +43,6 @@ namespace osu.Game.Tests.Visual.UserInterface Child = container = new ChannelManagerContainer(new List { channel1, channel2 }) { RelativeSizeAxes = Axes.Both, }; chatOverlay = container.ChatOverlay; channelManager = container.ChannelManager; - chatOverlay.Show(); }); } @@ -86,12 +85,10 @@ namespace osu.Game.Tests.Visual.UserInterface private class ChannelManagerContainer : Container { - [Cached] - private ChannelManager channelManager = new ChannelManager(); - public TestChatOverlay ChatOverlay { get; private set; } - public ChannelManager ChannelManager => channelManager; + [Cached] + public ChannelManager ChannelManager { get; } = new ChannelManager(); private readonly List channels; @@ -103,15 +100,10 @@ namespace osu.Game.Tests.Visual.UserInterface [BackgroundDependencyLoader] private void load() { - var availableChannels = (BindableList)channelManager.AvailableChannels; + ((BindableList)ChannelManager.AvailableChannels).AddRange(channels); - availableChannels.AddRange(channels); - - Child = ChatOverlay = new TestChatOverlay - { - RelativeSizeAxes = Axes.Both, - Size = new Vector2(1) - }; + Child = ChatOverlay = new TestChatOverlay { RelativeSizeAxes = Axes.Both, }; + ChatOverlay.Show(); } } From 116a027ffa9ef9383e96cd3391a333cf39a56950 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Thu, 27 Jun 2019 14:51:59 +0900 Subject: [PATCH 14/28] remove unused using --- .../Visual/UserInterface/TestSceneChatOverlayScenarios.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs index 70b7ba3769..2886bcfe56 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs @@ -14,7 +14,6 @@ using osu.Game.Overlays; using osu.Game.Overlays.Chat.Selection; using osu.Game.Overlays.Chat.Tabs; using osu.Game.Users; -using osuTK; using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface From 4465e42b85b4180c19e703fe8c00af8eee414d78 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 28 Jun 2019 23:21:14 +0300 Subject: [PATCH 15/28] HandlePositionalInput must be true To update IsHovered --- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 1cce5598e1..1aec2c513c 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -85,6 +85,8 @@ namespace osu.Game.Rulesets.Objects.Drawables public override bool RemoveCompletedTransforms => false; protected override bool RequiresChildrenUpdate => true; + public override bool HandlePositionalInput => true; + public override bool IsPresent => base.IsPresent || (State.Value == ArmedState.Idle && Clock?.CurrentTime >= LifetimeStart); public readonly Bindable State = new Bindable(); From a57218e50ee3883d4fc938b87b7cbdf7f1998a2d Mon Sep 17 00:00:00 2001 From: Welsar55 Date: Fri, 28 Jun 2019 20:45:11 -0500 Subject: [PATCH 16/28] Move to LocalSkinOverride --- .../Gameplay/TestSceneSkinReloadable.cs | 5 ++-- osu.Game/Screens/Play/Player.cs | 11 +------- .../Skinning/LocalSkinOverrideContainer.cs | 26 ++++++++++++++++++- 3 files changed, 29 insertions(+), 13 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinReloadable.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinReloadable.cs index c7a0df6e9f..f03ffea5dc 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinReloadable.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinReloadable.cs @@ -4,6 +4,7 @@ using System; using NUnit.Framework; using osu.Framework.Audio.Sample; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -28,7 +29,7 @@ namespace osu.Game.Tests.Visual.Gameplay Child = new SkinSourceContainer { RelativeSizeAxes = Axes.Both, - Child = new LocalSkinOverrideContainer(secondarySource) + Child = new LocalSkinOverrideContainer(secondarySource, new BindableInt()) { RelativeSizeAxes = Axes.Both, Child = consumer = new SkinConsumer("test", name => new NamedBox("Default Implementation"), source => true) @@ -53,7 +54,7 @@ namespace osu.Game.Tests.Visual.Gameplay Child = new SkinSourceContainer { RelativeSizeAxes = Axes.Both, - Child = target = new LocalSkinOverrideContainer(secondarySource) + Child = target = new LocalSkinOverrideContainer(secondarySource, new BindableInt()) { RelativeSizeAxes = Axes.Both, } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index f620c790aa..55d43bb4c8 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -66,7 +66,6 @@ namespace osu.Game.Screens.Play private IAPIProvider api; private SampleChannel sampleRestart; - private SampleChannel sampleComboBreak; protected ScoreProcessor ScoreProcessor { get; private set; } protected DrawableRuleset DrawableRuleset { get; private set; } @@ -108,14 +107,12 @@ namespace osu.Game.Screens.Play return; sampleRestart = audio.Samples.Get(@"Gameplay/restart"); - sampleComboBreak = audio.Samples.Get(@"Gameplay/combobreak"); mouseWheelDisabled = config.GetBindable(OsuSetting.MouseDisableWheel); showStoryboard = config.GetBindable(OsuSetting.ShowStoryboard); ScoreProcessor = DrawableRuleset.CreateScoreProcessor(); ScoreProcessor.Mods.BindTo(Mods); - ScoreProcessor.Combo.BindValueChanged(onComboChange); if (!ScoreProcessor.Mode.Disabled) config.BindWith(OsuSetting.ScoreDisplayMode, ScoreProcessor.Mode); @@ -127,7 +124,7 @@ namespace osu.Game.Screens.Play StoryboardContainer = CreateStoryboardContainer(), new ScalingContainer(ScalingMode.Gameplay) { - Child = new LocalSkinOverrideContainer(working.Skin) + Child = new LocalSkinOverrideContainer(working.Skin, ScoreProcessor.Combo) { RelativeSizeAxes = Axes.Both, Child = DrawableRuleset @@ -267,12 +264,6 @@ namespace osu.Game.Screens.Play private ScheduledDelegate onCompletionEvent; - private void onComboChange(ValueChangedEvent combo) - { - if (combo.NewValue == 0 && combo.OldValue > 20) - sampleComboBreak?.Play(); - } - private void onCompletion() { // Only show the completion screen if the player hasn't failed diff --git a/osu.Game/Skinning/LocalSkinOverrideContainer.cs b/osu.Game/Skinning/LocalSkinOverrideContainer.cs index f1ed14595e..a3606ef00c 100644 --- a/osu.Game/Skinning/LocalSkinOverrideContainer.cs +++ b/osu.Game/Skinning/LocalSkinOverrideContainer.cs @@ -3,6 +3,7 @@ using System; using osu.Framework.Allocation; +using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -23,11 +24,15 @@ namespace osu.Game.Skinning private readonly Bindable beatmapHitsounds = new Bindable(); private readonly ISkin skin; + + private readonly ComboEffects comboEffects; + private ISkinSource fallbackSource; - public LocalSkinOverrideContainer(ISkin skin) + public LocalSkinOverrideContainer(ISkin skin, BindableInt combo) { this.skin = skin; + comboEffects = new ComboEffects(combo); } public Drawable GetDrawableComponent(string componentName) @@ -87,6 +92,9 @@ namespace osu.Game.Skinning beatmapSkins.BindValueChanged(_ => onSourceChanged()); beatmapHitsounds.BindValueChanged(_ => onSourceChanged()); + AudioManager audio = dependencies.Get(); + comboEffects.SampleComboBreak = GetSample(@"Gameplay/combobreak") ?? audio.Samples.Get(@"Gameplay/combobreak"); + return dependencies; } @@ -100,5 +108,21 @@ namespace osu.Game.Skinning if (fallbackSource != null) fallbackSource.SourceChanged -= onSourceChanged; } + + private class ComboEffects + { + public SampleChannel SampleComboBreak; + + public ComboEffects(BindableInt combo) + { + combo.BindValueChanged(onComboChange); + } + + private void onComboChange(ValueChangedEvent combo) + { + if (combo.NewValue == 0 && combo.OldValue > 20) + SampleComboBreak?.Play(); + } + } } } From a22c166575f50867c3761739834c2a490d80863c Mon Sep 17 00:00:00 2001 From: Welsar55 Date: Sat, 29 Jun 2019 11:28:40 -0500 Subject: [PATCH 17/28] Make ComboEffects its own class --- .../Gameplay/TestSceneSkinReloadable.cs | 5 ++- osu.Game/Screens/Play/ComboEffects.cs | 35 +++++++++++++++++++ osu.Game/Screens/Play/Player.cs | 8 +++-- .../Skinning/LocalSkinOverrideContainer.cs | 25 +------------ 4 files changed, 44 insertions(+), 29 deletions(-) create mode 100644 osu.Game/Screens/Play/ComboEffects.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinReloadable.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinReloadable.cs index f03ffea5dc..c7a0df6e9f 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinReloadable.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinReloadable.cs @@ -4,7 +4,6 @@ using System; using NUnit.Framework; using osu.Framework.Audio.Sample; -using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -29,7 +28,7 @@ namespace osu.Game.Tests.Visual.Gameplay Child = new SkinSourceContainer { RelativeSizeAxes = Axes.Both, - Child = new LocalSkinOverrideContainer(secondarySource, new BindableInt()) + Child = new LocalSkinOverrideContainer(secondarySource) { RelativeSizeAxes = Axes.Both, Child = consumer = new SkinConsumer("test", name => new NamedBox("Default Implementation"), source => true) @@ -54,7 +53,7 @@ namespace osu.Game.Tests.Visual.Gameplay Child = new SkinSourceContainer { RelativeSizeAxes = Axes.Both, - Child = target = new LocalSkinOverrideContainer(secondarySource, new BindableInt()) + Child = target = new LocalSkinOverrideContainer(secondarySource) { RelativeSizeAxes = Axes.Both, } diff --git a/osu.Game/Screens/Play/ComboEffects.cs b/osu.Game/Screens/Play/ComboEffects.cs new file mode 100644 index 0000000000..d752f4a556 --- /dev/null +++ b/osu.Game/Screens/Play/ComboEffects.cs @@ -0,0 +1,35 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; +using osu.Framework.Bindables; +using osu.Framework.Graphics.Containers; +using osu.Game.Rulesets.Scoring; +using osu.Game.Skinning; + +namespace osu.Game.Screens.Play +{ + public class ComboEffects : CompositeDrawable + { + private SampleChannel sampleComboBreak; + + public ComboEffects(ScoreProcessor processor) + { + processor.Combo.BindValueChanged(onComboChange); + } + + private void onComboChange(ValueChangedEvent combo) + { + if (combo.NewValue == 0 && combo.OldValue > 20) + sampleComboBreak?.Play(); + } + + [BackgroundDependencyLoader] + private void load(ISkinSource skin, AudioManager audio) + { + sampleComboBreak = skin.GetSample(@"Gameplay/combobreak") ?? audio.Samples.Get(@"Gameplay/combobreak"); + } + } +} \ No newline at end of file diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 55d43bb4c8..7c4863fbf5 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -124,10 +124,14 @@ namespace osu.Game.Screens.Play StoryboardContainer = CreateStoryboardContainer(), new ScalingContainer(ScalingMode.Gameplay) { - Child = new LocalSkinOverrideContainer(working.Skin, ScoreProcessor.Combo) + Child = new LocalSkinOverrideContainer(working.Skin) { RelativeSizeAxes = Axes.Both, - Child = DrawableRuleset + Children = new Drawable[] + { + DrawableRuleset, + new ComboEffects(ScoreProcessor) + } } }, new BreakOverlay(working.Beatmap.BeatmapInfo.LetterboxInBreaks, ScoreProcessor) diff --git a/osu.Game/Skinning/LocalSkinOverrideContainer.cs b/osu.Game/Skinning/LocalSkinOverrideContainer.cs index a3606ef00c..37f4cc28a2 100644 --- a/osu.Game/Skinning/LocalSkinOverrideContainer.cs +++ b/osu.Game/Skinning/LocalSkinOverrideContainer.cs @@ -3,7 +3,6 @@ using System; using osu.Framework.Allocation; -using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -25,14 +24,11 @@ namespace osu.Game.Skinning private readonly ISkin skin; - private readonly ComboEffects comboEffects; - private ISkinSource fallbackSource; - public LocalSkinOverrideContainer(ISkin skin, BindableInt combo) + public LocalSkinOverrideContainer(ISkin skin) { this.skin = skin; - comboEffects = new ComboEffects(combo); } public Drawable GetDrawableComponent(string componentName) @@ -92,9 +88,6 @@ namespace osu.Game.Skinning beatmapSkins.BindValueChanged(_ => onSourceChanged()); beatmapHitsounds.BindValueChanged(_ => onSourceChanged()); - AudioManager audio = dependencies.Get(); - comboEffects.SampleComboBreak = GetSample(@"Gameplay/combobreak") ?? audio.Samples.Get(@"Gameplay/combobreak"); - return dependencies; } @@ -108,21 +101,5 @@ namespace osu.Game.Skinning if (fallbackSource != null) fallbackSource.SourceChanged -= onSourceChanged; } - - private class ComboEffects - { - public SampleChannel SampleComboBreak; - - public ComboEffects(BindableInt combo) - { - combo.BindValueChanged(onComboChange); - } - - private void onComboChange(ValueChangedEvent combo) - { - if (combo.NewValue == 0 && combo.OldValue > 20) - SampleComboBreak?.Play(); - } - } } } From dbb1369eaffc650371d99af750e1eb566d44e91f Mon Sep 17 00:00:00 2001 From: Welsar55 Date: Sat, 29 Jun 2019 11:54:02 -0500 Subject: [PATCH 18/28] Use resources build 627 --- 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 9dd8c8572e..5f02a75470 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -14,7 +14,7 @@ - + From 9a617dd1432ce16285e8fbee015553ed7c4cbd4b Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 30 Jun 2019 03:16:58 +0300 Subject: [PATCH 19/28] Add Venera Medium in Store --- osu.Game/OsuGameBase.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 3bdf37d769..491c96e98d 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -154,6 +154,7 @@ namespace osu.Game Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Venera")); Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Venera-Light")); + Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Venera-Medium")); runMigrations(); From 60ea3d4e1aeeed90a359ad4155f00c2bafc9c7b3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 30 Jun 2019 21:58:30 +0900 Subject: [PATCH 20/28] Fix skinning support for combobreak --- .../Objects/JuiceStream.cs | 4 +- .../Beatmaps/ManiaBeatmapConverter.cs | 2 +- .../Legacy/DistanceObjectPatternGenerator.cs | 6 +- .../Legacy/EndTimeObjectPatternGenerator.cs | 6 +- .../Legacy/HitObjectPatternGenerator.cs | 8 +-- .../TestSceneSlider.cs | 10 +-- osu.Game.Rulesets.Osu/Objects/Slider.cs | 10 +-- .../TestSceneInputDrum.cs | 2 +- .../Audio/DrumSampleMapping.cs | 6 +- .../Beatmaps/TaikoBeatmapConverter.cs | 14 ++-- .../Drawables/DrawableTaikoHitObject.cs | 2 +- .../Formats/LegacyBeatmapDecoderTest.cs | 38 +++++----- .../Beatmaps/Formats/OsuJsonDecoderTest.cs | 4 +- osu.Game/Audio/HitSampleInfo.cs | 70 +++++++++++++++++++ osu.Game/Audio/ISampleInfo.cs | 17 +++++ osu.Game/Audio/SampleInfo.cs | 65 +++-------------- .../ControlPoints/SampleControlPoint.cs | 18 ++--- osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 4 +- .../Objects/Drawables/DrawableHitObject.cs | 4 +- osu.Game/Rulesets/Objects/HitObject.cs | 6 +- .../Legacy/Catch/ConvertHitObjectParser.cs | 2 +- .../Objects/Legacy/ConvertHitObjectParser.cs | 32 ++++----- .../Rulesets/Objects/Legacy/ConvertSlider.cs | 2 +- .../Legacy/Mania/ConvertHitObjectParser.cs | 2 +- .../Legacy/Osu/ConvertHitObjectParser.cs | 2 +- .../Legacy/Taiko/ConvertHitObjectParser.cs | 2 +- .../Rulesets/Objects/Types/IHasRepeats.cs | 2 +- osu.Game/Screens/Play/ComboEffects.cs | 31 ++++---- osu.Game/Skinning/SkinnableSound.cs | 16 +++-- 29 files changed, 222 insertions(+), 165 deletions(-) create mode 100644 osu.Game/Audio/HitSampleInfo.cs create mode 100644 osu.Game/Audio/ISampleInfo.cs diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index a9fd34455a..0952e8981a 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -46,7 +46,7 @@ namespace osu.Game.Rulesets.Catch.Objects { base.CreateNestedHitObjects(); - var tickSamples = Samples.Select(s => new SampleInfo + var tickSamples = Samples.Select(s => new HitSampleInfo { Bank = s.Bank, Name = @"slidertick", @@ -126,7 +126,7 @@ namespace osu.Game.Rulesets.Catch.Objects public double Distance => Path.Distance; - public List> NodeSamples { get; set; } = new List>(); + public List> NodeSamples { get; set; } = new List>(); public double? LegacyLastTickOffset { get; set; } } diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs index 704deba78b..e10602312e 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs @@ -255,7 +255,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps /// /// The time to retrieve the sample info list from. /// - private List sampleInfoListAt(double time) + private List sampleInfoListAt(double time) { var curveData = HitObject as IHasCurve; diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs index 1b6ff16388..ea418eedb4 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs @@ -364,7 +364,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy break; } - bool isDoubleSample(SampleInfo sample) => sample.Name == SampleInfo.HIT_CLAP || sample.Name == SampleInfo.HIT_FINISH; + bool isDoubleSample(HitSampleInfo sample) => sample.Name == HitSampleInfo.HIT_CLAP || sample.Name == HitSampleInfo.HIT_FINISH; bool canGenerateTwoNotes = !convertType.HasFlag(PatternType.LowProbability); canGenerateTwoNotes &= HitObject.Samples.Any(isDoubleSample) || sampleInfoListAt(HitObject.StartTime).Any(isDoubleSample); @@ -443,7 +443,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy noteCount = 0; noteCount = Math.Min(TotalColumns - 1, noteCount); - bool ignoreHead = !sampleInfoListAt(startTime).Any(s => s.Name == SampleInfo.HIT_WHISTLE || s.Name == SampleInfo.HIT_FINISH || s.Name == SampleInfo.HIT_CLAP); + bool ignoreHead = !sampleInfoListAt(startTime).Any(s => s.Name == HitSampleInfo.HIT_WHISTLE || s.Name == HitSampleInfo.HIT_FINISH || s.Name == HitSampleInfo.HIT_CLAP); var rowPattern = new Pattern(); @@ -472,7 +472,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy /// /// The time to retrieve the sample info list from. /// - private List sampleInfoListAt(double time) + private List sampleInfoListAt(double time) { var curveData = HitObject as IHasCurve; diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs index 9e95be35fa..b3be08e1f7 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs @@ -35,7 +35,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy switch (TotalColumns) { - case 8 when HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_FINISH) && endTime - HitObject.StartTime < 1000: + case 8 when HitObject.Samples.Any(s => s.Name == HitSampleInfo.HIT_FINISH) && endTime - HitObject.StartTime < 1000: addToPattern(pattern, 0, generateHold); break; @@ -72,9 +72,9 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy }; if (hold.Head.Samples == null) - hold.Head.Samples = new List(); + hold.Head.Samples = new List(); - hold.Head.Samples.Add(new SampleInfo { Name = SampleInfo.HIT_NORMAL }); + hold.Head.Samples.Add(new HitSampleInfo { Name = HitSampleInfo.HIT_NORMAL }); hold.Tail.Samples = HitObject.Samples; diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs index d13b21183b..decd159ee9 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs @@ -79,9 +79,9 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy if (!convertType.HasFlag(PatternType.KeepSingle)) { - if (HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_FINISH) && TotalColumns != 8) + if (HitObject.Samples.Any(s => s.Name == HitSampleInfo.HIT_FINISH) && TotalColumns != 8) convertType |= PatternType.Mirror; - else if (HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_CLAP)) + else if (HitObject.Samples.Any(s => s.Name == HitSampleInfo.HIT_CLAP)) convertType |= PatternType.Gathered; } } @@ -263,7 +263,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy /// /// Whether this hit object can generate a note in the special column. /// - private bool hasSpecialColumn => HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_CLAP) && HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_FINISH); + private bool hasSpecialColumn => HitObject.Samples.Any(s => s.Name == HitSampleInfo.HIT_CLAP) && HitObject.Samples.Any(s => s.Name == HitSampleInfo.HIT_FINISH); /// /// Generates a random pattern. @@ -364,7 +364,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy break; } - if (HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_CLAP)) + if (HitObject.Samples.Any(s => s.Name == HitSampleInfo.HIT_CLAP)) p2 = 1; return GetRandomNoteCount(p2, p3, p4, p5); diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs index 1ba6d107be..c5a27205d6 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs @@ -248,9 +248,9 @@ namespace osu.Game.Rulesets.Osu.Tests private void createCatmull(int repeats = 0) { - var repeatSamples = new List>(); + var repeatSamples = new List>(); for (int i = 0; i < repeats; i++) - repeatSamples.Add(new List()); + repeatSamples.Add(new List()); var slider = new Slider { @@ -270,11 +270,11 @@ namespace osu.Game.Rulesets.Osu.Tests addSlider(slider, 3, 1); } - private List> createEmptySamples(int repeats) + private List> createEmptySamples(int repeats) { - var repeatSamples = new List>(); + var repeatSamples = new List>(); for (int i = 0; i < repeats; i++) - repeatSamples.Add(new List()); + repeatSamples.Add(new List()); return repeatSamples; } diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index a8aec005d1..a4638c31f2 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -99,7 +99,7 @@ namespace osu.Game.Rulesets.Osu.Objects /// internal float LazyTravelDistance; - public List> NodeSamples { get; set; } = new List>(); + public List> NodeSamples { get; set; } = new List>(); private int repeatCount; @@ -157,12 +157,12 @@ namespace osu.Game.Rulesets.Osu.Objects foreach (var e in SliderEventGenerator.Generate(StartTime, SpanDuration, Velocity, TickDistance, Path.Distance, this.SpanCount(), LegacyLastTickOffset)) { - var firstSample = Samples.Find(s => s.Name == SampleInfo.HIT_NORMAL) + var firstSample = Samples.Find(s => s.Name == HitSampleInfo.HIT_NORMAL) ?? Samples.FirstOrDefault(); // TODO: remove this when guaranteed sort is present for samples (https://github.com/ppy/osu/issues/1933) - var sampleList = new List(); + var sampleList = new List(); if (firstSample != null) - sampleList.Add(new SampleInfo + sampleList.Add(new HitSampleInfo { Bank = firstSample.Bank, Volume = firstSample.Volume, @@ -225,7 +225,7 @@ namespace osu.Game.Rulesets.Osu.Objects } } - private List getNodeSamples(int nodeIndex) => + private List getNodeSamples(int nodeIndex) => nodeIndex < NodeSamples.Count ? NodeSamples[nodeIndex] : Samples; public override Judgement CreateJudgement() => new OsuJudgement(); diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneInputDrum.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneInputDrum.cs index 02300a5dde..8c1b0c4c62 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TestSceneInputDrum.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneInputDrum.cs @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Taiko.Tests { typeof(InputDrum), typeof(DrumSampleMapping), - typeof(SampleInfo), + typeof(HitSampleInfo), typeof(SampleControlPoint) }; diff --git a/osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs b/osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs index d7fa661e8a..ad2596931d 100644 --- a/osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs +++ b/osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs @@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Taiko.Audio foreach (var s in samplePoints) { var centre = s.GetSampleInfo(); - var rim = s.GetSampleInfo(SampleInfo.HIT_CLAP); + var rim = s.GetSampleInfo(HitSampleInfo.HIT_CLAP); // todo: this is ugly centre.Namespace = "taiko"; @@ -43,9 +43,9 @@ namespace osu.Game.Rulesets.Taiko.Audio } } - private SkinnableSound addSound(SampleInfo sampleInfo) + private SkinnableSound addSound(HitSampleInfo hitSampleInfo) { - var drawable = new SkinnableSound(sampleInfo); + var drawable = new SkinnableSound(hitSampleInfo); Sounds.Add(drawable); return drawable; } diff --git a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs index f8672037cd..f0cf8d9c7d 100644 --- a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs +++ b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs @@ -79,9 +79,9 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps var curveData = obj as IHasCurve; // Old osu! used hit sounding to determine various hit type information - List samples = obj.Samples; + List samples = obj.Samples; - bool strong = samples.Any(s => s.Name == SampleInfo.HIT_FINISH); + bool strong = samples.Any(s => s.Name == HitSampleInfo.HIT_FINISH); if (distanceData != null) { @@ -117,15 +117,15 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps if (!isForCurrentRuleset && tickSpacing > 0 && osuDuration < 2 * speedAdjustedBeatLength) { - List> allSamples = curveData != null ? curveData.NodeSamples : 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) { - List currentSamples = allSamples[i]; - bool isRim = currentSamples.Any(s => s.Name == SampleInfo.HIT_CLAP || s.Name == SampleInfo.HIT_WHISTLE); - strong = currentSamples.Any(s => s.Name == SampleInfo.HIT_FINISH); + List currentSamples = allSamples[i]; + bool isRim = currentSamples.Any(s => s.Name == HitSampleInfo.HIT_CLAP || s.Name == HitSampleInfo.HIT_WHISTLE); + strong = currentSamples.Any(s => s.Name == HitSampleInfo.HIT_FINISH); if (isRim) { @@ -175,7 +175,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps } else { - bool isRim = samples.Any(s => s.Name == SampleInfo.HIT_CLAP || s.Name == SampleInfo.HIT_WHISTLE); + bool isRim = samples.Any(s => s.Name == HitSampleInfo.HIT_CLAP || s.Name == HitSampleInfo.HIT_WHISTLE); if (isRim) { diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs index 119940536e..bd45b52d7b 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs @@ -122,7 +122,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables } // Normal and clap samples are handled by the drum - protected override IEnumerable GetSamples() => HitObject.Samples.Where(s => s.Name != SampleInfo.HIT_NORMAL && s.Name != SampleInfo.HIT_CLAP); + protected override IEnumerable GetSamples() => HitObject.Samples.Where(s => s.Name != HitSampleInfo.HIT_NORMAL && s.Name != HitSampleInfo.HIT_CLAP); protected override string SampleNamespace => "Taiko"; diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index 5fd5fe342d..d087251e7e 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -354,14 +354,14 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.IsNotNull(curveData); Assert.AreEqual(new Vector2(192, 168), positionData.Position); Assert.AreEqual(956, hitObjects[0].StartTime); - Assert.IsTrue(hitObjects[0].Samples.Any(s => s.Name == SampleInfo.HIT_NORMAL)); + Assert.IsTrue(hitObjects[0].Samples.Any(s => s.Name == HitSampleInfo.HIT_NORMAL)); positionData = hitObjects[1] as IHasPosition; Assert.IsNotNull(positionData); Assert.AreEqual(new Vector2(304, 56), positionData.Position); Assert.AreEqual(1285, hitObjects[1].StartTime); - Assert.IsTrue(hitObjects[1].Samples.Any(s => s.Name == SampleInfo.HIT_CLAP)); + Assert.IsTrue(hitObjects[1].Samples.Any(s => s.Name == HitSampleInfo.HIT_CLAP)); } } @@ -384,7 +384,7 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.AreEqual("soft-hitnormal8", getTestableSampleInfo(hitObjects[4]).LookupNames.First()); } - SampleInfo getTestableSampleInfo(HitObject hitObject) => hitObject.SampleControlPoint.ApplyTo(hitObject.Samples[0]); + HitSampleInfo getTestableSampleInfo(HitObject hitObject) => hitObject.SampleControlPoint.ApplyTo(hitObject.Samples[0]); } [Test] @@ -402,7 +402,7 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.AreEqual("normal-hitnormal3", getTestableSampleInfo(hitObjects[2]).LookupNames.First()); } - SampleInfo getTestableSampleInfo(HitObject hitObject) => hitObject.SampleControlPoint.ApplyTo(hitObject.Samples[0]); + HitSampleInfo getTestableSampleInfo(HitObject hitObject) => hitObject.SampleControlPoint.ApplyTo(hitObject.Samples[0]); } [Test] @@ -422,7 +422,7 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.AreEqual(70, getTestableSampleInfo(hitObjects[3]).Volume); } - SampleInfo getTestableSampleInfo(HitObject hitObject) => hitObject.SampleControlPoint.ApplyTo(hitObject.Samples[0]); + HitSampleInfo getTestableSampleInfo(HitObject hitObject) => hitObject.SampleControlPoint.ApplyTo(hitObject.Samples[0]); } [Test] @@ -438,34 +438,34 @@ namespace osu.Game.Tests.Beatmaps.Formats var slider1 = (ConvertSlider)hitObjects[0]; Assert.AreEqual(1, slider1.NodeSamples[0].Count); - Assert.AreEqual(SampleInfo.HIT_NORMAL, slider1.NodeSamples[0][0].Name); + Assert.AreEqual(HitSampleInfo.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(HitSampleInfo.HIT_NORMAL, slider1.NodeSamples[1][0].Name); Assert.AreEqual(1, slider1.NodeSamples[2].Count); - Assert.AreEqual(SampleInfo.HIT_NORMAL, slider1.NodeSamples[2][0].Name); + Assert.AreEqual(HitSampleInfo.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(HitSampleInfo.HIT_NORMAL, slider2.NodeSamples[0][0].Name); + Assert.AreEqual(HitSampleInfo.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(HitSampleInfo.HIT_NORMAL, slider2.NodeSamples[1][0].Name); + Assert.AreEqual(HitSampleInfo.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); + Assert.AreEqual(HitSampleInfo.HIT_NORMAL, slider2.NodeSamples[2][0].Name); + Assert.AreEqual(HitSampleInfo.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(HitSampleInfo.HIT_NORMAL, slider3.NodeSamples[0][0].Name); + Assert.AreEqual(HitSampleInfo.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(HitSampleInfo.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); + Assert.AreEqual(HitSampleInfo.HIT_NORMAL, slider3.NodeSamples[2][0].Name); + Assert.AreEqual(HitSampleInfo.HIT_CLAP, slider3.NodeSamples[2][1].Name); } } diff --git a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs index 39b7735a55..a725c58462 100644 --- a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs @@ -101,14 +101,14 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.IsNotNull(curveData); Assert.AreEqual(new Vector2(192, 168), positionData.Position); Assert.AreEqual(956, beatmap.HitObjects[0].StartTime); - Assert.IsTrue(beatmap.HitObjects[0].Samples.Any(s => s.Name == SampleInfo.HIT_NORMAL)); + Assert.IsTrue(beatmap.HitObjects[0].Samples.Any(s => s.Name == HitSampleInfo.HIT_NORMAL)); positionData = beatmap.HitObjects[1] as IHasPosition; Assert.IsNotNull(positionData); Assert.AreEqual(new Vector2(304, 56), positionData.Position); Assert.AreEqual(1285, beatmap.HitObjects[1].StartTime); - Assert.IsTrue(beatmap.HitObjects[1].Samples.Any(s => s.Name == SampleInfo.HIT_CLAP)); + Assert.IsTrue(beatmap.HitObjects[1].Samples.Any(s => s.Name == HitSampleInfo.HIT_CLAP)); } [TestCase(normal)] diff --git a/osu.Game/Audio/HitSampleInfo.cs b/osu.Game/Audio/HitSampleInfo.cs new file mode 100644 index 0000000000..23a74d3fa6 --- /dev/null +++ b/osu.Game/Audio/HitSampleInfo.cs @@ -0,0 +1,70 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; + +namespace osu.Game.Audio +{ + /// + /// Describes a gameplay hit sample. + /// + [Serializable] + public class HitSampleInfo : ISampleInfo + { + public const string HIT_WHISTLE = @"hitwhistle"; + public const string HIT_FINISH = @"hitfinish"; + public const string HIT_NORMAL = @"hitnormal"; + public const string HIT_CLAP = @"hitclap"; + + /// + /// An optional ruleset namespace. + /// + public string Namespace; + + /// + /// The bank to load the sample from. + /// + public string Bank; + + /// + /// The name of the sample to load. + /// + public string Name; + + /// + /// An optional suffix to provide priority lookup. Falls back to non-suffixed . + /// + public string Suffix; + + /// + /// The sample volume. + /// + public int Volume { get; set; } + + /// + /// Retrieve all possible filenames that can be used as a source, returned in order of preference (highest first). + /// + public virtual IEnumerable LookupNames + { + get + { + if (!string.IsNullOrEmpty(Namespace)) + { + if (!string.IsNullOrEmpty(Suffix)) + yield return $"{Namespace}/{Bank}-{Name}{Suffix}"; + + yield return $"{Namespace}/{Bank}-{Name}"; + } + + // check non-namespace as a fallback even when we have a namespace + if (!string.IsNullOrEmpty(Suffix)) + yield return $"{Bank}-{Name}{Suffix}"; + + yield return $"{Bank}-{Name}"; + } + } + + public HitSampleInfo Clone() => (HitSampleInfo)MemberwiseClone(); + } +} diff --git a/osu.Game/Audio/ISampleInfo.cs b/osu.Game/Audio/ISampleInfo.cs new file mode 100644 index 0000000000..4f81d37e78 --- /dev/null +++ b/osu.Game/Audio/ISampleInfo.cs @@ -0,0 +1,17 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; + +namespace osu.Game.Audio +{ + public interface ISampleInfo + { + /// + /// Retrieve all possible filenames that can be used as a source, returned in order of preference (highest first). + /// + IEnumerable LookupNames { get; } + + int Volume { get; } + } +} diff --git a/osu.Game/Audio/SampleInfo.cs b/osu.Game/Audio/SampleInfo.cs index 5bc6dce60b..66c07209f3 100644 --- a/osu.Game/Audio/SampleInfo.cs +++ b/osu.Game/Audio/SampleInfo.cs @@ -1,67 +1,24 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; using System.Collections.Generic; namespace osu.Game.Audio { - [Serializable] - public class SampleInfo + /// + /// Describes a gameplay sample. + /// + public class SampleInfo : ISampleInfo { - public const string HIT_WHISTLE = @"hitwhistle"; - public const string HIT_FINISH = @"hitfinish"; - public const string HIT_NORMAL = @"hitnormal"; - public const string HIT_CLAP = @"hitclap"; + private readonly string sampleName; - /// - /// An optional ruleset namespace. - /// - public string Namespace; - - /// - /// The bank to load the sample from. - /// - public string Bank; - - /// - /// The name of the sample to load. - /// - public string Name; - - /// - /// An optional suffix to provide priority lookup. Falls back to non-suffixed . - /// - public string Suffix; - - /// - /// The sample volume. - /// - public int Volume; - - /// - /// Retrieve all possible filenames that can be used as a source, returned in order of preference (highest first). - /// - public virtual IEnumerable LookupNames + public SampleInfo(string sampleName) { - get - { - if (!string.IsNullOrEmpty(Namespace)) - { - if (!string.IsNullOrEmpty(Suffix)) - yield return $"{Namespace}/{Bank}-{Name}{Suffix}"; - - yield return $"{Namespace}/{Bank}-{Name}"; - } - - // check non-namespace as a fallback even when we have a namespace - if (!string.IsNullOrEmpty(Suffix)) - yield return $"{Bank}-{Name}{Suffix}"; - - yield return $"{Bank}-{Name}"; - } + this.sampleName = sampleName; } - public SampleInfo Clone() => (SampleInfo)MemberwiseClone(); + public IEnumerable LookupNames => new[] { sampleName }; + + public int Volume { get; set; } = 100; } } diff --git a/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs index 4c45bef862..7bc7a9056d 100644 --- a/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs @@ -24,8 +24,8 @@ namespace osu.Game.Beatmaps.ControlPoints /// Create a SampleInfo based on the sample settings in this control point. /// /// The name of the same. - /// A populated . - public SampleInfo GetSampleInfo(string sampleName = SampleInfo.HIT_NORMAL) => new SampleInfo + /// A populated . + public HitSampleInfo GetSampleInfo(string sampleName = HitSampleInfo.HIT_NORMAL) => new HitSampleInfo { Bank = SampleBank, Name = sampleName, @@ -33,15 +33,15 @@ namespace osu.Game.Beatmaps.ControlPoints }; /// - /// Applies and to a if necessary, returning the modified . + /// Applies and to a if necessary, returning the modified . /// - /// The . This will not be modified. - /// The modified . This does not share a reference with . - public virtual SampleInfo ApplyTo(SampleInfo sampleInfo) + /// The . This will not be modified. + /// The modified . This does not share a reference with . + public virtual HitSampleInfo ApplyTo(HitSampleInfo hitSampleInfo) { - var newSampleInfo = sampleInfo.Clone(); - newSampleInfo.Bank = sampleInfo.Bank ?? SampleBank; - newSampleInfo.Volume = sampleInfo.Volume > 0 ? sampleInfo.Volume : SampleVolume; + var newSampleInfo = hitSampleInfo.Clone(); + newSampleInfo.Bank = hitSampleInfo.Bank ?? SampleBank; + newSampleInfo.Volume = hitSampleInfo.Volume > 0 ? hitSampleInfo.Volume : SampleVolume; return newSampleInfo; } diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index 7b7e0e7101..7999c82761 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -193,9 +193,9 @@ namespace osu.Game.Beatmaps.Formats { public int CustomSampleBank; - public override SampleInfo ApplyTo(SampleInfo sampleInfo) + public override HitSampleInfo ApplyTo(HitSampleInfo hitSampleInfo) { - var baseInfo = base.ApplyTo(sampleInfo); + var baseInfo = base.ApplyTo(hitSampleInfo); if (string.IsNullOrEmpty(baseInfo.Suffix) && CustomSampleBank > 1) baseInfo.Suffix = CustomSampleBank.ToString(); diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 35c3a0e5e4..1f6ca4dd73 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Objects.Drawables protected SkinnableSound Samples; - protected virtual IEnumerable GetSamples() => HitObject.Samples; + protected virtual IEnumerable GetSamples() => HitObject.Samples; private readonly Lazy> nestedHitObjects = new Lazy>(); public IEnumerable NestedHitObjects => nestedHitObjects.IsValueCreated ? nestedHitObjects.Value : Enumerable.Empty(); @@ -104,7 +104,7 @@ namespace osu.Game.Rulesets.Objects.Drawables var samples = GetSamples().ToArray(); - if (samples.Any()) + if (samples.Length > 0) { if (HitObject.SampleControlPoint == null) throw new ArgumentNullException(nameof(HitObject.SampleControlPoint), $"{nameof(HitObject)}s must always have an attached {nameof(HitObject.SampleControlPoint)}." diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index cede2e50d0..bf04963b76 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.cs @@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Objects /// public virtual double StartTime { get; set; } - private List samples; + private List samples; /// /// The samples to be played when this hit object is hit. @@ -38,9 +38,9 @@ namespace osu.Game.Rulesets.Objects /// and can be treated as the default samples for the hit object. /// /// - public List Samples + public List Samples { - get => samples ?? (samples = new List()); + get => samples ?? (samples = new List()); set => samples = value; } diff --git a/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs index 48f637dfe8..6e79d0b766 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, PathType pathType, int repeatCount, List> nodeSamples) + protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, PathType pathType, int repeatCount, List> nodeSamples) { newCombo |= forceNewCombo; comboOffset += extraComboOffset; diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs index c14f3b6a42..f5b1cbcebf 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs @@ -180,7 +180,7 @@ namespace osu.Game.Rulesets.Objects.Legacy } // Generate the final per-node samples - var nodeSamples = new List>(nodes); + var nodeSamples = new List>(nodes); for (int i = 0; i < nodes; i++) nodeSamples.Add(convertSoundType(nodeSoundTypes[i], nodeBankInfos[i])); @@ -291,7 +291,7 @@ namespace osu.Game.Rulesets.Objects.Legacy /// The slider repeat count. /// 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, Vector2[] controlPoints, double length, PathType pathType, int repeatCount, List> nodeSamples); + protected abstract HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, PathType pathType, int repeatCount, List> nodeSamples); /// /// Creates a legacy Spinner-type hit object. @@ -312,14 +312,14 @@ namespace osu.Game.Rulesets.Objects.Legacy /// The hold end time. protected abstract HitObject CreateHold(Vector2 position, bool newCombo, int comboOffset, double endTime); - private List convertSoundType(LegacySoundType type, SampleBankInfo bankInfo) + private List convertSoundType(LegacySoundType type, SampleBankInfo bankInfo) { // Todo: This should return the normal SampleInfos if the specified sample file isn't found, but that's a pretty edge-case scenario if (!string.IsNullOrEmpty(bankInfo.Filename)) { - return new List + return new List { - new FileSampleInfo + new FileHitSampleInfo { Filename = bankInfo.Filename, Volume = bankInfo.Volume @@ -327,12 +327,12 @@ namespace osu.Game.Rulesets.Objects.Legacy }; } - var soundTypes = new List + var soundTypes = new List { - new LegacySampleInfo + new LegacyHitSampleInfo { Bank = bankInfo.Normal, - Name = SampleInfo.HIT_NORMAL, + Name = HitSampleInfo.HIT_NORMAL, Volume = bankInfo.Volume, CustomSampleBank = bankInfo.CustomSampleBank } @@ -340,10 +340,10 @@ namespace osu.Game.Rulesets.Objects.Legacy if (type.HasFlag(LegacySoundType.Finish)) { - soundTypes.Add(new LegacySampleInfo + soundTypes.Add(new LegacyHitSampleInfo { Bank = bankInfo.Add, - Name = SampleInfo.HIT_FINISH, + Name = HitSampleInfo.HIT_FINISH, Volume = bankInfo.Volume, CustomSampleBank = bankInfo.CustomSampleBank }); @@ -351,10 +351,10 @@ namespace osu.Game.Rulesets.Objects.Legacy if (type.HasFlag(LegacySoundType.Whistle)) { - soundTypes.Add(new LegacySampleInfo + soundTypes.Add(new LegacyHitSampleInfo { Bank = bankInfo.Add, - Name = SampleInfo.HIT_WHISTLE, + Name = HitSampleInfo.HIT_WHISTLE, Volume = bankInfo.Volume, CustomSampleBank = bankInfo.CustomSampleBank }); @@ -362,10 +362,10 @@ namespace osu.Game.Rulesets.Objects.Legacy if (type.HasFlag(LegacySoundType.Clap)) { - soundTypes.Add(new LegacySampleInfo + soundTypes.Add(new LegacyHitSampleInfo { Bank = bankInfo.Add, - Name = SampleInfo.HIT_CLAP, + Name = HitSampleInfo.HIT_CLAP, Volume = bankInfo.Volume, CustomSampleBank = bankInfo.CustomSampleBank }); @@ -387,7 +387,7 @@ namespace osu.Game.Rulesets.Objects.Legacy public SampleBankInfo Clone() => (SampleBankInfo)MemberwiseClone(); } - private class LegacySampleInfo : SampleInfo + private class LegacyHitSampleInfo : HitSampleInfo { public int CustomSampleBank { @@ -399,7 +399,7 @@ namespace osu.Game.Rulesets.Objects.Legacy } } - private class FileSampleInfo : SampleInfo + private class FileHitSampleInfo : HitSampleInfo { public string Filename; diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs index bb1a5e200d..ff6b9be8b5 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Objects.Legacy public double Distance => Path.Distance; - public List> NodeSamples { 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 8a3e232e60..b20a027e78 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, Vector2[] controlPoints, double length, PathType pathType, int repeatCount, List> nodeSamples) + protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, PathType pathType, int repeatCount, List> nodeSamples) { return new ConvertSlider { diff --git a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs index b98de32bd0..0a4e38df02 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, PathType pathType, int repeatCount, List> nodeSamples) + protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, PathType pathType, int repeatCount, List> nodeSamples) { newCombo |= forceNewCombo; comboOffset += extraComboOffset; diff --git a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs index bab21b31ad..7c1514c1eb 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko return new ConvertHit(); } - protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, PathType pathType, int repeatCount, List> nodeSamples) + protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, PathType pathType, int repeatCount, List> nodeSamples) { return new ConvertSlider { diff --git a/osu.Game/Rulesets/Objects/Types/IHasRepeats.cs b/osu.Game/Rulesets/Objects/Types/IHasRepeats.cs index 8be95c063d..697adeda98 100644 --- a/osu.Game/Rulesets/Objects/Types/IHasRepeats.cs +++ b/osu.Game/Rulesets/Objects/Types/IHasRepeats.cs @@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Objects.Types /// n-1: The last repeat.
/// n: The last node. ///
- List> NodeSamples { get; } + List> NodeSamples { get; } } public static class HasRepeatsExtensions diff --git a/osu.Game/Screens/Play/ComboEffects.cs b/osu.Game/Screens/Play/ComboEffects.cs index d752f4a556..1c4ac921f0 100644 --- a/osu.Game/Screens/Play/ComboEffects.cs +++ b/osu.Game/Screens/Play/ComboEffects.cs @@ -2,10 +2,9 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; -using osu.Framework.Audio; -using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics.Containers; +using osu.Game.Audio; using osu.Game.Rulesets.Scoring; using osu.Game.Skinning; @@ -13,23 +12,31 @@ namespace osu.Game.Screens.Play { public class ComboEffects : CompositeDrawable { - private SampleChannel sampleComboBreak; + private readonly ScoreProcessor processor; + + private SkinnableSound comboBreakSample; public ComboEffects(ScoreProcessor processor) { - processor.Combo.BindValueChanged(onComboChange); + this.processor = processor; + } + + [BackgroundDependencyLoader] + private void load() + { + InternalChild = comboBreakSample = new SkinnableSound(new SampleInfo("combobreak")); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + processor.Combo.BindValueChanged(onComboChange, true); } private void onComboChange(ValueChangedEvent combo) { if (combo.NewValue == 0 && combo.OldValue > 20) - sampleComboBreak?.Play(); - } - - [BackgroundDependencyLoader] - private void load(ISkinSource skin, AudioManager audio) - { - sampleComboBreak = skin.GetSample(@"Gameplay/combobreak") ?? audio.Samples.Get(@"Gameplay/combobreak"); + comboBreakSample?.Play(); } } -} \ No newline at end of file +} diff --git a/osu.Game/Skinning/SkinnableSound.cs b/osu.Game/Skinning/SkinnableSound.cs index e88e088f5e..8e2b5cec98 100644 --- a/osu.Game/Skinning/SkinnableSound.cs +++ b/osu.Game/Skinning/SkinnableSound.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Audio; @@ -13,14 +14,19 @@ namespace osu.Game.Skinning { public class SkinnableSound : SkinReloadableDrawable { - private readonly SampleInfo[] samples; + private readonly ISampleInfo[] hitSamples; private SampleChannel[] channels; private AudioManager audio; - public SkinnableSound(params SampleInfo[] samples) + public SkinnableSound(IEnumerable hitSamples) { - this.samples = samples; + this.hitSamples = hitSamples.ToArray(); + } + + public SkinnableSound(ISampleInfo hitSamples) + { + this.hitSamples = new[] { hitSamples }; } [BackgroundDependencyLoader] @@ -35,7 +41,7 @@ namespace osu.Game.Skinning protected override void SkinChanged(ISkinSource skin, bool allowFallback) { - channels = samples.Select(s => + channels = hitSamples.Select(s => { var ch = loadChannel(s, skin.GetSample); if (ch == null && allowFallback) @@ -44,7 +50,7 @@ namespace osu.Game.Skinning }).Where(c => c != null).ToArray(); } - private SampleChannel loadChannel(SampleInfo info, Func getSampleFunction) + private SampleChannel loadChannel(ISampleInfo info, Func getSampleFunction) { foreach (var lookup in info.LookupNames) { From 489ca7b45786c762b1fea01cdfa60fb5b3e3b40b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 30 Jun 2019 22:26:49 +0900 Subject: [PATCH 21/28] Update resources in ios props --- osu.iOS.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.iOS.props b/osu.iOS.props index ce8b62cc3f..a8013914af 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -104,7 +104,7 @@ - + From f42ded343779ab6d168538892d0dc77d6a3ee00b Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 30 Jun 2019 18:27:47 +0300 Subject: [PATCH 22/28] Move to DrawableOsuHitObject --- osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs | 2 ++ osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs index 10b37af957..eb5b6aab36 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs @@ -18,6 +18,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables { private readonly ShakeContainer shakeContainer; + public override bool HandlePositionalInput => true; + protected DrawableOsuHitObject(OsuHitObject hitObject) : base(hitObject) { diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index cc1a1f370f..1f6ca4dd73 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -81,8 +81,6 @@ namespace osu.Game.Rulesets.Objects.Drawables public override bool RemoveCompletedTransforms => false; protected override bool RequiresChildrenUpdate => true; - public override bool HandlePositionalInput => true; - public override bool IsPresent => base.IsPresent || (State.Value == ArmedState.Idle && Clock?.CurrentTime >= LifetimeStart); public readonly Bindable State = new Bindable(); From d11b799571df4d06973b4955994b94ad0e520da9 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 30 Jun 2019 18:28:20 +0300 Subject: [PATCH 23/28] Add explaining comment --- osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs index eb5b6aab36..f372cb65ce 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs @@ -18,6 +18,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables { private readonly ShakeContainer shakeContainer; + // Must be set to update IsHovered as it's used in relax mdo to detect osu hit objects. public override bool HandlePositionalInput => true; protected DrawableOsuHitObject(OsuHitObject hitObject) From 665da09ed76c5a74bd688ddf2a41c5dd325b3ba7 Mon Sep 17 00:00:00 2001 From: Unknown Date: Mon, 1 Jul 2019 09:45:14 +0200 Subject: [PATCH 24/28] disable HD for taiko --- osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs index 502dd54e9e..a6f902208c 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs @@ -9,5 +9,6 @@ namespace osu.Game.Rulesets.Taiko.Mods { public override string Description => @"Beats fade out before you hit them!"; public override double ScoreMultiplier => 1.06; + public override bool HasImplementation => false; } } From b875ab2f5809623f2b146042d987e8bbeacd57f5 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 1 Jul 2019 12:15:53 +0300 Subject: [PATCH 25/28] Update resources --- 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 b4af007447..5a5f93046c 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -14,7 +14,7 @@ - + From e6c1b059bc7a4899de9a418731d386d5b37d3ca1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 1 Jul 2019 18:49:36 +0900 Subject: [PATCH 26/28] Disable dimming main content --- osu.Game/Overlays/Chat/Selection/ChannelSelectionOverlay.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Overlays/Chat/Selection/ChannelSelectionOverlay.cs b/osu.Game/Overlays/Chat/Selection/ChannelSelectionOverlay.cs index 71e9e4bdf3..e0ded11ec9 100644 --- a/osu.Game/Overlays/Chat/Selection/ChannelSelectionOverlay.cs +++ b/osu.Game/Overlays/Chat/Selection/ChannelSelectionOverlay.cs @@ -32,6 +32,8 @@ namespace osu.Game.Overlays.Chat.Selection private readonly SearchTextBox search; private readonly SearchContainer sectionsFlow; + protected override bool DimMainContent => false; + public Action OnRequestJoin; public Action OnRequestLeave; From e25158f434e6a44bc396e81dd5955c6044c60551 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 1 Jul 2019 19:35:04 +0900 Subject: [PATCH 27/28] Rename move and fix tests --- .../Visual/Online/TestSceneChatOverlay.cs | 135 +++++++++++++++-- .../TestSceneChatOverlayScenarios.cs | 137 ------------------ 2 files changed, 124 insertions(+), 148 deletions(-) delete mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs index c75348112f..4d3992ce13 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs @@ -3,19 +3,23 @@ using System; using System.Collections.Generic; -using System.ComponentModel; +using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.UserInterface; using osu.Game.Online.Chat; using osu.Game.Overlays; using osu.Game.Overlays.Chat; +using osu.Game.Overlays.Chat.Selection; using osu.Game.Overlays.Chat.Tabs; +using osu.Game.Users; +using osuTK.Input; namespace osu.Game.Tests.Visual.Online { - [Description("Testing chat api and overlay")] - public class TestSceneChatOverlay : OsuTestScene + public class TestSceneChatOverlay : ManualInputManagerTestScene { public override IReadOnlyList RequiredTypes => new[] { @@ -28,17 +32,126 @@ namespace osu.Game.Tests.Visual.Online typeof(TabCloseButton) }; - [Cached] - private readonly ChannelManager channelManager = new ChannelManager(); + private TestChatOverlay chatOverlay; + private ChannelManager channelManager; - [BackgroundDependencyLoader] - private void load() + private readonly Channel channel1 = new Channel(new User()) { Name = "test1" }; + private readonly Channel channel2 = new Channel(new User()) { Name = "test2" }; + + [SetUp] + public void Setup() { - Children = new Drawable[] + Schedule(() => { - channelManager, - new ChatOverlay { State = { Value = Visibility.Visible } } - }; + ChannelManagerContainer container; + + Child = container = new ChannelManagerContainer(new List { channel1, channel2 }) + { + RelativeSizeAxes = Axes.Both, + }; + + chatOverlay = container.ChatOverlay; + channelManager = container.ChannelManager; + }); + } + + [Test] + public void TestHideOverlay() + { + AddAssert("Chat overlay is visible", () => chatOverlay.State.Value == Visibility.Visible); + AddAssert("Selector is visible", () => chatOverlay.SelectionOverlayState == Visibility.Visible); + + AddStep("Close chat overlay", () => chatOverlay.Hide()); + + AddAssert("Chat overlay was hidden", () => chatOverlay.State.Value == Visibility.Hidden); + AddAssert("Channel selection overlay was hidden", () => chatOverlay.SelectionOverlayState == Visibility.Hidden); + } + + [Test] + public void TestSelectingChannelClosesSelector() + { + AddAssert("Selector is visible", () => chatOverlay.SelectionOverlayState == Visibility.Visible); + + AddStep("Join channel 1", () => channelManager.JoinChannel(channel1)); + AddStep("Switch to channel 1", () => clickDrawable(chatOverlay.TabMap[channel1])); + + AddAssert("Current channel is channel 1", () => channelManager.CurrentChannel.Value == channel1); + AddAssert("Channel selector was closed", () => chatOverlay.SelectionOverlayState == Visibility.Hidden); + } + + [Test] + public void TestCloseChannelWhileSelectorClosed() + { + AddStep("Join channel 1", () => channelManager.JoinChannel(channel1)); + AddStep("Join channel 2", () => channelManager.JoinChannel(channel2)); + + AddStep("Switch to channel 2", () => clickDrawable(chatOverlay.TabMap[channel2])); + AddStep("Close channel 2", () => clickDrawable(((TestChannelTabItem)chatOverlay.TabMap[channel2]).CloseButton.Child)); + + AddAssert("Selector remained closed", () => chatOverlay.SelectionOverlayState == Visibility.Hidden); + AddAssert("Current channel is channel 1", () => channelManager.CurrentChannel.Value == channel1); + + AddStep("Close channel 1", () => clickDrawable(((TestChannelTabItem)chatOverlay.TabMap[channel1]).CloseButton.Child)); + + AddAssert("Selector is visible", () => chatOverlay.SelectionOverlayState == Visibility.Visible); + } + + private void clickDrawable(Drawable d) + { + InputManager.MoveMouseTo(d); + InputManager.Click(MouseButton.Left); + } + + private class ChannelManagerContainer : Container + { + public TestChatOverlay ChatOverlay { get; private set; } + + [Cached] + public ChannelManager ChannelManager { get; } = new ChannelManager(); + + private readonly List channels; + + public ChannelManagerContainer(List channels) + { + this.channels = channels; + } + + [BackgroundDependencyLoader] + private void load() + { + ((BindableList)ChannelManager.AvailableChannels).AddRange(channels); + + Child = ChatOverlay = new TestChatOverlay { RelativeSizeAxes = Axes.Both, }; + ChatOverlay.Show(); + } + } + + private class TestChatOverlay : ChatOverlay + { + public Visibility SelectionOverlayState => ChannelSelectionOverlay.State.Value; + + public new ChannelSelectionOverlay ChannelSelectionOverlay => base.ChannelSelectionOverlay; + + protected override ChannelTabControl CreateChannelTabControl() => new TestTabControl(); + + public IReadOnlyDictionary> TabMap => ((TestTabControl)ChannelTabControl).TabMap; + } + + private class TestTabControl : ChannelTabControl + { + protected override TabItem CreateTabItem(Channel value) => new TestChannelTabItem(value); + + public new IReadOnlyDictionary> TabMap => base.TabMap; + } + + private class TestChannelTabItem : PrivateChannelTabItem + { + public TestChannelTabItem(Channel channel) + : base(channel) + { + } + + public new ClickableContainer CloseButton => base.CloseButton; } } } diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs deleted file mode 100644 index 2886bcfe56..0000000000 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneChatOverlayScenarios.cs +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System; -using System.Collections.Generic; -using NUnit.Framework; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.UserInterface; -using osu.Game.Online.Chat; -using osu.Game.Overlays; -using osu.Game.Overlays.Chat.Selection; -using osu.Game.Overlays.Chat.Tabs; -using osu.Game.Users; -using osuTK.Input; - -namespace osu.Game.Tests.Visual.UserInterface -{ - public class TestSceneChatOverlayScenarios : ManualInputManagerTestScene - { - public override IReadOnlyList RequiredTypes => new[] - { - typeof(ChannelTabControl), - typeof(ChannelTabItem), - typeof(ChatOverlay), - }; - - private TestChatOverlay chatOverlay; - private ChannelManager channelManager; - - private readonly Channel channel1 = new Channel(new User()) { Name = "test1" }; - private readonly Channel channel2 = new Channel(new User()) { Name = "test2" }; - - [SetUp] - public void Setup() - { - Schedule(() => - { - ChannelManagerContainer container; - Child = container = new ChannelManagerContainer(new List { channel1, channel2 }) { RelativeSizeAxes = Axes.Both, }; - chatOverlay = container.ChatOverlay; - channelManager = container.ChannelManager; - }); - } - - [Test] - public void TestHideOverlay() - { - AddStep("Close chat overlay", () => chatOverlay.Hide()); - AddAssert("Channel selection overlay was hidden", () => chatOverlay.SelectionOverlayState == Visibility.Hidden); - AddAssert("Chat overlay was hidden", () => chatOverlay.State.Value == Visibility.Hidden); - } - - [Test] - public void TestTabbingAwayClosesSelector() - { - AddAssert("Selector is visible", () => chatOverlay.SelectionOverlayState == Visibility.Visible); - AddStep("Join channel 1", () => channelManager.JoinChannel(channel1)); - AddStep("Switch to channel 1", () => clickDrawable(chatOverlay.TabMap[channel1])); - AddAssert("Current channel is channel 1", () => channelManager.CurrentChannel.Value == channel1); - AddAssert("Channel selector was closed", () => chatOverlay.SelectionOverlayState == Visibility.Hidden); - } - - [Test] - public void TestCloseChannelWhileSelectorClosed() - { - AddStep("Join channel 1", () => channelManager.JoinChannel(channel1)); - AddStep("Join channel 2", () => channelManager.JoinChannel(channel2)); - AddStep("Switch to channel 2", () => clickDrawable(chatOverlay.TabMap[channel2])); - AddStep("Close channel 2", () => clickDrawable(((TestChannelTabItem)chatOverlay.TabMap[channel2]).CloseButton.Child)); - AddAssert("Selector remained closed", () => chatOverlay.SelectionOverlayState == Visibility.Hidden); - AddAssert("Current channel is channel 1", () => channelManager.CurrentChannel.Value == channel1); - AddStep("Close channel 1", () => clickDrawable(((TestChannelTabItem)chatOverlay.TabMap[channel1]).CloseButton.Child)); - AddAssert("Selector is visible", () => chatOverlay.SelectionOverlayState == Visibility.Visible); - } - - private void clickDrawable(Drawable d) - { - InputManager.MoveMouseTo(d); - InputManager.Click(MouseButton.Left); - } - - private class ChannelManagerContainer : Container - { - public TestChatOverlay ChatOverlay { get; private set; } - - [Cached] - public ChannelManager ChannelManager { get; } = new ChannelManager(); - - private readonly List channels; - - public ChannelManagerContainer(List channels) - { - this.channels = channels; - } - - [BackgroundDependencyLoader] - private void load() - { - ((BindableList)ChannelManager.AvailableChannels).AddRange(channels); - - Child = ChatOverlay = new TestChatOverlay { RelativeSizeAxes = Axes.Both, }; - ChatOverlay.Show(); - } - } - - private class TestChatOverlay : ChatOverlay - { - public Visibility SelectionOverlayState => ChannelSelectionOverlay.State.Value; - - public new ChannelSelectionOverlay ChannelSelectionOverlay => base.ChannelSelectionOverlay; - - protected override ChannelTabControl CreateChannelTabControl() => new TestTabControl(); - - public IReadOnlyDictionary> TabMap => ((TestTabControl)ChannelTabControl).TabMap; - } - - private class TestTabControl : ChannelTabControl - { - protected override TabItem CreateTabItem(Channel value) => new TestChannelTabItem(value); - - public new IReadOnlyDictionary> TabMap => base.TabMap; - } - - private class TestChannelTabItem : PrivateChannelTabItem - { - public TestChannelTabItem(Channel channel) - : base(channel) - { - } - - public new ClickableContainer CloseButton => base.CloseButton; - } - } -} From 6e739411144163839767ed11f1e09b835e1c047b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 1 Jul 2019 22:06:54 +0900 Subject: [PATCH 28/28] Update iOS resources --- osu.iOS.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.iOS.props b/osu.iOS.props index a8013914af..48d2e6846a 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -104,7 +104,7 @@ - +