Merge branch 'master' into master

This commit is contained in:
Salman Ahmed 2021-12-16 16:58:24 +03:00 committed by GitHub
commit 9a22a082ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 135 additions and 85 deletions

View File

@ -1,6 +1,6 @@
# Contributing Guidelines # Contributing Guidelines
Thank you for showing interest in the development of osu!lazer! We aim to provide a good collaborating environment for everyone involved, and as such have decided to list some of the most important things to keep in mind in the process. The guidelines below have been chosen based on past experience. Thank you for showing interest in the development of osu!. We aim to provide a good collaborating environment for everyone involved, and as such have decided to list some of the most important things to keep in mind in the process. The guidelines below have been chosen based on past experience.
These are not "official rules" *per se*, but following them will help everyone deal with things in the most efficient manner. These are not "official rules" *per se*, but following them will help everyone deal with things in the most efficient manner.
@ -32,7 +32,7 @@ Issues, bug reports and feature suggestions are welcomed, though please keep in
* **Provide more information when asked to do so.** * **Provide more information when asked to do so.**
Sometimes when a bug is more elusive or complicated, none of the information listed above will pinpoint a concrete cause of the problem. In this case we will most likely ask you for additional info, such as a Windows Event Log dump or a copy of your local lazer database (`client.db`). Providing that information is beneficial to both parties - we can track down the problem better, and hopefully fix it for you at some point once we know where it is! Sometimes when a bug is more elusive or complicated, none of the information listed above will pinpoint a concrete cause of the problem. In this case we will most likely ask you for additional info, such as a Windows Event Log dump or a copy of your local osu! database (`client.db`). Providing that information is beneficial to both parties - we can track down the problem better, and hopefully fix it for you at some point once we know where it is!
* **When submitting a feature proposal, please describe it in the most understandable way you can.** * **When submitting a feature proposal, please describe it in the most understandable way you can.**
@ -54,7 +54,7 @@ Issues, bug reports and feature suggestions are welcomed, though please keep in
We also welcome pull requests from unaffiliated contributors. The [issue tracker](https://github.com/ppy/osu/issues) should provide plenty of issues that you can work on; we also mark issues that we think would be good for newcomers with the [`good-first-issue`](https://github.com/ppy/osu/issues?q=is%3Aissue+is%3Aopen+label%3Agood-first-issue) label. We also welcome pull requests from unaffiliated contributors. The [issue tracker](https://github.com/ppy/osu/issues) should provide plenty of issues that you can work on; we also mark issues that we think would be good for newcomers with the [`good-first-issue`](https://github.com/ppy/osu/issues?q=is%3Aissue+is%3Aopen+label%3Agood-first-issue) label.
However, do keep in mind that the core team is committed to bringing osu!lazer up to par with stable first and foremost, so depending on what your contribution concerns, it might not be merged and released right away. Our approach to managing issues and their priorities is described [in the wiki](https://github.com/ppy/osu/wiki/Project-management). However, do keep in mind that the core team is committed to bringing osu!(lazer) up to par with osu!(stable) first and foremost, so depending on what your contribution concerns, it might not be merged and released right away. Our approach to managing issues and their priorities is described [in the wiki](https://github.com/ppy/osu/wiki/Project-management).
Here are some key things to note before jumping in: Here are some key things to note before jumping in:
@ -128,7 +128,7 @@ Here are some key things to note before jumping in:
* **Don't mistake criticism of code for criticism of your person.** * **Don't mistake criticism of code for criticism of your person.**
As mentioned before, we are highly committed to quality when it comes to the lazer project. This means that contributions from less experienced community members can take multiple rounds of review to get to a mergeable state. We try our utmost best to never conflate a person with the code they authored, and to keep the discussion focused on the code at all times. Please consider our comments and requests a learning experience, and don't treat it as a personal attack. As mentioned before, we are highly committed to quality when it comes to the osu! project. This means that contributions from less experienced community members can take multiple rounds of review to get to a mergeable state. We try our utmost best to never conflate a person with the code they authored, and to keep the discussion focused on the code at all times. Please consider our comments and requests a learning experience, and don't treat it as a personal attack.
* **Feel free to reach out for help.** * **Feel free to reach out for help.**

View File

@ -11,7 +11,7 @@
A free-to-win rhythm game. Rhythm is just a *click* away! A free-to-win rhythm game. Rhythm is just a *click* away!
The future of [osu!](https://osu.ppy.sh) and the beginning of an open era! Currently known by and released under the codename "*lazer*". As in sharper than cutting-edge. The future of [osu!](https://osu.ppy.sh) and the beginning of an open era! Currently known by and released under the release codename "*lazer*". As in sharper than cutting-edge.
## Status ## Status

View File

@ -3,8 +3,10 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using osu.Framework.Input;
using osu.Framework.Input.Bindings; using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
using osu.Framework.Input.StateChanges.Events;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets.Osu namespace osu.Game.Rulesets.Osu
@ -39,6 +41,19 @@ namespace osu.Game.Rulesets.Osu
return base.Handle(e); return base.Handle(e);
} }
protected override bool HandleMouseTouchStateChange(TouchStateChangeEvent e)
{
if (!AllowUserCursorMovement)
{
// Still allow for forwarding of the "touch" part, but replace the positional data with that of the mouse.
// Primarily relied upon by the "autopilot" osu! mod.
var touch = new Touch(e.Touch.Source, CurrentState.Mouse.Position);
e = new TouchStateChangeEvent(e.State, e.Input, touch, e.IsActive, null);
}
return base.HandleMouseTouchStateChange(e);
}
private class OsuKeyBindingContainer : RulesetKeyBindingContainer private class OsuKeyBindingContainer : RulesetKeyBindingContainer
{ {
public bool AllowUserPresses = true; public bool AllowUserPresses = true;

View File

@ -6,12 +6,12 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Testing; using osu.Framework.Testing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
using osu.Game.Beatmaps.Drawables.Cards; using osu.Game.Beatmaps.Drawables.Cards;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Online.API; using osu.Game.Online.API;
@ -19,11 +19,10 @@ using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays; using osu.Game.Overlays;
using osuTK; using osuTK;
using APIUser = osu.Game.Online.API.Requests.Responses.APIUser;
namespace osu.Game.Tests.Visual.Beatmaps namespace osu.Game.Tests.Visual.Beatmaps
{ {
public class TestSceneBeatmapCard : OsuTestScene public class TestSceneBeatmapCard : OsuManualInputManagerTestScene
{ {
/// <summary> /// <summary>
/// All cards on this scene use a common online ID to ensure that map download, preview tracks, etc. can be tested manually with online sources. /// All cards on this scene use a common online ID to ensure that map download, preview tracks, etc. can be tested manually with online sources.
@ -253,14 +252,32 @@ namespace osu.Game.Tests.Visual.Beatmaps
public void TestNormal() public void TestNormal()
{ {
createTestCase(beatmapSetInfo => new BeatmapCard(beatmapSetInfo)); createTestCase(beatmapSetInfo => new BeatmapCard(beatmapSetInfo));
}
AddToggleStep("toggle expanded state", expanded => [Test]
{ public void TestHoverState()
var card = this.ChildrenOfType<BeatmapCard>().Last(); {
if (!card.Expanded.Disabled) AddStep("create cards", () => Child = createContent(OverlayColourScheme.Blue, s => new BeatmapCard(s)));
card.Expanded.Value = expanded;
}); AddStep("Hover card", () => InputManager.MoveMouseTo(firstCard()));
AddToggleStep("disable/enable expansion", disabled => this.ChildrenOfType<BeatmapCard>().ForEach(card => card.Expanded.Disabled = disabled)); AddWaitStep("wait for potential state change", 5);
AddAssert("card is not expanded", () => !firstCard().Expanded.Value);
AddStep("Hover spectrum display", () => InputManager.MoveMouseTo(firstCard().ChildrenOfType<DifficultySpectrumDisplay>().Single()));
AddUntilStep("card is expanded", () => firstCard().Expanded.Value);
AddStep("Hover difficulty content", () => InputManager.MoveMouseTo(firstCard().ChildrenOfType<BeatmapCardDifficultyList>().Single()));
AddWaitStep("wait for potential state change", 5);
AddAssert("card is still expanded", () => firstCard().Expanded.Value);
AddStep("Hover main content again", () => InputManager.MoveMouseTo(firstCard()));
AddWaitStep("wait for potential state change", 5);
AddAssert("card is still expanded", () => firstCard().Expanded.Value);
AddStep("Hover away", () => InputManager.MoveMouseTo(this.ChildrenOfType<BeatmapCard>().Last()));
AddUntilStep("card is not expanded", () => !firstCard().Expanded.Value);
BeatmapCard firstCard() => this.ChildrenOfType<BeatmapCard>().First();
} }
} }
} }

View File

@ -393,6 +393,25 @@ namespace osu.Game.Tests.Visual.Online
channelManager.CurrentChannel.Value.Type == ChannelType.PM && channelManager.CurrentChannel.Value.Users.Single().Username == "some body"); channelManager.CurrentChannel.Value.Type == ChannelType.PM && channelManager.CurrentChannel.Value.Users.Single().Username == "some body");
} }
[Test]
public void TestMultiplayerChannelIsNotShown()
{
Channel multiplayerChannel = null;
AddStep("join multiplayer channel", () => channelManager.JoinChannel(multiplayerChannel = new Channel(new APIUser())
{
Name = "#mp_1",
Type = ChannelType.Multiplayer,
}));
AddAssert("channel joined", () => channelManager.JoinedChannels.Contains(multiplayerChannel));
AddAssert("channel not present in overlay", () => !chatOverlay.TabMap.ContainsKey(multiplayerChannel));
AddAssert("multiplayer channel is not current", () => channelManager.CurrentChannel.Value != multiplayerChannel);
AddStep("leave channel", () => channelManager.LeaveChannel(multiplayerChannel));
AddAssert("channel left", () => !channelManager.JoinedChannels.Contains(multiplayerChannel));
}
private void pressChannelHotkey(int number) private void pressChannelHotkey(int number)
{ {
var channelKey = Key.Number0 + number; var channelKey = Key.Number0 + number;

View File

@ -33,7 +33,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards
public const float TRANSITION_DURATION = 400; public const float TRANSITION_DURATION = 400;
public const float CORNER_RADIUS = 10; public const float CORNER_RADIUS = 10;
public Bindable<bool> Expanded { get; } = new BindableBool(); public IBindable<bool> Expanded { get; }
private const float width = 408; private const float width = 408;
private const float height = 100; private const float height = 100;
@ -64,9 +64,11 @@ namespace osu.Game.Beatmaps.Drawables.Cards
[Resolved] [Resolved]
private OverlayColourProvider colourProvider { get; set; } = null!; private OverlayColourProvider colourProvider { get; set; } = null!;
public BeatmapCard(APIBeatmapSet beatmapSet) public BeatmapCard(APIBeatmapSet beatmapSet, bool allowExpansion = true)
: base(HoverSampleSet.Submit) : base(HoverSampleSet.Submit)
{ {
Expanded = new BindableBool { Disabled = !allowExpansion };
this.beatmapSet = beatmapSet; this.beatmapSet = beatmapSet;
favouriteState = new Bindable<BeatmapSetFavouriteState>(new BeatmapSetFavouriteState(beatmapSet.HasFavourited, beatmapSet.FavouriteCount)); favouriteState = new Bindable<BeatmapSetFavouriteState>(new BeatmapSetFavouriteState(beatmapSet.HasFavourited, beatmapSet.FavouriteCount));
downloadTracker = new BeatmapDownloadTracker(beatmapSet); downloadTracker = new BeatmapDownloadTracker(beatmapSet);
@ -282,15 +284,15 @@ namespace osu.Game.Beatmaps.Drawables.Cards
{ {
Hovered = _ => Hovered = _ =>
{ {
content.ScheduleShow(); content.ExpandAfterDelay();
return false; return false;
}, },
Unhovered = _ => Unhovered = _ =>
{ {
// This hide should only trigger if the expanded content has not shown yet. // Handles the case where a user has not shown explicit intent to view expanded info.
// ie. if the user has not shown intent to want to see it (quickly moved over the info row area). // ie. quickly moved over the info row area but didn't remain within it.
if (!Expanded.Value) if (!Expanded.Value)
content.ScheduleHide(); content.CancelExpand();
} }
} }
} }
@ -366,8 +368,6 @@ namespace osu.Game.Beatmaps.Drawables.Cards
protected override void OnHoverLost(HoverLostEvent e) protected override void OnHoverLost(HoverLostEvent e)
{ {
content.ScheduleHide();
updateState(); updateState();
base.OnHoverLost(e); base.OnHoverLost(e);
} }

View File

@ -31,7 +31,9 @@ namespace osu.Game.Beatmaps.Drawables.Cards
set => dropdownScroll.Child = value; set => dropdownScroll.Child = value;
} }
public Bindable<bool> Expanded { get; } = new BindableBool(); public IBindable<bool> Expanded => expanded;
private readonly BindableBool expanded = new BindableBool();
private readonly Box background; private readonly Box background;
private readonly Container content; private readonly Container content;
@ -54,7 +56,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards
AutoSizeAxes = Axes.Y, AutoSizeAxes = Axes.Y,
CornerRadius = BeatmapCard.CORNER_RADIUS, CornerRadius = BeatmapCard.CORNER_RADIUS,
Masking = true, Masking = true,
Unhovered = _ => checkForHide(), Unhovered = _ => updateFromHoverChange(),
Children = new Drawable[] Children = new Drawable[]
{ {
background = new Box background = new Box
@ -76,10 +78,10 @@ namespace osu.Game.Beatmaps.Drawables.Cards
Alpha = 0, Alpha = 0,
Hovered = _ => Hovered = _ =>
{ {
keep(); updateFromHoverChange();
return true; return true;
}, },
Unhovered = _ => checkForHide(), Unhovered = _ => updateFromHoverChange(),
Child = dropdownScroll = new ExpandedContentScrollContainer Child = dropdownScroll = new ExpandedContentScrollContainer
{ {
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
@ -119,51 +121,20 @@ namespace osu.Game.Beatmaps.Drawables.Cards
private ScheduledDelegate? scheduledExpandedChange; private ScheduledDelegate? scheduledExpandedChange;
public void ScheduleShow() public void ExpandAfterDelay() => queueExpandedStateChange(true, 100);
{
scheduledExpandedChange?.Cancel();
if (Expanded.Disabled || Expanded.Value)
return;
scheduledExpandedChange = Scheduler.AddDelayed(() => public void CancelExpand() => scheduledExpandedChange?.Cancel();
{
if (!Expanded.Disabled)
Expanded.Value = true;
}, 100);
}
public void ScheduleHide() private void updateFromHoverChange() =>
{ queueExpandedStateChange(content.IsHovered || dropdownContent.IsHovered, 100);
scheduledExpandedChange?.Cancel();
if (Expanded.Disabled || !Expanded.Value)
return;
scheduledExpandedChange = Scheduler.AddDelayed(() => private void queueExpandedStateChange(bool newState, int delay = 0)
{
if (!Expanded.Disabled)
Expanded.Value = false;
}, 500);
}
private void checkForHide()
{
if (Expanded.Disabled)
return;
if (content.IsHovered || dropdownContent.IsHovered)
return;
scheduledExpandedChange?.Cancel();
Expanded.Value = false;
}
private void keep()
{ {
if (Expanded.Disabled) if (Expanded.Disabled)
return; return;
scheduledExpandedChange?.Cancel(); scheduledExpandedChange?.Cancel();
Expanded.Value = true; scheduledExpandedChange = Scheduler.AddDelayed(() => expanded.Value = newState, delay);
} }
private void updateState() private void updateState()

View File

@ -72,18 +72,21 @@ namespace osu.Game.Graphics.Cursor
protected override bool OnMouseDown(MouseDownEvent e) protected override bool OnMouseDown(MouseDownEvent e)
{ {
// only trigger animation for main mouse buttons if (State.Value == Visibility.Visible)
activeCursor.Scale = new Vector2(1);
activeCursor.ScaleTo(0.90f, 800, Easing.OutQuint);
activeCursor.AdditiveLayer.Alpha = 0;
activeCursor.AdditiveLayer.FadeInFromZero(800, Easing.OutQuint);
if (cursorRotate.Value && dragRotationState != DragRotationState.Rotating)
{ {
// if cursor is already rotating don't reset its rotate origin // only trigger animation for main mouse buttons
dragRotationState = DragRotationState.DragStarted; activeCursor.Scale = new Vector2(1);
positionMouseDown = e.MousePosition; activeCursor.ScaleTo(0.90f, 800, Easing.OutQuint);
activeCursor.AdditiveLayer.Alpha = 0;
activeCursor.AdditiveLayer.FadeInFromZero(800, Easing.OutQuint);
if (cursorRotate.Value && dragRotationState != DragRotationState.Rotating)
{
// if cursor is already rotating don't reset its rotate origin
dragRotationState = DragRotationState.DragStarted;
positionMouseDown = e.MousePosition;
}
} }
return base.OnMouseDown(e); return base.OnMouseDown(e);

View File

@ -237,10 +237,7 @@ namespace osu.Game.Overlays
Schedule(() => Schedule(() =>
{ {
// TODO: consider scheduling bindable callbacks to not perform when overlay is not present. // TODO: consider scheduling bindable callbacks to not perform when overlay is not present.
channelManager.JoinedChannels.CollectionChanged += joinedChannelsChanged; channelManager.JoinedChannels.BindCollectionChanged(joinedChannelsChanged, true);
foreach (Channel channel in channelManager.JoinedChannels)
ChannelTabControl.AddChannel(channel);
channelManager.AvailableChannels.CollectionChanged += availableChannelsChanged; channelManager.AvailableChannels.CollectionChanged += availableChannelsChanged;
availableChannelsChanged(null, null); availableChannelsChanged(null, null);
@ -436,12 +433,19 @@ namespace osu.Game.Overlays
{ {
case NotifyCollectionChangedAction.Add: case NotifyCollectionChangedAction.Add:
foreach (Channel channel in args.NewItems.Cast<Channel>()) foreach (Channel channel in args.NewItems.Cast<Channel>())
ChannelTabControl.AddChannel(channel); {
if (channel.Type != ChannelType.Multiplayer)
ChannelTabControl.AddChannel(channel);
}
break; break;
case NotifyCollectionChangedAction.Remove: case NotifyCollectionChangedAction.Remove:
foreach (Channel channel in args.OldItems.Cast<Channel>()) foreach (Channel channel in args.OldItems.Cast<Channel>())
{ {
if (!ChannelTabControl.Items.Contains(channel))
continue;
ChannelTabControl.RemoveChannel(channel); ChannelTabControl.RemoveChannel(channel);
var loaded = loadedChannels.Find(c => c.Channel == channel); var loaded = loadedChannels.Find(c => c.Channel == channel);

View File

@ -5,12 +5,14 @@ using System;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Audio; using osu.Framework.Audio;
using osu.Framework.Audio.Sample; using osu.Framework.Audio.Sample;
using osu.Framework.Bindables;
using osu.Framework.Configuration.Tracking; using osu.Framework.Configuration.Tracking;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Configuration;
using osu.Game.Graphics; using osu.Game.Graphics;
using osuTK; using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
@ -28,6 +30,8 @@ namespace osu.Game.Overlays.OSD
private Sample sampleOff; private Sample sampleOff;
private Sample sampleChange; private Sample sampleChange;
private Bindable<double?> lastPlaybackTime;
public TrackedSettingToast(SettingDescription description) public TrackedSettingToast(SettingDescription description)
: base(description.Name, description.Value, description.Shortcut) : base(description.Name, description.Value, description.Shortcut)
{ {
@ -75,10 +79,28 @@ namespace osu.Game.Overlays.OSD
optionLights.Add(new OptionLight { Glowing = i == selectedOption }); optionLights.Add(new OptionLight { Glowing = i == selectedOption });
} }
[Resolved]
private SessionStatics statics { get; set; }
protected override void LoadComplete() protected override void LoadComplete()
{ {
base.LoadComplete(); base.LoadComplete();
playSound();
}
private void playSound()
{
// This debounce code roughly follows what we're using in HoverSampleDebounceComponent.
// We're sharing the existing static for hover sounds because it doesn't really matter if they block each other.
// This is a simple solution, but if this ever becomes a problem (or other performance issues arise),
// the whole toast system should be rewritten to avoid recreating this drawable each time a value changes.
lastPlaybackTime = statics.GetBindable<double?>(Static.LastHoverSoundPlaybackTime);
bool enoughTimePassedSinceLastPlayback = !lastPlaybackTime.Value.HasValue || Time.Current - lastPlaybackTime.Value >= OsuGameBase.SAMPLE_DEBOUNCE_TIME;
if (!enoughTimePassedSinceLastPlayback) return;
if (optionCount == 1) if (optionCount == 1)
{ {
if (selectedOption == 0) if (selectedOption == 0)
@ -93,6 +115,8 @@ namespace osu.Game.Overlays.OSD
sampleChange.Frequency.Value = 1 + (double)selectedOption / (optionCount - 1) * 0.25f; sampleChange.Frequency.Value = 1 + (double)selectedOption / (optionCount - 1) * 0.25f;
sampleChange.Play(); sampleChange.Play();
} }
lastPlaybackTime.Value = Time.Current;
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]

View File

@ -101,7 +101,7 @@ namespace osu.Game.Overlays
DisplayTemporarily(box); DisplayTemporarily(box);
}); });
private void displayTrackedSettingChange(SettingDescription description) => Display(new TrackedSettingToast(description)); private void displayTrackedSettingChange(SettingDescription description) => Scheduler.AddOnce(Display, new TrackedSettingToast(description));
private TransformSequence<Drawable> fadeIn; private TransformSequence<Drawable> fadeIn;
private ScheduledDelegate fadeOut; private ScheduledDelegate fadeOut;

View File

@ -228,10 +228,7 @@ namespace osu.Game.Screens.Play
onlineBeatmapRequest.Success += beatmapSet => Schedule(() => onlineBeatmapRequest.Success += beatmapSet => Schedule(() =>
{ {
this.beatmapSet = beatmapSet; this.beatmapSet = beatmapSet;
beatmapPanelContainer.Child = new BeatmapCard(this.beatmapSet) beatmapPanelContainer.Child = new BeatmapCard(this.beatmapSet, allowExpansion: false);
{
Expanded = { Disabled = true }
};
checkForAutomaticDownload(); checkForAutomaticDownload();
}); });