Merge branch 'master' into fix-transform-mutation-mod-selection

This commit is contained in:
Dean Herbert
2021-01-08 11:16:15 +09:00
60 changed files with 779 additions and 684 deletions

View File

@ -0,0 +1,17 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.ComponentModel;
namespace osu.Game.Configuration
{
public enum DiscordRichPresenceMode
{
Off,
[Description("Hide identifiable information")]
Limited,
Full
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
@ -138,6 +138,8 @@ namespace osu.Game.Configuration
Set(OsuSetting.MenuBackgroundSource, BackgroundSource.Skin);
Set(OsuSetting.SeasonalBackgroundMode, SeasonalBackgroundMode.Sometimes);
Set(OsuSetting.DiscordRichPresence, DiscordRichPresenceMode.Full);
Set(OsuSetting.EditorWaveformOpacity, 1f);
}
@ -266,6 +268,7 @@ namespace osu.Game.Configuration
GameplayDisableWinKey,
SeasonalBackgroundMode,
EditorWaveformOpacity,
DiscordRichPresence,
AutomaticallyDownloadWhenSpectating,
}
}

View File

@ -2,8 +2,9 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using JetBrains.Annotations;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Events;
using osuTK;
using osuTK.Graphics;
@ -17,22 +18,32 @@ namespace osu.Game.Graphics.UserInterface
/// </summary>
public class LoadingLayer : LoadingSpinner
{
private readonly Drawable dimTarget;
[CanBeNull]
protected Box BackgroundDimLayer { get; }
/// <summary>
/// Constuct a new loading spinner.
/// Construct a new loading spinner.
/// </summary>
/// <param name="dimTarget">An optional target to dim when displayed.</param>
/// <param name="dimBackground">Whether the full background area should be dimmed while loading.</param>
/// <param name="withBox">Whether the spinner should have a surrounding black box for visibility.</param>
public LoadingLayer(Drawable dimTarget = null, bool withBox = true)
public LoadingLayer(bool dimBackground = false, bool withBox = true)
: base(withBox)
{
RelativeSizeAxes = Axes.Both;
Size = new Vector2(1);
this.dimTarget = dimTarget;
MainContents.RelativeSizeAxes = Axes.None;
if (dimBackground)
{
AddInternal(BackgroundDimLayer = new Box
{
Depth = float.MaxValue,
Colour = Color4.Black,
Alpha = 0,
RelativeSizeAxes = Axes.Both,
});
}
}
public override bool HandleNonPositionalInput => false;
@ -56,31 +67,21 @@ namespace osu.Game.Graphics.UserInterface
protected override void PopIn()
{
dimTarget?.FadeColour(OsuColour.Gray(0.5f), TRANSITION_DURATION, Easing.OutQuint);
BackgroundDimLayer?.FadeTo(0.5f, TRANSITION_DURATION * 2, Easing.OutQuint);
base.PopIn();
}
protected override void PopOut()
{
dimTarget?.FadeColour(Color4.White, TRANSITION_DURATION, Easing.OutQuint);
BackgroundDimLayer?.FadeOut(TRANSITION_DURATION, Easing.OutQuint);
base.PopOut();
}
protected override void Update()
{
base.Update();
MainContents.Size = new Vector2(Math.Clamp(Math.Min(DrawWidth, DrawHeight) * 0.25f, 30, 100));
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
if (State.Value == Visibility.Visible)
{
// ensure we don't leave the target in a bad state.
dimTarget?.FadeColour(Color4.White, TRANSITION_DURATION, Easing.OutQuint);
}
}
}
}

View File

@ -34,7 +34,7 @@ namespace osu.Game.Input.Bindings
new KeyBinding(new[] { InputKey.Control, InputKey.Alt, InputKey.R }, GlobalAction.ResetInputSettings),
new KeyBinding(new[] { InputKey.Control, InputKey.T }, GlobalAction.ToggleToolbar),
new KeyBinding(new[] { InputKey.Control, InputKey.O }, GlobalAction.ToggleSettings),
new KeyBinding(new[] { InputKey.Control, InputKey.D }, GlobalAction.ToggleDirect),
new KeyBinding(new[] { InputKey.Control, InputKey.D }, GlobalAction.ToggleBeatmapListing),
new KeyBinding(new[] { InputKey.Control, InputKey.N }, GlobalAction.ToggleNotifications),
new KeyBinding(InputKey.Escape, GlobalAction.Back),
@ -112,8 +112,8 @@ namespace osu.Game.Input.Bindings
[Description("Toggle settings")]
ToggleSettings,
[Description("Toggle osu!direct")]
ToggleDirect,
[Description("Toggle beatmap listing")]
ToggleBeatmapListing,
[Description("Increase volume")]
IncreaseVolume,

View File

@ -151,11 +151,11 @@ namespace osu.Game
updateBlockingOverlayFade();
}
public void RemoveBlockingOverlay(OverlayContainer overlay)
public void RemoveBlockingOverlay(OverlayContainer overlay) => Schedule(() =>
{
visibleBlockingOverlays.Remove(overlay);
updateBlockingOverlayFade();
}
});
/// <summary>
/// Close all game-wide overlays.

View File

@ -48,11 +48,9 @@ namespace osu.Game.Overlays.AccountCreation
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
FillFlowContainer mainContent;
InternalChildren = new Drawable[]
{
mainContent = new FillFlowContainer
new FillFlowContainer
{
RelativeSizeAxes = Axes.Both,
Direction = FillDirection.Vertical,
@ -124,7 +122,7 @@ namespace osu.Game.Overlays.AccountCreation
},
},
},
loadingLayer = new LoadingLayer(mainContent)
loadingLayer = new LoadingLayer(true)
};
textboxes = new[] { usernameTextBox, emailTextBox, passwordTextBox };

View File

@ -92,14 +92,14 @@ namespace osu.Game.Overlays
{
foundContent = new FillFlowContainer<BeatmapPanel>(),
notFoundContent = new NotFoundDrawable(),
loadingLayer = new LoadingLayer(panelTarget)
}
}
}
},
},
}
}
}
},
},
loadingLayer = new LoadingLayer(true)
};
}

View File

@ -53,7 +53,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
Size = new Vector2(18),
Shadow = false,
},
loading = new LoadingLayer(icon, false),
loading = new LoadingLayer(true, false),
});
Action = () =>

View File

@ -157,11 +157,11 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
}
}
},
loading = new LoadingLayer()
}
}
}
}
},
},
loading = new LoadingLayer()
});
}
@ -228,7 +228,9 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
{
Scores = null;
notSupporterPlaceholder.Show();
loading.Hide();
loading.FinishTransforms();
return;
}
@ -241,6 +243,8 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
getScoresRequest.Success += scores =>
{
loading.Hide();
loading.FinishTransforms();
Scores = scores;
if (!scores.Scores.Any())

View File

@ -128,7 +128,7 @@ namespace osu.Game.Overlays.Dashboard.Friends
AutoSizeAxes = Axes.Y,
Padding = new MarginPadding { Horizontal = 50 }
},
loading = new LoadingLayer(itemsPlaceholder)
loading = new LoadingLayer(true)
}
}
}

View File

@ -68,7 +68,7 @@ namespace osu.Game.Overlays
}
}
},
loading = new LoadingLayer(content),
loading = new LoadingLayer(true),
};
}

View File

@ -59,7 +59,7 @@ namespace osu.Game.Overlays
},
},
},
loading = new LoadingLayer(content),
loading = new LoadingLayer(true),
};
}

View File

