1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-14 11:35:35 +08:00

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
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.
@ -32,7 +32,7 @@ Issues, bug reports and feature suggestions are welcomed, though please keep in
* **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.**
@ -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.
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:
@ -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.**
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.**

View File

@ -11,7 +11,7 @@
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

View File

@ -3,8 +3,10 @@
using System.Collections.Generic;
using System.ComponentModel;
using osu.Framework.Input;
using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
using osu.Framework.Input.StateChanges.Events;
using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets.Osu
@ -39,6 +41,19 @@ namespace osu.Game.Rulesets.Osu
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
{
public bool AllowUserPresses = true;

View File

@ -6,12 +6,12 @@ using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
using osu.Game.Beatmaps.Drawables.Cards;
using osu.Game.Graphics.Containers;
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.Overlays;
using osuTK;
using APIUser = osu.Game.Online.API.Requests.Responses.APIUser;
namespace osu.Game.Tests.Visual.Beatmaps
{
public class TestSceneBeatmapCard : OsuTestScene
public class TestSceneBeatmapCard : OsuManualInputManagerTestScene
{
/// <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.
@ -253,14 +252,32 @@ namespace osu.Game.Tests.Visual.Beatmaps
public void TestNormal()
{
createTestCase(beatmapSetInfo => new BeatmapCard(beatmapSetInfo));
}
AddToggleStep("toggle expanded state", expanded =>
{
var card = this.ChildrenOfType<BeatmapCard>().Last();
if (!card.Expanded.Disabled)
card.Expanded.Value = expanded;
});
AddToggleStep("disable/enable expansion", disabled => this.ChildrenOfType<BeatmapCard>().ForEach(card => card.Expanded.Disabled = disabled));
[Test]
public void TestHoverState()
{
AddStep("create cards", () => Child = createContent(OverlayColourScheme.Blue, s => new BeatmapCard(s)));
AddStep("Hover card", () => InputManager.MoveMouseTo(firstCard()));
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");
}
[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)
{
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 CORNER_RADIUS = 10;
public Bindable<bool> Expanded { get; } = new BindableBool();
public IBindable<bool> Expanded { get; }
private const float width = 408;
private const float height = 100;
@ -64,9 +64,11 @@ namespace osu.Game.Beatmaps.Drawables.Cards
[Resolved]
private OverlayColourProvider colourProvider { get; set; } = null!;
public BeatmapCard(APIBeatmapSet beatmapSet)
public BeatmapCard(APIBeatmapSet beatmapSet, bool allowExpansion = true)
: base(HoverSampleSet.Submit)
{
Expanded = new BindableBool { Disabled = !allowExpansion };
this.beatmapSet = beatmapSet;
favouriteState = new Bindable<BeatmapSetFavouriteState>(new BeatmapSetFavouriteState(beatmapSet.HasFavourited, beatmapSet.FavouriteCount));
downloadTracker = new BeatmapDownloadTracker(beatmapSet);
@ -282,15 +284,15 @@ namespace osu.Game.Beatmaps.Drawables.Cards
{
Hovered = _ =>
{
content.ScheduleShow();
content.ExpandAfterDelay();
return false;
},
Unhovered = _ =>
{
// This hide should only trigger if the expanded content has not shown yet.
// ie. if the user has not shown intent to want to see it (quickly moved over the info row area).
// Handles the case where a user has not shown explicit intent to view expanded info.
// ie. quickly moved over the info row area but didn't remain within it.
if (!Expanded.Value)
content.ScheduleHide();
content.CancelExpand();
}
}
}
@ -366,8 +368,6 @@ namespace osu.Game.Beatmaps.Drawables.Cards
protected override void OnHoverLost(HoverLostEvent e)
{
content.ScheduleHide();
updateState();
base.OnHoverLost(e);
}

View File

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

View File

@ -72,18 +72,21 @@ namespace osu.Game.Graphics.Cursor
protected override bool OnMouseDown(MouseDownEvent e)
{
// only trigger animation for main mouse buttons
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 (State.Value == Visibility.Visible)
{
// if cursor is already rotating don't reset its rotate origin
dragRotationState = DragRotationState.DragStarted;
positionMouseDown = e.MousePosition;
// only trigger animation for main mouse buttons
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
dragRotationState = DragRotationState.DragStarted;
positionMouseDown = e.MousePosition;
}
}
return base.OnMouseDown(e);

View File

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

View File

@ -5,12 +5,14 @@ using System;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Bindables;
using osu.Framework.Configuration.Tracking;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osuTK;
using osuTK.Graphics;
@ -28,6 +30,8 @@ namespace osu.Game.Overlays.OSD
private Sample sampleOff;
private Sample sampleChange;
private Bindable<double?> lastPlaybackTime;
public TrackedSettingToast(SettingDescription description)
: base(description.Name, description.Value, description.Shortcut)
{
@ -75,10 +79,28 @@ namespace osu.Game.Overlays.OSD
optionLights.Add(new OptionLight { Glowing = i == selectedOption });
}
[Resolved]
private SessionStatics statics { get; set; }
protected override void 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 (selectedOption == 0)
@ -93,6 +115,8 @@ namespace osu.Game.Overlays.OSD
sampleChange.Frequency.Value = 1 + (double)selectedOption / (optionCount - 1) * 0.25f;
sampleChange.Play();
}
lastPlaybackTime.Value = Time.Current;
}
[BackgroundDependencyLoader]

View File

@ -101,7 +101,7 @@ namespace osu.Game.Overlays
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 ScheduledDelegate fadeOut;

View File

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