@ -45,6 +45,7 @@ namespace osu.Game.Overlays.Rankings
{
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
InternalChild = new ReverseChildIDFillFlowContainer<Drawable>
{
RelativeSizeAxes = Axes.X,
@ -68,7 +69,7 @@ namespace osu.Game.Overlays.Rankings
AutoSizeAxes = Axes.Y,
Margin = new MarginPadding { Vertical = 10 }
},
loading = new LoadingLayer(content)
loading = new LoadingLayer(true)
}
}
}

View File

@ -42,6 +42,8 @@ namespace osu.Game.Overlays
Depth = -float.MaxValue
})
{
loading = new LoadingLayer(true);
Children = new Drawable[]
{
background = new Box
@ -74,12 +76,12 @@ namespace osu.Game.Overlays
RelativeSizeAxes = Axes.X,
Margin = new MarginPadding { Bottom = 10 }
},
loading = new LoadingLayer(contentContainer),
}
}
}
}
}
},
loading
};
}

View File

@ -132,6 +132,15 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
}
},
};
}
protected override void LoadComplete()
{
base.LoadComplete();
scalingSettings.ForEach(s => bindPreviewEvent(s.Current));
windowModeDropdown.Current.ValueChanged += _ => updateResolutionDropdown();
windowModes.BindCollectionChanged((sender, args) =>
{
@ -141,8 +150,6 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
windowModeDropdown.Hide();
}, true);
windowModeDropdown.Current.ValueChanged += _ => updateResolutionDropdown();
currentDisplay.BindValueChanged(display => Schedule(() =>
{
resolutions.RemoveRange(1, resolutions.Count - 1);
@ -159,8 +166,6 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
updateResolutionDropdown();
}), true);
scalingSettings.ForEach(s => bindPreviewEvent(s.Current));
scalingMode.BindValueChanged(mode =>
{
scalingSettings.ClearTransforms();
@ -181,11 +186,6 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
}
}
/// <summary>
/// Create a delayed bindable which only updates when a condition is met.
/// </summary>
/// <param name="bindable">The config bindable.</param>
/// <returns>A bindable which will propagate updates with a delay.</returns>
private void bindPreviewEvent(Bindable<float> bindable)
{
bindable.ValueChanged += _ =>

View File

@ -0,0 +1,27 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Configuration;
namespace osu.Game.Overlays.Settings.Sections.Online
{
public class IntegrationSettings : SettingsSubsection
{
protected override string Header => "Integrations";
[BackgroundDependencyLoader]
private void load(OsuConfigManager config)
{
Children = new Drawable[]
{
new SettingsEnumDropdown<DiscordRichPresenceMode>
{
LabelText = "Discord Rich Presence",
Current = config.GetBindable<DiscordRichPresenceMode>(OsuSetting.DiscordRichPresence)
}
};
}
}
}

View File

@ -20,7 +20,8 @@ namespace osu.Game.Overlays.Settings.Sections
{
Children = new Drawable[]
{
new WebSettings()
new WebSettings(),
new IntegrationSettings()
};
}
}

View File

@ -2,15 +2,18 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Input.Bindings;
namespace osu.Game.Overlays.Toolbar
{
public class ToolbarBeatmapListingButton : ToolbarOverlayToggleButton
{
protected override Anchor TooltipAnchor => Anchor.TopRight;
public ToolbarBeatmapListingButton()
{
Hotkey = GlobalAction.ToggleDirect;
Hotkey = GlobalAction.ToggleBeatmapListing;
}
[BackgroundDependencyLoader(true)]

View File

@ -2,11 +2,14 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Graphics;
namespace osu.Game.Overlays.Toolbar
{
public class ToolbarChangelogButton : ToolbarOverlayToggleButton
{
protected override Anchor TooltipAnchor => Anchor.TopRight;
[BackgroundDependencyLoader(true)]
private void load(ChangelogOverlay changelog)
{

View File

@ -2,12 +2,15 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Input.Bindings;
namespace osu.Game.Overlays.Toolbar
{
public class ToolbarChatButton : ToolbarOverlayToggleButton
{
protected override Anchor TooltipAnchor => Anchor.TopRight;
public ToolbarChatButton()
{
Hotkey = GlobalAction.ToggleChat;

View File

@ -2,11 +2,14 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Graphics;
namespace osu.Game.Overlays.Toolbar
{
public class ToolbarNewsButton : ToolbarOverlayToggleButton
{
protected override Anchor TooltipAnchor => Anchor.TopRight;
[BackgroundDependencyLoader(true)]
private void load(NewsOverlay news)
{

View File

@ -2,11 +2,14 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Graphics;
namespace osu.Game.Overlays.Toolbar
{
public class ToolbarRankingsButton : ToolbarOverlayToggleButton
{
protected override Anchor TooltipAnchor => Anchor.TopRight;
[BackgroundDependencyLoader(true)]
private void load(RankingsOverlay rankings)
{

View File

@ -2,12 +2,15 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Input.Bindings;
namespace osu.Game.Overlays.Toolbar
{
public class ToolbarSocialButton : ToolbarOverlayToggleButton
{
protected override Anchor TooltipAnchor => Anchor.TopRight;
public ToolbarSocialButton()
{
Hotkey = GlobalAction.ToggleSocial;

View File

@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Mods
public void ApplyToPlayer(Player player)
{
player.Background.EnableUserDim.Value = false;
player.ApplyToBackground(b => b.EnableUserDim.Value = false);
player.DimmableStoryboard.IgnoreUserSettings.Value = true;

View File

@ -750,7 +750,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
if (Result.Type != originalType)
{
Logger.Log($"{GetType().ReadableName()} applied an invalid hit result ({originalType}) when {nameof(HitResult.IgnoreMiss)} or {nameof(HitResult.IgnoreHit)} is expected.\n"
+ $"This has been automatically adjusted to {Result.Type}, and support will be removed from 2020-03-28 onwards.", level: LogLevel.Important);
+ $"This has been automatically adjusted to {Result.Type}, and support will be removed from 2021-03-28 onwards.", level: LogLevel.Important);
}
}

View File

@ -10,10 +10,7 @@ using osu.Game.Beatmaps.ControlPoints;
namespace osu.Game.Rulesets.Objects.Legacy
{
internal abstract class ConvertSlider : ConvertHitObject, IHasPathWithRepeats, IHasLegacyLastTickOffset,
#pragma warning disable 618
IHasCurve
#pragma warning restore 618
internal abstract class ConvertSlider : ConvertHitObject, IHasPathWithRepeats, IHasLegacyLastTickOffset
{
/// <summary>
/// Scoring distance with a speed-adjusted beat length of 1 second.

View File

@ -1,55 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using osuTK;
namespace osu.Game.Rulesets.Objects.Types
{
[Obsolete("Use IHasPathWithRepeats instead.")] // can be removed 20201126
public interface IHasCurve : IHasDistance, IHasRepeats
{
/// <summary>
/// The curve.
/// </summary>
SliderPath Path { get; }
}
#pragma warning disable 618
[Obsolete("Use IHasPathWithRepeats instead.")] // can be removed 20201126
public static class HasCurveExtensions
{
/// <summary>
/// Computes the position on the curve relative to how much of the <see cref="HitObject"/> has been completed.
/// </summary>
/// <param name="obj">The curve.</param>
/// <param name="progress">[0, 1] where 0 is the start time of the <see cref="HitObject"/> and 1 is the end time of the <see cref="HitObject"/>.</param>
/// <returns>The position on the curve.</returns>
public static Vector2 CurvePositionAt(this IHasCurve obj, double progress)
=> obj.Path.PositionAt(obj.ProgressAt(progress));
/// <summary>
/// Computes the progress along the curve relative to how much of the <see cref="HitObject"/> has been completed.
/// </summary>
/// <param name="obj">The curve.</param>
/// <param name="progress">[0, 1] where 0 is the start time of the <see cref="HitObject"/> and 1 is the end time of the <see cref="HitObject"/>.</param>
/// <returns>[0, 1] where 0 is the beginning of the curve and 1 is the end of the curve.</returns>
public static double ProgressAt(this IHasCurve obj, double progress)
{
double p = progress * obj.SpanCount() % 1;
if (obj.SpanAt(progress) % 2 == 1)
p = 1 - p;
return p;
}
/// <summary>
/// Determines which span of the curve the progress point is on.
/// </summary>
/// <param name="obj">The curve.</param>
/// <param name="progress">[0, 1] where 0 is the beginning of the curve and 1 is the end of the curve.</param>
/// <returns>[0, SpanCount) where 0 is the first run.</returns>
public static int SpanAt(this IHasCurve obj, double progress)
=> (int)(progress * obj.SpanCount());
}
#pragma warning restore 618
}

View File

@ -6,26 +6,16 @@ namespace osu.Game.Rulesets.Objects.Types
/// <summary>
/// A HitObject that ends at a different time than its start time.
/// </summary>
#pragma warning disable 618
public interface IHasDuration : IHasEndTime
#pragma warning restore 618
public interface IHasDuration
{
double IHasEndTime.EndTime
{
get => EndTime;
set => Duration = (Duration - EndTime) + value;
}
double IHasEndTime.Duration => Duration;
/// <summary>
/// The time at which the HitObject ends.
/// </summary>
new double EndTime { get; }
double EndTime { get; }
/// <summary>
/// The duration of the HitObject.
/// </summary>
new double Duration { get; set; }
double Duration { get; set; }
}
}

View File

@ -1,26 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using Newtonsoft.Json;
namespace osu.Game.Rulesets.Objects.Types
{
/// <summary>
/// A HitObject that ends at a different time than its start time.
/// </summary>
[Obsolete("Use IHasDuration instead.")] // can be removed 20201126
public interface IHasEndTime
{
/// <summary>
/// The time at which the HitObject ends.
/// </summary>
[JsonIgnore]
double EndTime { get; set; }
/// <summary>
/// The duration of the HitObject.
/// </summary>
double Duration { get; }
}
}

View File

@ -100,9 +100,7 @@ namespace osu.Game.Rulesets
foreach (var r in instances.Where(r => !(r is ILegacyRuleset)))
{
// todo: StartsWith can be changed to Equals on 2020-11-08
// This is to give users enough time to have their database use new abbreviated info).
if (existingRulesets.FirstOrDefault(ri => ri.InstantiationInfo.StartsWith(r.RulesetInfo.InstantiationInfo, StringComparison.Ordinal)) == null)
if (existingRulesets.FirstOrDefault(ri => ri.InstantiationInfo.Equals(r.RulesetInfo.InstantiationInfo, StringComparison.Ordinal)) == null)
context.RulesetInfo.Add(r.RulesetInfo);
}

View File

@ -34,6 +34,12 @@ namespace osu.Game.Screens
return false;
}
/// <summary>
/// Apply arbitrary changes to this background in a thread safe manner.
/// </summary>
/// <param name="action">The operation to perform.</param>
public void ApplyToBackground(Action<BackgroundScreen> action) => Schedule(() => action.Invoke(this));
protected override void Update()
{
base.Update();

View File

@ -444,11 +444,14 @@ namespace osu.Game.Screens.Edit
{
base.OnEntering(last);
// todo: temporary. we want to be applying dim using the UserDimContainer eventually.
Background.FadeColour(Color4.DarkGray, 500);
ApplyToBackground(b =>
{
// todo: temporary. we want to be applying dim using the UserDimContainer eventually.
b.FadeColour(Color4.DarkGray, 500);
Background.EnableUserDim.Value = false;
Background.BlurAmount.Value = 0;
b.EnableUserDim.Value = false;
b.BlurAmount.Value = 0;
});
resetTrack(true);
}
@ -480,7 +483,7 @@ namespace osu.Game.Screens.Edit
}
}
Background.FadeColour(Color4.White, 500);
ApplyToBackground(b => b.FadeColour(Color4.White, 500));
resetTrack();
return base.OnExiting(next);

View File

@ -129,8 +129,8 @@ namespace osu.Game.Screens.Menu
buttonsPlay.ForEach(b => b.VisibleState = ButtonSystemState.Play);
buttonsTopLevel.Add(new Button(@"play", @"button-play-select", OsuIcon.Logo, new Color4(102, 68, 204, 255), () => State = ButtonSystemState.Play, WEDGE_WIDTH, Key.P));
buttonsTopLevel.Add(new Button(@"osu!editor", @"button-generic-select", OsuIcon.EditCircle, new Color4(238, 170, 0, 255), () => OnEdit?.Invoke(), 0, Key.E));
buttonsTopLevel.Add(new Button(@"osu!direct", @"button-direct-select", OsuIcon.ChevronDownCircle, new Color4(165, 204, 0, 255), () => OnBeatmapListing?.Invoke(), 0, Key.D));
buttonsTopLevel.Add(new Button(@"edit", @"button-generic-select", OsuIcon.EditCircle, new Color4(238, 170, 0, 255), () => OnEdit?.Invoke(), 0, Key.E));
buttonsTopLevel.Add(new Button(@"browse", @"button-direct-select", OsuIcon.ChevronDownCircle, new Color4(165, 204, 0, 255), () => OnBeatmapListing?.Invoke(), 0, Key.D));
if (host.CanExit)
buttonsTopLevel.Add(new Button(@"exit", string.Empty, OsuIcon.CrossCircle, new Color4(238, 51, 153, 255), () => OnExit?.Invoke(), 0, Key.Q));

View File

@ -201,7 +201,7 @@ namespace osu.Game.Screens.Menu
"New features are coming online every update. Make sure to stay up-to-date!",
"If you find the UI too large or small, try adjusting UI scale in settings!",
"Try adjusting the \"Screen Scaling\" mode to change your gameplay or UI area, even in fullscreen!",
"For now, osu!direct is available to all users on lazer. You can access it anywhere using Ctrl-D!",
"For now, what used to be \"osu!direct\" is available to all users on lazer. You can access it anywhere using Ctrl-D!",
"Seeking in replays is available by dragging on the difficulty bar at the bottom of the screen!",
"Multithreading support means that even with low \"FPS\" your input and judgements will be accurate!",
"Try scrolling down in the mod select panel to find a bunch of new fun mods!",

View File

@ -127,11 +127,11 @@ namespace osu.Game.Screens.Menu
{
case ButtonSystemState.Initial:
case ButtonSystemState.Exit:
Background.FadeColour(Color4.White, 500, Easing.OutSine);
ApplyToBackground(b => b.FadeColour(Color4.White, 500, Easing.OutSine));
break;
default:
Background.FadeColour(OsuColour.Gray(0.8f), 500, Easing.OutSine);
ApplyToBackground(b => b.FadeColour(OsuColour.Gray(0.8f), 500, Easing.OutSine));
break;
}
};
@ -256,7 +256,7 @@ namespace osu.Game.Screens.Menu
{
base.OnResuming(last);
(Background as BackgroundScreenDefault)?.Next();
ApplyToBackground(b => (b as BackgroundScreenDefault)?.Next());
// we may have consumed our preloaded instance, so let's make another.
preloadSongSelect();

View File

@ -2,8 +2,6 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Linq;
using System.Linq.Expressions;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Game.Beatmaps;
@ -41,38 +39,21 @@ namespace osu.Game.Screens.OnlinePlay.Components
SelectedItem.BindValueChanged(item => updateSelectedItem(item.NewValue), true);
}
private void updateSelectedItem(PlaylistItem item)
{
hasBeatmap = findBeatmap(expr => beatmaps.QueryBeatmap(expr));
}
private void updateSelectedItem(PlaylistItem _) => Scheduler.AddOnce(updateBeatmapState);
private void beatmapUpdated(ValueChangedEvent<WeakReference<BeatmapSetInfo>> _) => Scheduler.AddOnce(updateBeatmapState);
private void beatmapRemoved(ValueChangedEvent<WeakReference<BeatmapSetInfo>> _) => Scheduler.AddOnce(updateBeatmapState);
private void beatmapUpdated(ValueChangedEvent<WeakReference<BeatmapSetInfo>> weakSet)
{
if (weakSet.NewValue.TryGetTarget(out var set))
{
if (findBeatmap(expr => set.Beatmaps.AsQueryable().FirstOrDefault(expr)))
Schedule(() => hasBeatmap = true);
}
}
private void beatmapRemoved(ValueChangedEvent<WeakReference<BeatmapSetInfo>> weakSet)
{
if (weakSet.NewValue.TryGetTarget(out var set))
{
if (findBeatmap(expr => set.Beatmaps.AsQueryable().FirstOrDefault(expr)))
Schedule(() => hasBeatmap = false);
}
}
private bool findBeatmap(Func<Expression<Func<BeatmapInfo, bool>>, BeatmapInfo> expression)
private void updateBeatmapState()
{
int? beatmapId = SelectedItem.Value?.Beatmap.Value?.OnlineBeatmapID;
string checksum = SelectedItem.Value?.Beatmap.Value?.MD5Hash;
if (beatmapId == null || checksum == null)
return false;
return;
return expression(b => b.OnlineBeatmapID == beatmapId && b.MD5Hash == checksum) != null;
var databasedBeatmap = beatmaps.QueryBeatmap(b => b.OnlineBeatmapID == beatmapId && b.MD5Hash == checksum);
hasBeatmap = databasedBeatmap?.BeatmapSet?.DeletePending == false;
}
protected override void Update()

View File

@ -65,7 +65,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
Padding = new MarginPadding(10),
Child = roomsContainer = new RoomsContainer { JoinRequested = joinRequested }
},
loadingLayer = new LoadingLayer(roomsContainer),
loadingLayer = new LoadingLayer(true),
}
},
new RoomInspector

View File

@ -71,201 +71,192 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
Container dimContent;
InternalChildren = new Drawable[]
{
dimContent = new Container
new Box
{
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
Colour = Color4Extensions.FromHex(@"28242d"),
},
new GridContainer
{
RelativeSizeAxes = Axes.Both,
RowDimensions = new[]
{
new Box
new Dimension(GridSizeMode.Distributed),
new Dimension(GridSizeMode.AutoSize),
},
Content = new[]
{
new Drawable[]
{
RelativeSizeAxes = Axes.Both,
Colour = Color4Extensions.FromHex(@"28242d"),
},
new GridContainer
{
RelativeSizeAxes = Axes.Both,
RowDimensions = new[]
new OsuScrollContainer
{
new Dimension(GridSizeMode.Distributed),
new Dimension(GridSizeMode.AutoSize),
},
Content = new[]
{
new Drawable[]
Padding = new MarginPadding
{
new OsuScrollContainer
Horizontal = OsuScreen.HORIZONTAL_OVERFLOW_PADDING,
Vertical = 10
},
RelativeSizeAxes = Axes.Both,
Children = new[]
{
new FillFlowContainer
{
Padding = new MarginPadding
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 10),
Children = new Drawable[]
{
Horizontal = OsuScreen.HORIZONTAL_OVERFLOW_PADDING,
Vertical = 10
},
RelativeSizeAxes = Axes.Both,
Children = new[]
{
new FillFlowContainer
new Container
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Padding = new MarginPadding { Horizontal = WaveOverlayContainer.WIDTH_PADDING },
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 10),
Children = new Drawable[]
{
new Container
new SectionContainer
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Padding = new MarginPadding { Horizontal = WaveOverlayContainer.WIDTH_PADDING },
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Children = new Drawable[]
Padding = new MarginPadding { Right = FIELD_PADDING / 2 },
Children = new[]
{
new SectionContainer
new Section("Room name")
{
Padding = new MarginPadding { Right = FIELD_PADDING / 2 },
Children = new[]
Child = NameField = new SettingsTextBox
{
new Section("Room name")
RelativeSizeAxes = Axes.X,
TabbableContentContainer = this,
},
},
new Section("Room visibility")
{
Alpha = disabled_alpha,
Child = AvailabilityPicker = new RoomAvailabilityPicker
{
Enabled = { Value = false }
},
},
new Section("Game type")
{
Alpha = disabled_alpha,
Child = new FillFlowContainer
{
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
Direction = FillDirection.Vertical,
Spacing = new Vector2(7),
Children = new Drawable[]
{
Child = NameField = new SettingsTextBox
TypePicker = new GameTypePicker
{
RelativeSizeAxes = Axes.X,
TabbableContentContainer = this,
},
},
new Section("Room visibility")
{
Alpha = disabled_alpha,
Child = AvailabilityPicker = new RoomAvailabilityPicker
{
Enabled = { Value = false }
},
},
new Section("Game type")
{
Alpha = disabled_alpha,
Child = new FillFlowContainer
typeLabel = new OsuSpriteText
{
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
Direction = FillDirection.Vertical,
Spacing = new Vector2(7),
Children = new Drawable[]
{
TypePicker = new GameTypePicker
{
RelativeSizeAxes = Axes.X,
Enabled = { Value = false }
},
typeLabel = new OsuSpriteText
{
Font = OsuFont.GetFont(size: 14),
Colour = colours.Yellow
},
},
Font = OsuFont.GetFont(size: 14),
Colour = colours.Yellow
},
},
},
},
new SectionContainer
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
Padding = new MarginPadding { Left = FIELD_PADDING / 2 },
Children = new[]
{
new Section("Max participants")
{
Alpha = disabled_alpha,
Child = MaxParticipantsField = new SettingsNumberTextBox
{
RelativeSizeAxes = Axes.X,
TabbableContentContainer = this,
ReadOnly = true,
},
},
new Section("Password (optional)")
{
Alpha = disabled_alpha,
Child = new SettingsPasswordTextBox
{
RelativeSizeAxes = Axes.X,
TabbableContentContainer = this,
ReadOnly = true,
},
},
}
}
},
},
initialBeatmapControl = new BeatmapSelectionControl
new SectionContainer
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
RelativeSizeAxes = Axes.X,
Width = 0.5f
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
Padding = new MarginPadding { Left = FIELD_PADDING / 2 },
Children = new[]
{
new Section("Max participants")
{
Alpha = disabled_alpha,
Child = MaxParticipantsField = new SettingsNumberTextBox
{
RelativeSizeAxes = Axes.X,
TabbableContentContainer = this,
ReadOnly = true,
},
},
new Section("Password (optional)")
{
Alpha = disabled_alpha,
Child = new SettingsPasswordTextBox
{
RelativeSizeAxes = Axes.X,
TabbableContentContainer = this,
ReadOnly = true,
},
},
}
}
}
},
},
initialBeatmapControl = new BeatmapSelectionControl
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
RelativeSizeAxes = Axes.X,
Width = 0.5f
}
},
},
}
}
},
new Drawable[]
},
},
new Drawable[]
{
new Container
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Y = 2,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Children = new Drawable[]
{
new Container
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4Extensions.FromHex(@"28242d").Darken(0.5f).Opacity(1f),
},
new FillFlowContainer
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Y = 2,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 20),
Margin = new MarginPadding { Vertical = 20 },
Padding = new MarginPadding { Horizontal = OsuScreen.HORIZONTAL_OVERFLOW_PADDING },
Children = new Drawable[]
{
new Box
ApplyButton = new CreateOrUpdateButton
{
RelativeSizeAxes = Axes.Both,
Colour = Color4Extensions.FromHex(@"28242d").Darken(0.5f).Opacity(1f),
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
Size = new Vector2(230, 55),
Enabled = { Value = false },
Action = apply,
},
new FillFlowContainer
ErrorText = new OsuSpriteText
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 20),
Margin = new MarginPadding { Vertical = 20 },
Padding = new MarginPadding { Horizontal = OsuScreen.HORIZONTAL_OVERFLOW_PADDING },
Children = new Drawable[]
{
ApplyButton = new CreateOrUpdateButton
{
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
Size = new Vector2(230, 55),
Enabled = { Value = false },
Action = apply,
},
ErrorText = new OsuSpriteText
{
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
Alpha = 0,
Depth = 1,
Colour = colours.RedDark
}
}
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
Alpha = 0,
Depth = 1,
Colour = colours.RedDark
}
}
}
}
}
},
}
}
},
loadingLayer = new LoadingLayer(dimContent)
loadingLayer = new LoadingLayer(true)
};
TypePicker.Current.BindValueChanged(type => typeLabel.Text = type.NewValue?.Name ?? string.Empty, true);

View File

@ -47,7 +47,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
[BackgroundDependencyLoader]
private void load()
{
AddInternal(loadingLayer = new LoadingLayer(Carousel));
AddInternal(loadingLayer = new LoadingLayer(true));
initialBeatmap = Beatmap.Value;
initialRuleset = Ruleset.Value;
initialMods = Mods.Value.ToList();

View File

@ -62,7 +62,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
// todo: this should be implemented via a custom HUD implementation, and correctly masked to the main content area.
LoadComponentAsync(leaderboard = new MultiplayerGameplayLeaderboard(ScoreProcessor, userIds), HUDOverlay.Add);
HUDOverlay.Add(loadingDisplay = new LoadingLayer(DrawableRuleset) { Depth = float.MaxValue });
HUDOverlay.Add(loadingDisplay = new LoadingLayer(true) { Depth = float.MaxValue });
if (Token == null)
return; // Todo: Somehow handle token retrieval failure.

View File

@ -64,243 +64,234 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
Container dimContent;
InternalChildren = new Drawable[]
{
dimContent = new Container
new Box
{
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
Colour = Color4Extensions.FromHex(@"28242d"),
},
new GridContainer
{
RelativeSizeAxes = Axes.Both,
RowDimensions = new[]
{
new Box
new Dimension(GridSizeMode.Distributed),
new Dimension(GridSizeMode.AutoSize),
},
Content = new[]
{
new Drawable[]
{
RelativeSizeAxes = Axes.Both,
Colour = Color4Extensions.FromHex(@"28242d"),
},
new GridContainer
{
RelativeSizeAxes = Axes.Both,
RowDimensions = new[]
new OsuScrollContainer
{
new Dimension(GridSizeMode.Distributed),
new Dimension(GridSizeMode.AutoSize),
},
Content = new[]
{
new Drawable[]
Padding = new MarginPadding
{
new OsuScrollContainer
{
Padding = new MarginPadding
{
Horizontal = OsuScreen.HORIZONTAL_OVERFLOW_PADDING,
Vertical = 10
},
RelativeSizeAxes = Axes.Both,
Children = new[]
{
new Container
{
Padding = new MarginPadding { Horizontal = WaveOverlayContainer.WIDTH_PADDING },
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Children = new Drawable[]
{
new SectionContainer
{
Padding = new MarginPadding { Right = FIELD_PADDING / 2 },
Children = new[]
{
new Section("Room name")
{
Child = NameField = new SettingsTextBox
{
RelativeSizeAxes = Axes.X,
TabbableContentContainer = this,
LengthLimit = 100
},
},
new Section("Duration")
{
Child = DurationField = new DurationDropdown
{
RelativeSizeAxes = Axes.X,
Items = new[]
{
TimeSpan.FromMinutes(30),
TimeSpan.FromHours(1),
TimeSpan.FromHours(2),
TimeSpan.FromHours(4),
TimeSpan.FromHours(8),
TimeSpan.FromHours(12),
//TimeSpan.FromHours(16),
TimeSpan.FromHours(24),
TimeSpan.FromDays(3),
TimeSpan.FromDays(7)
}
}
},
new Section("Room visibility")
{
Alpha = disabled_alpha,
Child = AvailabilityPicker = new RoomAvailabilityPicker
{
Enabled = { Value = false }
},
},
new Section("Game type")
{
Alpha = disabled_alpha,
Child = new FillFlowContainer
{
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
Direction = FillDirection.Vertical,
Spacing = new Vector2(7),
Children = new Drawable[]
{
TypePicker = new GameTypePicker
{
RelativeSizeAxes = Axes.X,
Enabled = { Value = false }
},
typeLabel = new OsuSpriteText
{
Font = OsuFont.GetFont(size: 14),
Colour = colours.Yellow
},
},
},
},
new Section("Max participants")
{
Alpha = disabled_alpha,
Child = MaxParticipantsField = new SettingsNumberTextBox
{
RelativeSizeAxes = Axes.X,
TabbableContentContainer = this,
ReadOnly = true,
},
},
new Section("Password (optional)")
{
Alpha = disabled_alpha,
Child = new SettingsPasswordTextBox
{
RelativeSizeAxes = Axes.X,
TabbableContentContainer = this,
ReadOnly = true,
},
},
},
},
new SectionContainer
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
Padding = new MarginPadding { Left = FIELD_PADDING / 2 },
Children = new[]
{
new Section("Playlist")
{
Child = new GridContainer
{
RelativeSizeAxes = Axes.X,
Height = 300,
Content = new[]
{
new Drawable[]
{
playlist = new DrawableRoomPlaylist(true, true) { RelativeSizeAxes = Axes.Both }
},
new Drawable[]
{
playlistLength = new OsuSpriteText
{
Margin = new MarginPadding { Vertical = 5 },
Colour = colours.Yellow,
Font = OsuFont.GetFont(size: 12),
}
},
new Drawable[]
{
new PurpleTriangleButton
{
RelativeSizeAxes = Axes.X,
Height = 40,
Text = "Edit playlist",
Action = () => EditPlaylist?.Invoke()
}
}
},
RowDimensions = new[]
{
new Dimension(),
new Dimension(GridSizeMode.AutoSize),
new Dimension(GridSizeMode.AutoSize),
}
}
},
},
},
},
}
},
},
Horizontal = OsuScreen.HORIZONTAL_OVERFLOW_PADDING,
Vertical = 10
},
new Drawable[]
RelativeSizeAxes = Axes.Both,
Children = new[]
{
new Container
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Y = 2,
Padding = new MarginPadding { Horizontal = WaveOverlayContainer.WIDTH_PADDING },
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Children = new Drawable[]
{
new Box
new SectionContainer
{
RelativeSizeAxes = Axes.Both,
Colour = Color4Extensions.FromHex(@"28242d").Darken(0.5f).Opacity(1f),
},
new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 20),
Margin = new MarginPadding { Vertical = 20 },
Padding = new MarginPadding { Horizontal = OsuScreen.HORIZONTAL_OVERFLOW_PADDING },
Children = new Drawable[]
Padding = new MarginPadding { Right = FIELD_PADDING / 2 },
Children = new[]
{
ApplyButton = new CreateRoomButton
new Section("Room name")
{
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
Size = new Vector2(230, 55),
Enabled = { Value = false },
Action = apply,
Child = NameField = new SettingsTextBox
{
RelativeSizeAxes = Axes.X,
TabbableContentContainer = this,
LengthLimit = 100
},
},
ErrorText = new OsuSpriteText
new Section("Duration")
{
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
Alpha = 0,
Depth = 1,
Colour = colours.RedDark
}
}
Child = DurationField = new DurationDropdown
{
RelativeSizeAxes = Axes.X,
Items = new[]
{
TimeSpan.FromMinutes(30),
TimeSpan.FromHours(1),
TimeSpan.FromHours(2),
TimeSpan.FromHours(4),
TimeSpan.FromHours(8),
TimeSpan.FromHours(12),
//TimeSpan.FromHours(16),
TimeSpan.FromHours(24),
TimeSpan.FromDays(3),
TimeSpan.FromDays(7)
}
}
},
new Section("Room visibility")
{
Alpha = disabled_alpha,
Child = AvailabilityPicker = new RoomAvailabilityPicker
{
Enabled = { Value = false }
},
},
new Section("Game type")
{
Alpha = disabled_alpha,
Child = new FillFlowContainer
{
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
Direction = FillDirection.Vertical,
Spacing = new Vector2(7),
Children = new Drawable[]
{
TypePicker = new GameTypePicker
{
RelativeSizeAxes = Axes.X,
Enabled = { Value = false }
},
typeLabel = new OsuSpriteText
{
Font = OsuFont.GetFont(size: 14),
Colour = colours.Yellow
},
},
},
},
new Section("Max participants")
{
Alpha = disabled_alpha,
Child = MaxParticipantsField = new SettingsNumberTextBox
{
RelativeSizeAxes = Axes.X,
TabbableContentContainer = this,
ReadOnly = true,
},
},
new Section("Password (optional)")
{
Alpha = disabled_alpha,
Child = new SettingsPasswordTextBox
{
RelativeSizeAxes = Axes.X,
TabbableContentContainer = this,
ReadOnly = true,
},
},
},
},
new SectionContainer
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
Padding = new MarginPadding { Left = FIELD_PADDING / 2 },
Children = new[]
{
new Section("Playlist")
{
Child = new GridContainer
{
RelativeSizeAxes = Axes.X,
Height = 300,
Content = new[]
{
new Drawable[]
{
playlist = new DrawableRoomPlaylist(true, true) { RelativeSizeAxes = Axes.Both }
},
new Drawable[]
{
playlistLength = new OsuSpriteText
{
Margin = new MarginPadding { Vertical = 5 },
Colour = colours.Yellow,
Font = OsuFont.GetFont(size: 12),
}
},
new Drawable[]
{
new PurpleTriangleButton
{
RelativeSizeAxes = Axes.X,
Height = 40,
Text = "Edit playlist",
Action = () => EditPlaylist?.Invoke()
}
}
},
RowDimensions = new[]
{
new Dimension(),
new Dimension(GridSizeMode.AutoSize),
new Dimension(GridSizeMode.AutoSize),
}
}
},
},
},
},
}
},
},
},
new Drawable[]
{
new Container
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Y = 2,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4Extensions.FromHex(@"28242d").Darken(0.5f).Opacity(1f),
},
new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 20),
Margin = new MarginPadding { Vertical = 20 },
Padding = new MarginPadding { Horizontal = OsuScreen.HORIZONTAL_OVERFLOW_PADDING },
Children = new Drawable[]
{
ApplyButton = new CreateRoomButton
{
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
Size = new Vector2(230, 55),
Enabled = { Value = false },
Action = apply,
},
ErrorText = new OsuSpriteText
{
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
Alpha = 0,
Depth = 1,
Colour = colours.RedDark
}
}
}
}
}
},
}
}
},
loadingLayer = new LoadingLayer(dimContent)
loadingLayer = new LoadingLayer(true)
};
TypePicker.Current.BindValueChanged(type => typeLabel.Text = type.NewValue?.Name ?? string.Empty, true);

View File

@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
@ -114,11 +115,17 @@ namespace osu.Game.Screens
Mods = screenDependencies.Mods;
}
protected BackgroundScreen Background => backgroundStack?.CurrentScreen as BackgroundScreen;
/// <summary>
/// The background created and owned by this screen. May be null if the background didn't change.
/// </summary>
[CanBeNull]
private BackgroundScreen ownedBackground;
private BackgroundScreen localBackground;
[CanBeNull]
private BackgroundScreen background;
[Resolved(canBeNull: true)]
[CanBeNull]
private BackgroundScreenStack backgroundStack { get; set; }
[Resolved(canBeNull: true)]
@ -140,6 +147,21 @@ namespace osu.Game.Screens
Activity.Value ??= InitialActivity;
}
/// <summary>
/// Apply arbitrary changes to the current background screen in a thread safe manner.
/// </summary>
/// <param name="action">The operation to perform.</param>
public void ApplyToBackground(Action<BackgroundScreen> action)
{
if (backgroundStack == null)
throw new InvalidOperationException("Attempted to apply to background without a background stack being available.");
if (background == null)
throw new InvalidOperationException("Attempted to apply to background before screen is pushed.");
background.ApplyToBackground(action);
}
public override void OnResuming(IScreen last)
{
if (PlayResumeSound)
@ -160,7 +182,16 @@ namespace osu.Game.Screens
{
applyArrivingDefaults(false);
backgroundStack?.Push(localBackground = CreateBackground());
backgroundStack?.Push(ownedBackground = CreateBackground());
background = backgroundStack?.CurrentScreen as BackgroundScreen;
if (background != ownedBackground)
{
// background may have not been replaced, at which point we don't want to track the background lifetime.
ownedBackground?.Dispose();
ownedBackground = null;
}
base.OnEntering(last);
}
@ -173,7 +204,7 @@ namespace osu.Game.Screens
if (base.OnExiting(next))
return true;
if (localBackground != null && backgroundStack?.CurrentScreen == localBackground)
if (ownedBackground != null && backgroundStack?.CurrentScreen == ownedBackground)
backgroundStack?.Exit();
return false;

View File

@ -53,7 +53,6 @@ namespace osu.Game.Screens.Play
private readonly Bindable<IReadOnlyList<Mod>> mods;
private readonly Drawable facade;
private LoadingSpinner loading;
private Sprite backgroundSprite;
public IBindable<IReadOnlyList<Mod>> Mods => mods;
@ -123,7 +122,7 @@ namespace osu.Game.Screens.Play
Masking = true,
Children = new Drawable[]
{
backgroundSprite = new Sprite
new Sprite
{
RelativeSizeAxes = Axes.Both,
Texture = beatmap?.Background,
@ -131,7 +130,7 @@ namespace osu.Game.Screens.Play
Anchor = Anchor.Centre,
FillMode = FillMode.Fill,
},
loading = new LoadingLayer(backgroundSprite)
loading = new LoadingLayer(true)
}
},
new OsuSpriteText

View File

@ -24,7 +24,19 @@ namespace osu.Game.Screens.Play
Alpha = 0f;
}
public BackgroundScreenBeatmap DimmableBackground { get; set; }
private BackgroundScreenBeatmap dimmableBackground;
public BackgroundScreenBeatmap DimmableBackground
{
get => dimmableBackground;
set
{
dimmableBackground = value;
if (IsLoaded)
updateBackgroundFade();
}
}
[BackgroundDependencyLoader]
private void load(OsuColour colours, IBindable<WorkingBeatmap> beatmap)
@ -75,11 +87,16 @@ namespace osu.Game.Screens.Play
protected override void PopIn()
{
DimmableBackground?.FadeColour(OsuColour.Gray(0.5f), FADE_DURATION, Easing.OutQuint);
updateBackgroundFade();
this.FadeIn(FADE_DURATION, Easing.OutQuint);
}
private void updateBackgroundFade()
{
DimmableBackground?.FadeColour(OsuColour.Gray(0.5f), FADE_DURATION, Easing.OutQuint);
}
protected override void PopOut() => this.FadeOut(FADE_DURATION);
}
}

View File

@ -721,15 +721,20 @@ namespace osu.Game.Screens.Play
.Delay(250)
.FadeIn(250);
Background.EnableUserDim.Value = true;
Background.BlurAmount.Value = 0;
ApplyToBackground(b =>
{
b.EnableUserDim.Value = true;
b.BlurAmount.Value = 0;
// bind component bindables.
b.IsBreakTime.BindTo(breakTracker.IsBreakTime);
b.StoryboardReplacesBackground.BindTo(storyboardReplacesBackground);
});
// bind component bindables.
Background.IsBreakTime.BindTo(breakTracker.IsBreakTime);
HUDOverlay.IsBreakTime.BindTo(breakTracker.IsBreakTime);
DimmableStoryboard.IsBreakTime.BindTo(breakTracker.IsBreakTime);
Background.StoryboardReplacesBackground.BindTo(storyboardReplacesBackground);
DimmableStoryboard.StoryboardReplacesBackground.BindTo(storyboardReplacesBackground);
storyboardReplacesBackground.Value = Beatmap.Value.Storyboard.ReplacesBackground && Beatmap.Value.Storyboard.HasDrawable;
@ -875,7 +880,7 @@ namespace osu.Game.Screens.Play
float fadeOutDuration = instant ? 0 : 250;
this.FadeOut(fadeOutDuration);
Background.EnableUserDim.Value = false;
ApplyToBackground(b => b.EnableUserDim.Value = false);
storyboardReplacesBackground.Value = false;
}

View File

@ -67,7 +67,7 @@ namespace osu.Game.Screens.Play
backgroundBrightnessReduction = value;
Background.FadeColour(OsuColour.Gray(backgroundBrightnessReduction ? 0.8f : 1), 200);
ApplyToBackground(b => b.FadeColour(OsuColour.Gray(backgroundBrightnessReduction ? 0.8f : 1), 200));
}
}
@ -176,12 +176,17 @@ namespace osu.Game.Screens.Play
{
base.OnEntering(last);
if (epilepsyWarning != null)
epilepsyWarning.DimmableBackground = Background;
ApplyToBackground(b =>
{
if (epilepsyWarning != null)
epilepsyWarning.DimmableBackground = b;
b?.FadeColour(Color4.White, 800, Easing.OutQuint);
});
Beatmap.Value.Track.AddAdjustment(AdjustableProperty.Volume, volumeAdjustment);
content.ScaleTo(0.7f);
Background?.FadeColour(Color4.White, 800, Easing.OutQuint);
contentIn();
@ -225,7 +230,8 @@ namespace osu.Game.Screens.Play
content.ScaleTo(0.7f, 150, Easing.InQuint);
this.FadeOut(150);
Background.EnableUserDim.Value = false;
ApplyToBackground(b => b.EnableUserDim.Value = false);
BackgroundBrightnessReduction = false;
Beatmap.Value.Track.RemoveAdjustment(AdjustableProperty.Volume, volumeAdjustment);
@ -270,16 +276,22 @@ namespace osu.Game.Screens.Play
if (inputManager.HoveredDrawables.Contains(VisualSettings))
{
// Preview user-defined background dim and blur when hovered on the visual settings panel.
Background.EnableUserDim.Value = true;
Background.BlurAmount.Value = 0;
ApplyToBackground(b =>
{
b.EnableUserDim.Value = true;
b.BlurAmount.Value = 0;
});
BackgroundBrightnessReduction = false;
}
else
{
// Returns background dim and blur to the values specified by PlayerLoader.
Background.EnableUserDim.Value = false;
Background.BlurAmount.Value = BACKGROUND_BLUR;
ApplyToBackground(b =>
{
// Returns background dim and blur to the values specified by PlayerLoader.
b.EnableUserDim.Value = false;
b.BlurAmount.Value = BACKGROUND_BLUR;
});
BackgroundBrightnessReduction = true;
}

View File

@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using osu.Game.Screens.Backgrounds;
namespace osu.Game.Screens.Play
@ -9,6 +10,6 @@ namespace osu.Game.Screens.Play
{
protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap.Value);
public new BackgroundScreenBeatmap Background => (BackgroundScreenBeatmap)base.Background;
public void ApplyToBackground(Action<BackgroundScreenBeatmap> action) => base.ApplyToBackground(b => action.Invoke((BackgroundScreenBeatmap)b));
}
}

View File

@ -18,14 +18,13 @@ using osu.Game.Input.Bindings;
using osu.Game.Online.API;
using osu.Game.Rulesets.Mods;
using osu.Game.Scoring;
using osu.Game.Screens.Backgrounds;
using osu.Game.Screens.Play;
using osu.Game.Screens.Ranking.Statistics;
using osuTK;
namespace osu.Game.Screens.Ranking
{
public abstract class ResultsScreen : OsuScreen, IKeyBindingHandler<GlobalAction>
public abstract class ResultsScreen : ScreenWithBeatmapBackground, IKeyBindingHandler<GlobalAction>
{
protected const float BACKGROUND_BLUR = 20;
private static readonly float screen_height = 768 - TwoLayerButton.SIZE_EXTENDED.Y;
@ -35,8 +34,6 @@ namespace osu.Game.Screens.Ranking
// Temporary for now to stop dual transitions. Should respect the current toolbar mode, but there's no way to do so currently.
public override bool HideOverlaysOnEnter => true;
protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap.Value);
public readonly Bindable<ScoreInfo> SelectedScore = new Bindable<ScoreInfo>();
public readonly ScoreInfo Score;
@ -237,15 +234,18 @@ namespace osu.Game.Screens.Ranking
{
base.OnEntering(last);
((BackgroundScreenBeatmap)Background).BlurAmount.Value = BACKGROUND_BLUR;
ApplyToBackground(b =>
{
b.BlurAmount.Value = BACKGROUND_BLUR;
b.FadeTo(0.5f, 250);
});
Background.FadeTo(0.5f, 250);
bottomPanel.FadeTo(1, 250);
}
public override bool OnExiting(IScreen next)
{
Background.FadeTo(1, 250);
ApplyToBackground(b => b.FadeTo(1, 250));
return base.OnExiting(next);
}
@ -295,7 +295,7 @@ namespace osu.Game.Screens.Ranking
ScorePanelList.HandleInput = false;
// Dim background.
Background.FadeTo(0.1f, 150);
ApplyToBackground(b => b.FadeTo(0.1f, 150));
detachedPanel = expandedPanel;
}
@ -319,7 +319,7 @@ namespace osu.Game.Screens.Ranking
ScorePanelList.HandleInput = true;
// Un-dim background.
Background.FadeTo(0.5f, 150);
ApplyToBackground(b => b.FadeTo(0.5f, 150));
detachedPanel = null;
}

View File

@ -13,6 +13,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Pooling;
using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
using osu.Framework.Layout;
using osu.Framework.Threading;
using osu.Framework.Utils;
using osu.Game.Beatmaps;
@ -124,6 +125,8 @@ namespace osu.Game.Screens.Select
{
BeatmapSetsChanged?.Invoke();
BeatmapSetsLoaded = true;
itemsCache.Invalidate();
});
}
@ -567,6 +570,15 @@ namespace osu.Game.Screens.Select
#endregion
protected override bool OnInvalidate(Invalidation invalidation, InvalidationSource source)
{
// handles the vertical size of the carousel changing (ie. on window resize when aspect ratio has changed).
if ((invalidation & Invalidation.Layout) > 0)
itemsCache.Invalidate();
return base.OnInvalidate(invalidation, source);
}
protected override void Update()
{
base.Update();
@ -777,13 +789,19 @@ namespace osu.Game.Screens.Select
Scroll.ScrollContent.Height = currentY;
if (BeatmapSetsLoaded && (selectedBeatmapSet == null || selectedBeatmap == null || selectedBeatmapSet.State.Value != CarouselItemState.Selected))
{
selectedBeatmapSet = null;
SelectionChanged?.Invoke(null);
}
itemsCache.Validate();
// update and let external consumers know about selection loss.
if (BeatmapSetsLoaded)
{
bool selectionLost = selectedBeatmapSet != null && selectedBeatmapSet.State.Value != CarouselItemState.Selected;
if (selectionLost)
{
selectedBeatmapSet = null;
SelectionChanged?.Invoke(null);
}
}
}
private bool firstScroll = true;
@ -806,14 +824,13 @@ namespace osu.Game.Screens.Select
break;
case PendingScrollOperation.Immediate:
// in order to simplify animation logic, rather than using the animated version of ScrollTo,
// we take the difference in scroll height and apply to all visible panels.
// this avoids edge cases like when the visible panels is reduced suddenly, causing ScrollContainer
// to enter clamp-special-case mode where it animates completely differently to normal.
float scrollChange = scrollTarget.Value - Scroll.Current;
Scroll.ScrollTo(scrollTarget.Value, false);
foreach (var i in Scroll.Children)
i.Y += scrollChange;
break;
@ -919,7 +936,6 @@ namespace osu.Game.Screens.Select
Masking = false;
}
// ReSharper disable once OptionalParameterHierarchyMismatch 2020.3 EAP4 bug. (https://youtrack.jetbrains.com/issue/RSRP-481535?p=RIDER-51910)
protected override void OnUserScroll(float value, bool animated = true, double? distanceDecay = default)
{
UserScrolling = true;

View File

@ -63,8 +63,6 @@ namespace osu.Game.Screens.Select
public BeatmapDetails()
{
Container content;
Children = new Drawable[]
{
new Box
@ -72,7 +70,7 @@ namespace osu.Game.Screens.Select
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black.Opacity(0.5f),
},
content = new Container
new Container
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Horizontal = spacing },
@ -159,7 +157,7 @@ namespace osu.Game.Screens.Select
},
},
},
loading = new LoadingLayer(content),
loading = new LoadingLayer(true),
};
}

View File

@ -5,6 +5,8 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@ -36,10 +38,14 @@ namespace osu.Game.Screens.Select.Carousel
public IEnumerable<DrawableCarouselItem> DrawableBeatmaps => beatmapContainer?.Children ?? Enumerable.Empty<DrawableCarouselItem>();
[CanBeNull]
private Container<DrawableCarouselItem> beatmapContainer;
private BeatmapSetInfo beatmapSet;
[CanBeNull]
private Task beatmapsLoadTask;
[Resolved]
private BeatmapManager manager { get; set; }
@ -85,7 +91,9 @@ namespace osu.Game.Screens.Select.Carousel
base.UpdateItem();
Content.Clear();
beatmapContainer = null;
beatmapsLoadTask = null;
if (Item == null)
return;
@ -122,11 +130,7 @@ namespace osu.Game.Screens.Select.Carousel
MovementContainer.MoveToX(0, 500, Easing.OutExpo);
if (beatmapContainer != null)
{
foreach (var beatmap in beatmapContainer)
beatmap.MoveToY(0, 800, Easing.OutQuint);
}
updateBeatmapYPositions();
}
protected override void Selected()
@ -163,7 +167,7 @@ namespace osu.Game.Screens.Select.Carousel
ChildrenEnumerable = visibleBeatmaps.Select(c => c.CreateDrawableRepresentation())
};
LoadComponentAsync(beatmapContainer, loaded =>
beatmapsLoadTask = LoadComponentAsync(beatmapContainer, loaded =>
{
// make sure the pooled target hasn't changed.
if (beatmapContainer != loaded)
@ -173,16 +177,29 @@ namespace osu.Game.Screens.Select.Carousel
updateBeatmapYPositions();
});
}
}
void updateBeatmapYPositions()
private void updateBeatmapYPositions()
{
if (beatmapContainer == null)
return;
if (beatmapsLoadTask == null || !beatmapsLoadTask.IsCompleted)
return;
float yPos = DrawableCarouselBeatmap.CAROUSEL_BEATMAP_SPACING;
bool isSelected = Item.State.Value == CarouselItemState.Selected;
foreach (var panel in beatmapContainer.Children)
{
float yPos = DrawableCarouselBeatmap.CAROUSEL_BEATMAP_SPACING;
foreach (var panel in beatmapContainer.Children)
if (isSelected)
{
panel.MoveToY(yPos, 800, Easing.OutQuint);
yPos += panel.Item.TotalHeight;
}
else
panel.MoveToY(0, 800, Easing.OutQuint);
}
}

View File

@ -19,7 +19,6 @@ using osu.Game.Overlays;
using osu.Game.Overlays.Mods;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Screens.Backgrounds;
using osu.Game.Screens.Edit;
using osu.Game.Screens.Menu;
using osu.Game.Screens.Select.Options;
@ -38,10 +37,11 @@ using osu.Game.Collections;
using osu.Game.Graphics.UserInterface;
using osu.Game.Scoring;
using System.Diagnostics;
using osu.Game.Screens.Play;
namespace osu.Game.Screens.Select
{
public abstract class SongSelect : OsuScreen, IKeyBindingHandler<GlobalAction>
public abstract class SongSelect : ScreenWithBeatmapBackground, IKeyBindingHandler<GlobalAction>
{
public static readonly float WEDGE_HEIGHT = 245;
@ -76,8 +76,6 @@ namespace osu.Game.Screens.Select
[Resolved]
private Bindable<IReadOnlyList<Mod>> selectedMods { get; set; }
protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap.Value);
protected BeatmapCarousel Carousel { get; private set; }
private BeatmapInfoWedge beatmapInfoWedge;
@ -428,16 +426,21 @@ namespace osu.Game.Screens.Select
private void updateSelectedBeatmap(BeatmapInfo beatmap)
{
if (beatmap == null && beatmapNoDebounce == null)
return;
if (beatmap?.Equals(beatmapNoDebounce) == true)
return;
beatmapNoDebounce = beatmap;
performUpdateSelected();
}
private void updateSelectedRuleset(RulesetInfo ruleset)
{
if (ruleset == null && rulesetNoDebounce == null)
return;
if (ruleset?.Equals(rulesetNoDebounce) == true)
return;
@ -684,12 +687,12 @@ namespace osu.Game.Screens.Select
/// <param name="beatmap">The working beatmap.</param>
private void updateComponentFromBeatmap(WorkingBeatmap beatmap)
{
if (Background is BackgroundScreenBeatmap backgroundModeBeatmap)
ApplyToBackground(backgroundModeBeatmap =>
{
backgroundModeBeatmap.Beatmap = beatmap;
backgroundModeBeatmap.BlurAmount.Value = BACKGROUND_BLUR;
backgroundModeBeatmap.FadeColour(Color4.White, 250);
}
});
beatmapInfoWedge.Beatmap = beatmap;