Merge branch 'master' into beatmap-set-downloader

This commit is contained in:
Dean Herbert
2018-06-06 20:32:58 +09:00
committed by GitHub
33 changed files with 545 additions and 297 deletions

View File

@ -7,33 +7,34 @@ using System.Linq;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
namespace osu.Game.Rulesets.Osu.Mods namespace osu.Game.Rulesets.Osu.Mods
{ {
public class OsuModHidden : ModHidden, IApplicableToDrawableHitObjects public class OsuModHidden : ModHidden
{ {
public override string Description => @"Play with no approach circles and fading circles/sliders."; public override string Description => @"Play with no approach circles and fading circles/sliders.";
public override double ScoreMultiplier => 1.06; public override double ScoreMultiplier => 1.06;
private const double fade_in_duration_multiplier = 0.4; private const double fade_in_duration_multiplier = 0.4;
private const double fade_out_duration_multiplier = 0.3; private const double fade_out_duration_multiplier = 0.3;
public void ApplyToDrawableHitObjects(IEnumerable<DrawableHitObject> drawables) public override void ApplyToDrawableHitObjects(IEnumerable<DrawableHitObject> drawables)
{ {
void adjustFadeIn(OsuHitObject h) => h.TimeFadein = h.TimePreempt * fade_in_duration_multiplier;
foreach (var d in drawables.OfType<DrawableOsuHitObject>()) foreach (var d in drawables.OfType<DrawableOsuHitObject>())
{ {
d.ApplyCustomUpdateState += ApplyHiddenState; adjustFadeIn(d.HitObject);
d.HitObject.TimeFadein = d.HitObject.TimePreempt * fade_in_duration_multiplier;
foreach (var h in d.HitObject.NestedHitObjects.OfType<OsuHitObject>()) foreach (var h in d.HitObject.NestedHitObjects.OfType<OsuHitObject>())
h.TimeFadein = h.TimePreempt * fade_in_duration_multiplier; adjustFadeIn(h);
} }
base.ApplyToDrawableHitObjects(drawables);
} }
protected void ApplyHiddenState(DrawableHitObject drawable, ArmedState state) protected override void ApplyHiddenState(DrawableHitObject drawable, ArmedState state)
{ {
if (!(drawable is DrawableOsuHitObject d)) if (!(drawable is DrawableOsuHitObject d))
return; return;

View File

@ -264,7 +264,8 @@ namespace osu.Game.Tests.Beatmaps.IO
private string createTemporaryBeatmap() private string createTemporaryBeatmap()
{ {
var temp = new FileInfo(osz_path).CopyTo(Path.GetTempFileName(), true).FullName; var temp = Path.GetTempFileName() + ".osz";
File.Copy(osz_path, temp, true);
Assert.IsTrue(File.Exists(temp)); Assert.IsTrue(File.Exists(temp));
return temp; return temp;
} }
@ -344,12 +345,12 @@ namespace osu.Game.Tests.Beatmaps.IO
private void waitForOrAssert(Func<bool> result, string failureMessage, int timeout = 60000) private void waitForOrAssert(Func<bool> result, string failureMessage, int timeout = 60000)
{ {
Action waitAction = () => Task task = Task.Run(() =>
{ {
while (!result()) Thread.Sleep(200); while (!result()) Thread.Sleep(200);
}; });
Assert.IsTrue(waitAction.BeginInvoke(null, null).AsyncWaitHandle.WaitOne(timeout), failureMessage); Assert.IsTrue(task.Wait(timeout), failureMessage);
} }
} }
} }

View File

@ -53,7 +53,7 @@ namespace osu.Game.Tests.Visual
AddStep("show", () => AddStep("show", () =>
{ {
infoWedge.State = Visibility.Visible; infoWedge.State = Visibility.Visible;
infoWedge.UpdateBeatmap(beatmap); infoWedge.Beatmap = beatmap;
}); });
// select part is redundant, but wait for load isn't // select part is redundant, but wait for load isn't
@ -133,7 +133,7 @@ namespace osu.Game.Tests.Visual
AddStep($"select {b.Metadata.Title} beatmap", () => AddStep($"select {b.Metadata.Title} beatmap", () =>
{ {
infoBefore = infoWedge.Info; infoBefore = infoWedge.Info;
infoWedge.UpdateBeatmap(beatmap.Value = new TestWorkingBeatmap(b)); infoWedge.Beatmap = beatmap.Value = new TestWorkingBeatmap(b);
}); });
AddUntilStep(() => infoWedge.Info != infoBefore, "wait for async load"); AddUntilStep(() => infoWedge.Info != infoBefore, "wait for async load");
@ -144,7 +144,7 @@ namespace osu.Game.Tests.Visual
AddStep("select null beatmap", () => AddStep("select null beatmap", () =>
{ {
beatmap.Value = beatmap.Default; beatmap.Value = beatmap.Default;
infoWedge.UpdateBeatmap(beatmap); infoWedge.Beatmap = beatmap;
}); });
} }

View File

@ -0,0 +1,115 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Game.Screens;
using osu.Game.Screens.Menu;
using OpenTK.Graphics;
namespace osu.Game.Tests.Visual
{
[TestFixture]
public class TestCaseLoaderAnimation : OsuTestCase
{
private TestLoader loader;
protected override void LoadComplete()
{
base.LoadComplete();
// required to preload the logo in a headless run (so it doesn't delay the loading itself).
Add(new OsuLogo());
bool logoVisible = false;
AddStep("almost instant display", () => Child = loader = new TestLoader(250));
AddUntilStep(() =>
{
logoVisible = loader.Logo?.Alpha > 0;
return loader.Logo != null && loader.ScreenLoaded;
}, "loaded");
AddAssert("logo not visible", () => !logoVisible);
AddStep("short load", () => Child = loader = new TestLoader(800));
AddUntilStep(() =>
{
logoVisible = loader.Logo?.Alpha > 0;
return loader.Logo != null && loader.ScreenLoaded;
}, "loaded");
AddAssert("logo visible", () => logoVisible);
AddUntilStep(() => loader.Logo?.Alpha == 0, "logo gone");
AddStep("longer load", () => Child = loader = new TestLoader(1400));
AddUntilStep(() =>
{
logoVisible = loader.Logo?.Alpha > 0;
return loader.Logo != null && loader.ScreenLoaded;
}, "loaded");
AddAssert("logo visible", () => logoVisible);
AddUntilStep(() => loader.Logo?.Alpha == 0, "logo gone");
}
private class TestLoader : Loader
{
private readonly double delay;
public OsuLogo Logo;
private TestScreen screen;
public bool ScreenLoaded => screen.IsCurrentScreen;
public TestLoader(double delay)
{
this.delay = delay;
}
protected override void LogoArriving(OsuLogo logo, bool resuming)
{
Logo = logo;
base.LogoArriving(logo, resuming);
}
protected override OsuScreen CreateLoadableScreen() => screen = new TestScreen();
protected override ShaderPrecompiler CreateShaderPrecompiler() => new TestShaderPrecompiler(delay);
private class TestShaderPrecompiler : ShaderPrecompiler
{
private readonly double delay;
private double startTime;
public TestShaderPrecompiler(double delay)
{
this.delay = delay;
}
protected override void LoadComplete()
{
base.LoadComplete();
startTime = Time.Current;
}
protected override bool AllLoaded => Time.Current > startTime + delay;
}
private class TestScreen : OsuScreen
{
public TestScreen()
{
Child = new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.DarkSlateGray,
Alpha = 0,
};
}
protected override void LogoArriving(OsuLogo logo, bool resuming)
{
base.LogoArriving(logo, resuming);
Child.FadeInFromZero(200);
}
}
}
}
}

View File

@ -170,7 +170,7 @@ namespace osu.Game.Beatmaps
{ {
if (error is OperationCanceledException) return; if (error is OperationCanceledException) return;
downloadNotification.State = ProgressNotificationState.Completed; downloadNotification.State = ProgressNotificationState.Cancelled;
Logger.Error(error, "Beatmap download failed!"); Logger.Error(error, "Beatmap download failed!");
currentDownloads.Remove(request); currentDownloads.Remove(request);
}; };

View File

@ -82,6 +82,8 @@ namespace osu.Game.Configuration
Set(OsuSetting.SpeedChangeVisualisation, SpeedChangeVisualisationMethod.Sequential); Set(OsuSetting.SpeedChangeVisualisation, SpeedChangeVisualisationMethod.Sequential);
Set(OsuSetting.IncreaseFirstObjectVisibility, true);
// Update // Update
Set(OsuSetting.ReleaseStream, ReleaseStream.Lazer); Set(OsuSetting.ReleaseStream, ReleaseStream.Lazer);
@ -144,6 +146,7 @@ namespace osu.Game.Configuration
ScreenshotCaptureMenuCursor, ScreenshotCaptureMenuCursor,
SongSelectRightMouseScroll, SongSelectRightMouseScroll,
BeatmapSkins, BeatmapSkins,
BeatmapHitsounds BeatmapHitsounds,
IncreaseFirstObjectVisibility
} }
} }

View File

@ -8,6 +8,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Input; using osu.Framework.Input;
using OpenTK; using OpenTK;
using osu.Framework.Configuration; using osu.Framework.Configuration;
using osu.Game.Overlays;
namespace osu.Game.Graphics.Containers namespace osu.Game.Graphics.Containers
{ {
@ -16,13 +17,13 @@ namespace osu.Game.Graphics.Containers
private SampleChannel samplePopIn; private SampleChannel samplePopIn;
private SampleChannel samplePopOut; private SampleChannel samplePopOut;
private readonly BindableBool allowOpeningOverlays = new BindableBool(true); protected readonly Bindable<OverlayActivation> OverlayActivationMode = new Bindable<OverlayActivation>(OverlayActivation.All);
[BackgroundDependencyLoader(true)] [BackgroundDependencyLoader(true)]
private void load(OsuGame osuGame, AudioManager audio) private void load(OsuGame osuGame, AudioManager audio)
{ {
if (osuGame != null) if (osuGame != null)
allowOpeningOverlays.BindTo(osuGame.AllowOpeningOverlays); OverlayActivationMode.BindTo(osuGame.OverlayActivationMode);
samplePopIn = audio.Sample.Get(@"UI/overlay-pop-in"); samplePopIn = audio.Sample.Get(@"UI/overlay-pop-in");
samplePopOut = audio.Sample.Get(@"UI/overlay-pop-out"); samplePopOut = audio.Sample.Get(@"UI/overlay-pop-out");
@ -52,20 +53,18 @@ namespace osu.Game.Graphics.Containers
private void onStateChanged(Visibility visibility) private void onStateChanged(Visibility visibility)
{ {
if (allowOpeningOverlays) switch (visibility)
{ {
switch (visibility) case Visibility.Visible:
{ if (OverlayActivationMode != OverlayActivation.Disabled)
case Visibility.Visible:
samplePopIn?.Play(); samplePopIn?.Play();
break; else
case Visibility.Hidden: State = Visibility.Hidden;
samplePopOut?.Play(); break;
break; case Visibility.Hidden:
} samplePopOut?.Play();
break;
} }
else
State = Visibility.Hidden;
} }
} }
} }

View File

@ -73,6 +73,7 @@ namespace osu.Game.Online.API
throw new TimeoutException(@"API request timeout hit"); throw new TimeoutException(@"API request timeout hit");
WebRequest = CreateWebRequest(); WebRequest = CreateWebRequest();
WebRequest.Failed += Fail;
WebRequest.AllowRetryOnTimeout = false; WebRequest.AllowRetryOnTimeout = false;
WebRequest.AddHeader("Authorization", $"Bearer {api.AccessToken}"); WebRequest.AddHeader("Authorization", $"Bearer {api.AccessToken}");

View File

@ -77,8 +77,7 @@ namespace osu.Game
public float ToolbarOffset => Toolbar.Position.Y + Toolbar.DrawHeight; public float ToolbarOffset => Toolbar.Position.Y + Toolbar.DrawHeight;
public readonly BindableBool HideOverlaysOnEnter = new BindableBool(); public readonly Bindable<OverlayActivation> OverlayActivationMode = new Bindable<OverlayActivation>();
public readonly BindableBool AllowOpeningOverlays = new BindableBool(true);
private OsuScreen screenStack; private OsuScreen screenStack;
@ -94,6 +93,8 @@ namespace osu.Game
private SettingsOverlay settings; private SettingsOverlay settings;
private readonly List<OverlayContainer> overlays = new List<OverlayContainer>();
// todo: move this to SongSelect once Screen has the ability to unsuspend. // todo: move this to SongSelect once Screen has the ability to unsuspend.
public readonly Bindable<IEnumerable<Mod>> SelectedMods = new Bindable<IEnumerable<Mod>>(new List<Mod>()); public readonly Bindable<IEnumerable<Mod>> SelectedMods = new Bindable<IEnumerable<Mod>>(new List<Mod>());
@ -106,6 +107,17 @@ namespace osu.Game
public void ToggleDirect() => direct.ToggleVisibility(); public void ToggleDirect() => direct.ToggleVisibility();
/// <summary>
/// Close all game-wide overlays.
/// </summary>
/// <param name="toolbar">Whether the toolbar should also be hidden.</param>
public void CloseAllOverlays(bool toolbar = true)
{
foreach (var o in overlays)
o.State = Visibility.Hidden;
if (toolbar) Toolbar.State = Visibility.Hidden;
}
private DependencyContainer dependencies; private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) => protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) =>
@ -251,7 +263,7 @@ namespace osu.Game
Depth = -5, Depth = -5,
OnHome = delegate OnHome = delegate
{ {
hideAllOverlays(); CloseAllOverlays(false);
intro?.ChildScreen?.MakeCurrent(); intro?.ChildScreen?.MakeCurrent();
}, },
}, overlayContent.Add); }, overlayContent.Add);
@ -308,6 +320,8 @@ namespace osu.Game
// ensure only one of these overlays are open at once. // ensure only one of these overlays are open at once.
var singleDisplayOverlays = new OverlayContainer[] { chat, social, direct }; var singleDisplayOverlays = new OverlayContainer[] { chat, social, direct };
overlays.AddRange(singleDisplayOverlays);
foreach (var overlay in singleDisplayOverlays) foreach (var overlay in singleDisplayOverlays)
{ {
overlay.StateChanged += state => overlay.StateChanged += state =>
@ -323,6 +337,8 @@ namespace osu.Game
} }
var singleDisplaySideOverlays = new OverlayContainer[] { settings, notifications }; var singleDisplaySideOverlays = new OverlayContainer[] { settings, notifications };
overlays.AddRange(singleDisplaySideOverlays);
foreach (var overlay in singleDisplaySideOverlays) foreach (var overlay in singleDisplaySideOverlays)
{ {
overlay.StateChanged += state => overlay.StateChanged += state =>
@ -339,6 +355,8 @@ namespace osu.Game
// eventually informational overlays should be displayed in a stack, but for now let's only allow one to stay open at a time. // eventually informational overlays should be displayed in a stack, but for now let's only allow one to stay open at a time.
var informationalOverlays = new OverlayContainer[] { beatmapSetOverlay, userProfile }; var informationalOverlays = new OverlayContainer[] { beatmapSetOverlay, userProfile };
overlays.AddRange(informationalOverlays);
foreach (var overlay in informationalOverlays) foreach (var overlay in informationalOverlays)
{ {
overlay.StateChanged += state => overlay.StateChanged += state =>
@ -353,6 +371,11 @@ namespace osu.Game
}; };
} }
OverlayActivationMode.ValueChanged += v =>
{
if (v != OverlayActivation.All) CloseAllOverlays();
};
void updateScreenOffset() void updateScreenOffset()
{ {
float offset = 0; float offset = 0;
@ -367,21 +390,6 @@ namespace osu.Game
settings.StateChanged += _ => updateScreenOffset(); settings.StateChanged += _ => updateScreenOffset();
notifications.StateChanged += _ => updateScreenOffset(); notifications.StateChanged += _ => updateScreenOffset();
notifications.Enabled.BindTo(AllowOpeningOverlays);
HideOverlaysOnEnter.ValueChanged += hide =>
{
//central game screen change logic.
if (hide)
{
hideAllOverlays();
musicController.State = Visibility.Hidden;
Toolbar.State = Visibility.Hidden;
}
else
Toolbar.State = Visibility.Visible;
};
} }
private void forwardLoggedErrorsToNotifications() private void forwardLoggedErrorsToNotifications()
@ -498,16 +506,6 @@ namespace osu.Game
private OsuScreen currentScreen; private OsuScreen currentScreen;
private FrameworkConfigManager frameworkConfig; private FrameworkConfigManager frameworkConfig;
private void hideAllOverlays()
{
settings.State = Visibility.Hidden;
chat.State = Visibility.Hidden;
direct.State = Visibility.Hidden;
social.State = Visibility.Hidden;
userProfile.State = Visibility.Hidden;
notifications.State = Visibility.Hidden;
}
protected override bool OnExiting() protected override bool OnExiting()
{ {
if (screenStack.ChildScreen == null) return false; if (screenStack.ChildScreen == null) return false;

View File

@ -21,7 +21,7 @@ namespace osu.Game.Overlays.BeatmapSet
private const float metadata_width = 225; private const float metadata_width = 225;
private const float spacing = 20; private const float spacing = 20;
private readonly MetadataSection description, source, tags; private readonly MetadataSection source, tags;
private readonly Box successRateBackground; private readonly Box successRateBackground;
private readonly SuccessRate successRate; private readonly SuccessRate successRate;
@ -83,7 +83,7 @@ namespace osu.Game.Overlays.BeatmapSet
Child = new Container Child = new Container
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Child = description = new MetadataSection("Description"), Child = new MetadataSection("Description"),
}, },
}, },
new Container new Container
@ -135,8 +135,6 @@ namespace osu.Game.Overlays.BeatmapSet
private void load(OsuColour colours) private void load(OsuColour colours)
{ {
successRateBackground.Colour = colours.GrayE; successRateBackground.Colour = colours.GrayE;
source.TextColour = description.TextColour = colours.Gray5;
tags.TextColour = colours.BlueDark;
updateDisplay(); updateDisplay();
} }
@ -195,7 +193,7 @@ namespace osu.Game.Overlays.BeatmapSet
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuColour colours) private void load(OsuColour colours)
{ {
header.Colour = colours.Gray5; header.Colour = textFlow.Colour = colours.Gray5;
} }
} }
} }

View File

@ -22,11 +22,6 @@ namespace osu.Game.Overlays
public const float TRANSITION_LENGTH = 600; public const float TRANSITION_LENGTH = 600;
/// <summary>
/// Whether posted notifications should be processed.
/// </summary>
public readonly BindableBool Enabled = new BindableBool(true);
private FlowContainer<NotificationSection> sections; private FlowContainer<NotificationSection> sections;
/// <summary> /// <summary>
@ -34,27 +29,6 @@ namespace osu.Game.Overlays
/// </summary> /// </summary>
public Func<float> GetToolbarHeight; public Func<float> GetToolbarHeight;
public NotificationOverlay()
{
ScheduledDelegate notificationsEnabler = null;
Enabled.ValueChanged += v =>
{
if (!IsLoaded)
{
processingPosts = v;
return;
}
notificationsEnabler?.Cancel();
if (v)
// we want a slight delay before toggling notifications on to avoid the user becoming overwhelmed.
notificationsEnabler = Scheduler.AddDelayed(() => processingPosts = true, 1000);
else
processingPosts = false;
};
}
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
@ -103,6 +77,29 @@ namespace osu.Game.Overlays
}; };
} }
private ScheduledDelegate notificationsEnabler;
private void updateProcessingMode()
{
bool enabled = OverlayActivationMode == OverlayActivation.All || State == Visibility.Visible;
notificationsEnabler?.Cancel();
if (enabled)
// we want a slight delay before toggling notifications on to avoid the user becoming overwhelmed.
notificationsEnabler = Scheduler.AddDelayed(() => processingPosts = true, State == Visibility.Visible ? 0 : 1000);
else
processingPosts = false;
}
protected override void LoadComplete()
{
base.LoadComplete();
StateChanged += _ => updateProcessingMode();
OverlayActivationMode.ValueChanged += _ => updateProcessingMode();
OverlayActivationMode.TriggerChange();
}
private int totalCount => sections.Select(c => c.DisplayedCount).Sum(); private int totalCount => sections.Select(c => c.DisplayedCount).Sum();
private int unreadCount => sections.Select(c => c.UnreadCount).Sum(); private int unreadCount => sections.Select(c => c.UnreadCount).Sum();

View File

@ -0,0 +1,12 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Overlays
{
public enum OverlayActivation
{
Disabled,
UserTriggered,
All
}
}

View File

@ -0,0 +1,26 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Game.Configuration;
namespace osu.Game.Overlays.Settings.Sections.Gameplay
{
public class ModsSettings : SettingsSubsection
{
protected override string Header => "Mods";
[BackgroundDependencyLoader]
private void load(OsuConfigManager config)
{
Children = new[]
{
new SettingsCheckbox
{
LabelText = "Increase visibility of first object with \"Hidden\" mod",
Bindable = config.GetBindable<bool>(OsuSetting.IncreaseFirstObjectVisibility)
},
};
}
}
}

View File

@ -21,7 +21,8 @@ namespace osu.Game.Overlays.Settings.Sections
{ {
new GeneralSettings(), new GeneralSettings(),
new SongSelectSettings(), new SongSelectSettings(),
new ScrollingSettings() new ScrollingSettings(),
new ModsSettings(),
}; };
} }

View File

@ -10,6 +10,8 @@ using osu.Framework.Input;
using osu.Game.Graphics; using osu.Game.Graphics;
using OpenTK; using OpenTK;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
namespace osu.Game.Overlays.Toolbar namespace osu.Game.Overlays.Toolbar
{ {
@ -29,6 +31,8 @@ namespace osu.Game.Overlays.Toolbar
private const float alpha_hovering = 0.8f; private const float alpha_hovering = 0.8f;
private const float alpha_normal = 0.6f; private const float alpha_normal = 0.6f;
private readonly Bindable<OverlayActivation> overlayActivationMode = new Bindable<OverlayActivation>(OverlayActivation.All);
public Toolbar() public Toolbar()
{ {
Children = new Drawable[] Children = new Drawable[]
@ -76,6 +80,19 @@ namespace osu.Game.Overlays.Toolbar
Size = new Vector2(1, HEIGHT); Size = new Vector2(1, HEIGHT);
} }
[BackgroundDependencyLoader(true)]
private void load(OsuGame osuGame)
{
if (osuGame != null)
overlayActivationMode.BindTo(osuGame.OverlayActivationMode);
StateChanged += visibility =>
{
if (overlayActivationMode == OverlayActivation.Disabled)
State = Visibility.Hidden;
};
}
public class ToolbarBackground : Container public class ToolbarBackground : Container
{ {
private readonly Box solidBackground; private readonly Box solidBackground;

View File

@ -0,0 +1,15 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Configuration;
namespace osu.Game.Rulesets.Mods
{
/// <summary>
/// An interface for mods that require reading access to the osu! configuration.
/// </summary>
public interface IReadFromConfig
{
void ReadFromConfig(OsuConfigManager config);
}
}

View File

@ -1,16 +1,37 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Configuration;
using osu.Game.Configuration;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Rulesets.Objects.Drawables;
using System.Collections.Generic;
using System.Linq;
namespace osu.Game.Rulesets.Mods namespace osu.Game.Rulesets.Mods
{ {
public abstract class ModHidden : Mod public abstract class ModHidden : Mod, IReadFromConfig, IApplicableToDrawableHitObjects
{ {
public override string Name => "Hidden"; public override string Name => "Hidden";
public override string ShortenedName => "HD"; public override string ShortenedName => "HD";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_hidden; public override FontAwesome Icon => FontAwesome.fa_osu_mod_hidden;
public override ModType Type => ModType.DifficultyIncrease; public override ModType Type => ModType.DifficultyIncrease;
public override bool Ranked => true; public override bool Ranked => true;
protected Bindable<bool> IncreaseFirstObjectVisibility = new Bindable<bool>();
public void ReadFromConfig(OsuConfigManager config)
{
IncreaseFirstObjectVisibility = config.GetBindable<bool>(OsuSetting.IncreaseFirstObjectVisibility);
}
public virtual void ApplyToDrawableHitObjects(IEnumerable<DrawableHitObject> drawables)
{
// todo: fix ordering of objects so we don't have to do this (#2740).
foreach (var d in drawables.Reverse().Skip(IncreaseFirstObjectVisibility ? 1 : 0))
d.ApplyCustomUpdateState += ApplyHiddenState;
}
protected virtual void ApplyHiddenState(DrawableHitObject hitObject, ArmedState state) { }
} }
} }

View File

@ -57,6 +57,7 @@ namespace osu.Game.Rulesets.UI
public abstract IEnumerable<HitObject> Objects { get; } public abstract IEnumerable<HitObject> Objects { get; }
private readonly Lazy<Playfield> playfield; private readonly Lazy<Playfield> playfield;
/// <summary> /// <summary>
/// The playfield. /// The playfield.
/// </summary> /// </summary>
@ -130,7 +131,6 @@ namespace osu.Game.Rulesets.UI
HasReplayLoaded.Value = ReplayInputManager.ReplayInputHandler != null; HasReplayLoaded.Value = ReplayInputManager.ReplayInputHandler != null;
} }
/// <summary> /// <summary>
/// Creates the cursor. May be null if the <see cref="RulesetContainer"/> doesn't provide a custom cursor. /// Creates the cursor. May be null if the <see cref="RulesetContainer"/> doesn't provide a custom cursor.
/// </summary> /// </summary>
@ -194,6 +194,7 @@ namespace osu.Game.Rulesets.UI
protected override Container<Drawable> Content => content; protected override Container<Drawable> Content => content;
private Container content; private Container content;
private IEnumerable<Mod> mods;
/// <summary> /// <summary>
/// Whether to assume the beatmap passed into this <see cref="RulesetContainer{TObject}"/> is for the current ruleset. /// Whether to assume the beatmap passed into this <see cref="RulesetContainer{TObject}"/> is for the current ruleset.
@ -216,13 +217,10 @@ namespace osu.Game.Rulesets.UI
KeyBindingInputManager = CreateInputManager(); KeyBindingInputManager = CreateInputManager();
KeyBindingInputManager.RelativeSizeAxes = Axes.Both; KeyBindingInputManager.RelativeSizeAxes = Axes.Both;
// Add mods, should always be the last thing applied to give full control to mods
applyMods(Mods);
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load(OsuConfigManager config)
{ {
KeyBindingInputManager.Add(content = new Container KeyBindingInputManager.Add(content = new Container
{ {
@ -235,6 +233,9 @@ namespace osu.Game.Rulesets.UI
if (Cursor != null) if (Cursor != null)
KeyBindingInputManager.Add(Cursor); KeyBindingInputManager.Add(Cursor);
// Apply mods
applyMods(Mods, config);
loadObjects(); loadObjects();
} }
@ -242,13 +243,16 @@ namespace osu.Game.Rulesets.UI
/// Applies the active mods to this RulesetContainer. /// Applies the active mods to this RulesetContainer.
/// </summary> /// </summary>
/// <param name="mods"></param> /// <param name="mods"></param>
private void applyMods(IEnumerable<Mod> mods) private void applyMods(IEnumerable<Mod> mods, OsuConfigManager config)
{ {
if (mods == null) if (mods == null)
return; return;
foreach (var mod in mods.OfType<IApplicableToRulesetContainer<TObject>>()) foreach (var mod in mods.OfType<IApplicableToRulesetContainer<TObject>>())
mod.ApplyToRulesetContainer(this); mod.ApplyToRulesetContainer(this);
foreach (var mod in mods.OfType<IReadFromConfig>())
mod.ReadFromConfig(config);
} }
public override void SetReplay(Replay replay) public override void SetReplay(Replay replay)

View File

@ -121,8 +121,6 @@ namespace osu.Game.Rulesets.UI
/// </summary> /// </summary>
private bool validState; private bool validState;
protected override bool RequiresChildrenUpdate => base.RequiresChildrenUpdate && validState;
private bool isAttached => replayInputHandler != null && !UseParentState; private bool isAttached => replayInputHandler != null && !UseParentState;
private const int max_catch_up_updates_per_frame = 50; private const int max_catch_up_updates_per_frame = 50;

View File

@ -1,7 +1,6 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
@ -30,43 +29,48 @@ namespace osu.Game.Screens
{ {
base.LogoArriving(logo, resuming); base.LogoArriving(logo, resuming);
logo.BeatMatching = false;
logo.Triangles = false; logo.Triangles = false;
logo.Origin = Anchor.BottomRight; logo.Origin = Anchor.BottomRight;
logo.Anchor = Anchor.BottomRight; logo.Anchor = Anchor.BottomRight;
logo.Position = new Vector2(-40); logo.Position = new Vector2(-40);
logo.Scale = new Vector2(0.2f); logo.Scale = new Vector2(0.2f);
logo.FadeInFromZero(5000, Easing.OutQuint); logo.Delay(500).FadeInFromZero(1000, Easing.OutQuint);
}
private OsuScreen loadScreen;
private ShaderPrecompiler precompiler;
protected override void OnEntering(Screen last)
{
base.OnEntering(last);
LoadComponentAsync(precompiler = new ShaderPrecompiler(loadIfReady), Add);
LoadComponentAsync(loadScreen = showDisclaimer ? (OsuScreen)new Disclaimer() : new Intro(), s => loadIfReady());
}
private void loadIfReady()
{
if (ChildScreen == loadScreen) return;
if (loadScreen.LoadState != LoadState.Ready)
return;
if (!precompiler.FinishedCompiling)
return;
Push(loadScreen);
} }
protected override void LogoSuspending(OsuLogo logo) protected override void LogoSuspending(OsuLogo logo)
{ {
base.LogoSuspending(logo); base.LogoSuspending(logo);
logo.FadeOut(100); logo.FadeOut(logo.Alpha * 400);
}
private OsuScreen loadableScreen;
private ShaderPrecompiler precompiler;
protected virtual OsuScreen CreateLoadableScreen() => showDisclaimer ? (OsuScreen)new Disclaimer() : new Intro();
protected virtual ShaderPrecompiler CreateShaderPrecompiler() => new ShaderPrecompiler();
protected override void OnEntering(Screen last)
{
base.OnEntering(last);
LoadComponentAsync(precompiler = CreateShaderPrecompiler(), Add);
LoadComponentAsync(loadableScreen = CreateLoadableScreen());
checkIfLoaded();
}
private void checkIfLoaded()
{
if (loadableScreen.LoadState != LoadState.Ready || !precompiler.FinishedCompiling)
{
Schedule(checkIfLoaded);
return;
}
Push(loadableScreen);
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
@ -80,16 +84,10 @@ namespace osu.Game.Screens
/// </summary> /// </summary>
public class ShaderPrecompiler : Drawable public class ShaderPrecompiler : Drawable
{ {
private readonly Action onLoaded;
private readonly List<Shader> loadTargets = new List<Shader>(); private readonly List<Shader> loadTargets = new List<Shader>();
public bool FinishedCompiling { get; private set; } public bool FinishedCompiling { get; private set; }
public ShaderPrecompiler(Action onLoaded)
{
this.onLoaded = onLoaded;
}
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(ShaderManager manager) private void load(ShaderManager manager)
{ {
@ -103,16 +101,17 @@ namespace osu.Game.Screens
loadTargets.Add(manager.Load(VertexShaderDescriptor.TEXTURE_3, FragmentShaderDescriptor.TEXTURE)); loadTargets.Add(manager.Load(VertexShaderDescriptor.TEXTURE_3, FragmentShaderDescriptor.TEXTURE));
} }
protected virtual bool AllLoaded => loadTargets.All(s => s.Loaded);
protected override void Update() protected override void Update()
{ {
base.Update(); base.Update();
// if our target is null we are done. // if our target is null we are done.
if (loadTargets.All(s => s.Loaded)) if (AllLoaded)
{ {
FinishedCompiling = true; FinishedCompiling = true;
Expire(); Expire();
onLoaded?.Invoke();
} }
} }
} }

View File

@ -8,7 +8,6 @@ using osu.Framework;
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.Configuration;
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;
@ -17,6 +16,7 @@ using osu.Framework.Input.Bindings;
using osu.Framework.Threading; using osu.Framework.Threading;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Input.Bindings; using osu.Game.Input.Bindings;
using osu.Game.Overlays;
using OpenTK; using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
using OpenTK.Input; using OpenTK.Input;
@ -27,9 +27,6 @@ namespace osu.Game.Screens.Menu
{ {
public event Action<MenuState> StateChanged; public event Action<MenuState> StateChanged;
private readonly BindableBool hideOverlaysOnEnter = new BindableBool();
private readonly BindableBool allowOpeningOverlays = new BindableBool();
public Action OnEdit; public Action OnEdit;
public Action OnExit; public Action OnExit;
public Action OnDirect; public Action OnDirect;
@ -133,15 +130,12 @@ namespace osu.Game.Screens.Menu
buttonFlow.AddRange(buttonsTopLevel); buttonFlow.AddRange(buttonsTopLevel);
} }
private OsuGame game;
[BackgroundDependencyLoader(true)] [BackgroundDependencyLoader(true)]
private void load(AudioManager audio, OsuGame game) private void load(AudioManager audio, OsuGame game)
{ {
if (game != null) this.game = game;
{
hideOverlaysOnEnter.BindTo(game.HideOverlaysOnEnter);
allowOpeningOverlays.BindTo(game.AllowOpeningOverlays);
}
sampleBack = audio.Sample.Get(@"Menu/button-back-select"); sampleBack = audio.Sample.Get(@"Menu/button-back-select");
} }
@ -328,18 +322,18 @@ namespace osu.Game.Screens.Menu
case MenuState.Initial: case MenuState.Initial:
logoDelayedAction?.Cancel(); logoDelayedAction?.Cancel();
logoDelayedAction = Scheduler.AddDelayed(() => logoDelayedAction = Scheduler.AddDelayed(() =>
{ {
logoTracking = false; logoTracking = false;
hideOverlaysOnEnter.Value = true; if (game != null)
allowOpeningOverlays.Value = false; game.OverlayActivationMode.Value = state == MenuState.Exit ? OverlayActivation.Disabled : OverlayActivation.UserTriggered;
logo.ClearTransforms(targetMember: nameof(Position)); logo.ClearTransforms(targetMember: nameof(Position));
logo.RelativePositionAxes = Axes.Both; logo.RelativePositionAxes = Axes.Both;
logo.MoveTo(new Vector2(0.5f), 800, Easing.OutExpo); logo.MoveTo(new Vector2(0.5f), 800, Easing.OutExpo);
logo.ScaleTo(1, 800, Easing.OutExpo); logo.ScaleTo(1, 800, Easing.OutExpo);
}, buttonArea.Alpha * 150); }, buttonArea.Alpha * 150);
break; break;
case MenuState.TopLevel: case MenuState.TopLevel:
case MenuState.Play: case MenuState.Play:
@ -366,8 +360,11 @@ namespace osu.Game.Screens.Menu
if (impact) if (impact)
logo.Impact(); logo.Impact();
hideOverlaysOnEnter.Value = false; if (game != null)
allowOpeningOverlays.Value = true; {
game.OverlayActivationMode.Value = OverlayActivation.All;
game.Toolbar.State = Visibility.Visible;
}
}, 200); }, 200);
break; break;
default: default:

View File

@ -9,6 +9,7 @@ using osu.Game.Graphics;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using OpenTK; using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
using osu.Game.Overlays;
namespace osu.Game.Screens.Menu namespace osu.Game.Screens.Menu
{ {
@ -19,7 +20,7 @@ namespace osu.Game.Screens.Menu
private Color4 iconColour; private Color4 iconColour;
protected override bool HideOverlaysOnEnter => true; protected override bool HideOverlaysOnEnter => true;
protected override bool AllowOpeningOverlays => false; protected override OverlayActivation InitialOverlayActivationMode => OverlayActivation.Disabled;
public override bool CursorVisible => false; public override bool CursorVisible => false;

View File

@ -15,6 +15,7 @@ using osu.Game.IO.Archives;
using osu.Game.Screens.Backgrounds; using osu.Game.Screens.Backgrounds;
using OpenTK; using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
using osu.Game.Overlays;
namespace osu.Game.Screens.Menu namespace osu.Game.Screens.Menu
{ {
@ -32,7 +33,7 @@ namespace osu.Game.Screens.Menu
private SampleChannel seeya; private SampleChannel seeya;
protected override bool HideOverlaysOnEnter => true; protected override bool HideOverlaysOnEnter => true;
protected override bool AllowOpeningOverlays => false; protected override OverlayActivation InitialOverlayActivationMode => OverlayActivation.Disabled;
public override bool CursorVisible => false; public override bool CursorVisible => false;
@ -79,31 +80,6 @@ namespace osu.Game.Screens.Menu
seeya = audio.Sample.Get(@"seeya"); seeya = audio.Sample.Get(@"seeya");
} }
protected override void OnEntering(Screen last)
{
base.OnEntering(last);
Game.Beatmap.Value = beatmap;
if (menuVoice)
welcome.Play();
Scheduler.AddDelayed(delegate
{
// Only start the current track if it is the menu music. A beatmap's track is started when entering the Main Manu.
if (menuMusic)
track.Start();
LoadComponentAsync(mainMenu = new MainMenu());
Scheduler.AddDelayed(delegate
{
DidLoadMenu = true;
Push(mainMenu);
}, delay_step_one);
}, delay_step_two);
}
private const double delay_step_one = 2300; private const double delay_step_one = 2300;
private const double delay_step_two = 600; private const double delay_step_two = 600;
@ -113,6 +89,29 @@ namespace osu.Game.Screens.Menu
{ {
base.LogoArriving(logo, resuming); base.LogoArriving(logo, resuming);
if (!resuming)
{
Game.Beatmap.Value = beatmap;
if (menuVoice)
welcome.Play();
Scheduler.AddDelayed(delegate
{
// Only start the current track if it is the menu music. A beatmap's track is started when entering the Main Manu.
if (menuMusic)
track.Start();
LoadComponentAsync(mainMenu = new MainMenu());
Scheduler.AddDelayed(delegate
{
DidLoadMenu = true;
Push(mainMenu);
}, delay_step_one);
}, delay_step_two);
}
logo.RelativePositionAxes = Axes.Both; logo.RelativePositionAxes = Axes.Both;
logo.Colour = Color4.White; logo.Colour = Color4.White;
logo.Ripple = false; logo.Ripple = false;

View File

@ -25,7 +25,6 @@ namespace osu.Game.Screens.Menu
private readonly ButtonSystem buttons; private readonly ButtonSystem buttons;
protected override bool HideOverlaysOnEnter => buttons.State == MenuState.Initial; protected override bool HideOverlaysOnEnter => buttons.State == MenuState.Initial;
protected override bool AllowOpeningOverlays => buttons.State != MenuState.Initial;
protected override bool AllowBackButton => buttons.State != MenuState.Initial; protected override bool AllowBackButton => buttons.State != MenuState.Initial;

View File

@ -24,8 +24,8 @@ namespace osu.Game.Screens.Menu
private readonly Bindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>(); private readonly Bindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
private readonly Box leftBox; private Box leftBox;
private readonly Box rightBox; private Box rightBox;
private const float amplitude_dead_zone = 0.25f; private const float amplitude_dead_zone = 0.25f;
private const float alpha_multiplier = (1 - amplitude_dead_zone) / 0.55f; private const float alpha_multiplier = (1 - amplitude_dead_zone) / 0.55f;
@ -42,27 +42,6 @@ namespace osu.Game.Screens.Menu
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.Both;
Anchor = Anchor.Centre; Anchor = Anchor.Centre;
Origin = Anchor.Centre; Origin = Anchor.Centre;
Children = new Drawable[]
{
leftBox = new Box
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
RelativeSizeAxes = Axes.Y,
Width = box_width,
Alpha = 0,
Blending = BlendingMode.Additive,
},
rightBox = new Box
{
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
RelativeSizeAxes = Axes.Y,
Width = box_width,
Alpha = 0,
Blending = BlendingMode.Additive,
}
};
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
@ -72,10 +51,34 @@ namespace osu.Game.Screens.Menu
// linear colour looks better in this case, so let's use it for now. // linear colour looks better in this case, so let's use it for now.
Color4 gradientDark = colours.Blue.Opacity(0).ToLinear(); Color4 gradientDark = colours.Blue.Opacity(0).ToLinear();
Color4 gradientLight = colours.Blue.Opacity(0.3f).ToLinear(); Color4 gradientLight = colours.Blue.Opacity(0.6f).ToLinear();
leftBox.Colour = ColourInfo.GradientHorizontal(gradientLight, gradientDark); Children = new Drawable[]
rightBox.Colour = ColourInfo.GradientHorizontal(gradientDark, gradientLight); {
leftBox = new Box
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
RelativeSizeAxes = Axes.Y,
Width = box_width * 2,
// align off-screen to make sure our edges don't become visible during parallax.
X = -box_width,
Alpha = 0,
Blending = BlendingMode.Additive,
Colour = ColourInfo.GradientHorizontal(gradientLight, gradientDark)
},
rightBox = new Box
{
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
RelativeSizeAxes = Axes.Y,
Width = box_width * 2,
X = box_width,
Alpha = 0,
Blending = BlendingMode.Additive,
Colour = ColourInfo.GradientHorizontal(gradientDark, gradientLight)
}
};
} }
protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes) protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes)

View File

@ -64,6 +64,8 @@ namespace osu.Game.Screens.Menu
set { colourAndTriangles.FadeTo(value ? 1 : 0, transition_length, Easing.OutQuint); } set { colourAndTriangles.FadeTo(value ? 1 : 0, transition_length, Easing.OutQuint); }
} }
public bool BeatMatching = true;
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => logoContainer.ReceiveMouseInputAt(screenSpacePos); public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => logoContainer.ReceiveMouseInputAt(screenSpacePos);
public bool Ripple public bool Ripple
@ -264,6 +266,8 @@ namespace osu.Game.Screens.Menu
{ {
base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes); base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes);
if (!BeatMatching) return;
lastBeatIndex = beatIndex; lastBeatIndex = beatIndex;
var beatLength = timingPoint.BeatLength; var beatLength = timingPoint.BeatLength;

View File

@ -18,6 +18,8 @@ using osu.Game.Rulesets;
using osu.Game.Screens.Menu; using osu.Game.Screens.Menu;
using OpenTK; using OpenTK;
using OpenTK.Input; using OpenTK.Input;
using osu.Game.Overlays;
using osu.Framework.Graphics.Containers;
namespace osu.Game.Screens namespace osu.Game.Screens
{ {
@ -40,19 +42,19 @@ namespace osu.Game.Screens
/// </summary> /// </summary>
protected virtual BackgroundScreen CreateBackground() => null; protected virtual BackgroundScreen CreateBackground() => null;
private readonly BindableBool hideOverlaysOnEnter = new BindableBool(); private Action updateOverlayStates;
/// <summary> /// <summary>
/// Whether overlays should be hidden when this screen is entered or resumed. /// Whether all overlays should be hidden when this screen is entered or resumed.
/// </summary> /// </summary>
protected virtual bool HideOverlaysOnEnter => false; protected virtual bool HideOverlaysOnEnter => false;
private readonly BindableBool allowOpeningOverlays = new BindableBool(); protected readonly Bindable<OverlayActivation> OverlayActivationMode = new Bindable<OverlayActivation>();
/// <summary> /// <summary>
/// Whether overlays should be able to be opened while this screen is active. /// Whether overlays should be able to be opened once this screen is entered or resumed.
/// </summary> /// </summary>
protected virtual bool AllowOpeningOverlays => true; protected virtual OverlayActivation InitialOverlayActivationMode => OverlayActivation.All;
/// <summary> /// <summary>
/// Whether this <see cref="OsuScreen"/> allows the cursor to be displayed. /// Whether this <see cref="OsuScreen"/> allows the cursor to be displayed.
@ -103,8 +105,15 @@ namespace osu.Game.Screens
if (osuGame != null) if (osuGame != null)
{ {
Ruleset.BindTo(osuGame.Ruleset); Ruleset.BindTo(osuGame.Ruleset);
hideOverlaysOnEnter.BindTo(osuGame.HideOverlaysOnEnter); OverlayActivationMode.BindTo(osuGame.OverlayActivationMode);
allowOpeningOverlays.BindTo(osuGame.AllowOpeningOverlays);
updateOverlayStates = () =>
{
if (HideOverlaysOnEnter)
osuGame.CloseAllOverlays();
else
osuGame.Toolbar.State = Visibility.Visible;
};
} }
sampleExit = audio.Sample.Get(@"UI/screen-back"); sampleExit = audio.Sample.Get(@"UI/screen-back");
@ -225,6 +234,7 @@ namespace osu.Game.Screens
logo.Anchor = Anchor.TopLeft; logo.Anchor = Anchor.TopLeft;
logo.Origin = Anchor.Centre; logo.Origin = Anchor.Centre;
logo.RelativePositionAxes = Axes.None; logo.RelativePositionAxes = Axes.None;
logo.BeatMatching = true;
logo.Triangles = true; logo.Triangles = true;
logo.Ripple = true; logo.Ripple = true;
} }
@ -239,8 +249,9 @@ namespace osu.Game.Screens
if (backgroundParallaxContainer != null) if (backgroundParallaxContainer != null)
backgroundParallaxContainer.ParallaxAmount = ParallaxContainer.DEFAULT_PARALLAX_AMOUNT * BackgroundParallaxAmount; backgroundParallaxContainer.ParallaxAmount = ParallaxContainer.DEFAULT_PARALLAX_AMOUNT * BackgroundParallaxAmount;
hideOverlaysOnEnter.Value = HideOverlaysOnEnter; OverlayActivationMode.Value = InitialOverlayActivationMode;
allowOpeningOverlays.Value = AllowOpeningOverlays;
updateOverlayStates?.Invoke();
} }
private void onExitingLogo() private void onExitingLogo()

View File

@ -21,6 +21,7 @@ using osu.Game.Configuration;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Cursor; using osu.Game.Graphics.Cursor;
using osu.Game.Online.API; using osu.Game.Online.API;
using osu.Game.Overlays;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
@ -37,6 +38,8 @@ namespace osu.Game.Screens.Play
protected override bool HideOverlaysOnEnter => true; protected override bool HideOverlaysOnEnter => true;
protected override OverlayActivation InitialOverlayActivationMode => OverlayActivation.UserTriggered;
public Action RestartRequested; public Action RestartRequested;
public bool HasFailed { get; private set; } public bool HasFailed { get; private set; }

View File

@ -6,7 +6,6 @@ using OpenTK.Graphics;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using System.Linq; using System.Linq;
@ -120,14 +119,8 @@ namespace osu.Game.Screens.Select
Margin = new MarginPadding { Top = spacing * 2 }, Margin = new MarginPadding { Top = spacing * 2 },
Children = new[] Children = new[]
{ {
description = new MetadataSection("Description") description = new MetadataSection("Description"),
{ source = new MetadataSection("Source"),
TextColour = Color4.White.Opacity(0.75f),
},
source = new MetadataSection("Source")
{
TextColour = Color4.White.Opacity(0.75f),
},
tags = new MetadataSection("Tags"), tags = new MetadataSection("Tags"),
}, },
}, },
@ -164,10 +157,9 @@ namespace osu.Game.Screens.Select
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuColour colours, APIAccess api) private void load(APIAccess api)
{ {
this.api = api; this.api = api;
tags.TextColour = colours.Yellow;
} }
protected override void UpdateAfterChildren() protected override void UpdateAfterChildren()
@ -364,7 +356,7 @@ namespace osu.Game.Screens.Select
{ {
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y, AutoSizeAxes = Axes.Y,
Colour = textFlow.Colour, Colour = Color4.White.Opacity(0.75f),
Text = text Text = text
}, loaded => }, loaded =>
{ {
@ -375,12 +367,6 @@ namespace osu.Game.Screens.Select
this.FadeIn(transition_duration); this.FadeIn(transition_duration);
}); });
} }
public Color4 TextColour
{
get { return textFlow.Colour; }
set { textFlow.Colour = value; }
}
} }
private class DimmedLoadingAnimation : VisibilityContainer private class DimmedLoadingAnimation : VisibilityContainer

View File

@ -57,7 +57,7 @@ namespace osu.Game.Screens.Select
{ {
if (osuGame != null) if (osuGame != null)
ruleset.BindTo(osuGame.Ruleset); ruleset.BindTo(osuGame.Ruleset);
ruleset.ValueChanged += updateRuleset; ruleset.ValueChanged += _ => updateDisplay();
} }
protected override bool BlockPassThroughMouse => false; protected override bool BlockPassThroughMouse => false;
@ -78,66 +78,76 @@ namespace osu.Game.Screens.Select
private WorkingBeatmap beatmap; private WorkingBeatmap beatmap;
public void UpdateBeatmap(WorkingBeatmap beatmap) public WorkingBeatmap Beatmap
{ {
this.beatmap = beatmap; get => beatmap;
loadBeatmap(); set
{
if (beatmap == value) return;
beatmap = value;
updateDisplay();
}
} }
private void updateRuleset(RulesetInfo ruleset) => loadBeatmap(); private BufferedWedgeInfo loadingInfo;
private void loadBeatmap() private void updateDisplay()
{ {
void updateState() void removeOldInfo()
{ {
State = beatmap == null ? Visibility.Hidden : Visibility.Visible; State = beatmap == null ? Visibility.Hidden : Visibility.Visible;
Info?.FadeOut(250); Info?.FadeOut(250);
Info?.Expire(); Info?.Expire();
Info = null;
} }
if (beatmap == null) if (beatmap == null)
{ {
updateState(); removeOldInfo();
return; return;
} }
LoadComponentAsync(new BufferedWedgeInfo(beatmap, ruleset.Value) LoadComponentAsync(loadingInfo = new BufferedWedgeInfo(beatmap, ruleset.Value)
{ {
Shear = -Shear, Shear = -Shear,
Depth = Info?.Depth + 1 ?? 0, Depth = Info?.Depth + 1 ?? 0
}, newInfo => }, loaded =>
{ {
updateState(); // ensure we are the most recent loaded wedge.
Add(Info = newInfo); if (loaded != loadingInfo) return;
removeOldInfo();
Add(Info = loaded);
}); });
} }
public class BufferedWedgeInfo : BufferedContainer public class BufferedWedgeInfo : BufferedContainer
{ {
private readonly WorkingBeatmap working;
public OsuSpriteText VersionLabel { get; private set; } public OsuSpriteText VersionLabel { get; private set; }
public OsuSpriteText TitleLabel { get; private set; } public OsuSpriteText TitleLabel { get; private set; }
public OsuSpriteText ArtistLabel { get; private set; } public OsuSpriteText ArtistLabel { get; private set; }
public FillFlowContainer MapperContainer { get; private set; } public FillFlowContainer MapperContainer { get; private set; }
public FillFlowContainer InfoLabelContainer { get; private set; } public FillFlowContainer InfoLabelContainer { get; private set; }
private UnicodeBindableString titleBinding; private UnicodeBindableString titleBinding;
private UnicodeBindableString artistBinding; private UnicodeBindableString artistBinding;
private readonly WorkingBeatmap beatmap;
private readonly RulesetInfo ruleset; private readonly RulesetInfo ruleset;
public BufferedWedgeInfo(WorkingBeatmap working, RulesetInfo userRuleset) public BufferedWedgeInfo(WorkingBeatmap beatmap, RulesetInfo userRuleset)
{ {
this.working = working; this.beatmap = beatmap;
ruleset = userRuleset ?? beatmap.BeatmapInfo.Ruleset;
ruleset = userRuleset ?? working.BeatmapInfo.Ruleset;
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(LocalisationEngine localisation) private void load(LocalisationEngine localisation)
{ {
var beatmapInfo = working.BeatmapInfo; var beatmapInfo = beatmap.BeatmapInfo;
var metadata = beatmapInfo.Metadata ?? working.BeatmapSetInfo?.Metadata ?? new BeatmapMetadata(); var metadata = beatmapInfo.Metadata ?? beatmap.BeatmapSetInfo?.Metadata ?? new BeatmapMetadata();
PixelSnapping = true; PixelSnapping = true;
CacheDrawnFrameBuffer = true; CacheDrawnFrameBuffer = true;
@ -165,7 +175,7 @@ namespace osu.Game.Screens.Select
Children = new[] Children = new[]
{ {
// Zoomed-in and cropped beatmap background // Zoomed-in and cropped beatmap background
new BeatmapBackgroundSprite(working) new BeatmapBackgroundSprite(beatmap)
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
@ -248,27 +258,27 @@ namespace osu.Game.Screens.Select
private InfoLabel[] getInfoLabels() private InfoLabel[] getInfoLabels()
{ {
var beatmap = working.Beatmap; var b = beatmap.Beatmap;
List<InfoLabel> labels = new List<InfoLabel>(); List<InfoLabel> labels = new List<InfoLabel>();
if (beatmap?.HitObjects?.Any() == true) if (b?.HitObjects?.Any() == true)
{ {
HitObject lastObject = beatmap.HitObjects.LastOrDefault(); HitObject lastObject = b.HitObjects.LastOrDefault();
double endTime = (lastObject as IHasEndTime)?.EndTime ?? lastObject?.StartTime ?? 0; double endTime = (lastObject as IHasEndTime)?.EndTime ?? lastObject?.StartTime ?? 0;
labels.Add(new InfoLabel(new BeatmapStatistic labels.Add(new InfoLabel(new BeatmapStatistic
{ {
Name = "Length", Name = "Length",
Icon = FontAwesome.fa_clock_o, Icon = FontAwesome.fa_clock_o,
Content = TimeSpan.FromMilliseconds(endTime - beatmap.HitObjects.First().StartTime).ToString(@"m\:ss"), Content = TimeSpan.FromMilliseconds(endTime - b.HitObjects.First().StartTime).ToString(@"m\:ss"),
})); }));
labels.Add(new InfoLabel(new BeatmapStatistic labels.Add(new InfoLabel(new BeatmapStatistic
{ {
Name = "BPM", Name = "BPM",
Icon = FontAwesome.fa_circle, Icon = FontAwesome.fa_circle,
Content = getBPMRange(beatmap), Content = getBPMRange(b),
})); }));
IBeatmap playableBeatmap; IBeatmap playableBeatmap;
@ -276,12 +286,12 @@ namespace osu.Game.Screens.Select
try try
{ {
// Try to get the beatmap with the user's ruleset // Try to get the beatmap with the user's ruleset
playableBeatmap = working.GetPlayableBeatmap(ruleset); playableBeatmap = beatmap.GetPlayableBeatmap(ruleset);
} }
catch (BeatmapInvalidForRulesetException) catch (BeatmapInvalidForRulesetException)
{ {
// Can't be converted to the user's ruleset, so use the beatmap's own ruleset // Can't be converted to the user's ruleset, so use the beatmap's own ruleset
playableBeatmap = working.GetPlayableBeatmap(working.BeatmapInfo.Ruleset); playableBeatmap = beatmap.GetPlayableBeatmap(beatmap.BeatmapInfo.Ruleset);
} }
labels.AddRange(playableBeatmap.GetStatistics().Select(s => new InfoLabel(s))); labels.AddRange(playableBeatmap.GetStatistics().Select(s => new InfoLabel(s)));

View File

@ -8,6 +8,7 @@ using osu.Framework.Allocation;
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.Cursor;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Input; using osu.Framework.Input;
using osu.Game.Graphics; using osu.Game.Graphics;
@ -142,6 +143,8 @@ namespace osu.Game.Screens.Select.Leaderboards
{ {
flagBadgeContainer = new Container flagBadgeContainer = new Container
{ {
Origin = Anchor.BottomLeft,
Anchor = Anchor.BottomLeft,
Size = new Vector2(87f, 20f), Size = new Vector2(87f, 20f),
Masking = true, Masking = true,
Children = new Drawable[] Children = new Drawable[]
@ -155,14 +158,16 @@ namespace osu.Game.Screens.Select.Leaderboards
}, },
new FillFlowContainer new FillFlowContainer
{ {
Origin = Anchor.BottomLeft,
Anchor = Anchor.BottomLeft,
AutoSizeAxes = Axes.Both, AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal, Direction = FillDirection.Horizontal,
Spacing = new Vector2(10f, 0f), Spacing = new Vector2(10f, 0f),
Margin = new MarginPadding { Left = edge_margin, }, Margin = new MarginPadding { Left = edge_margin },
Children = new Drawable[] Children = new Drawable[]
{ {
maxCombo = new ScoreComponentLabel(FontAwesome.fa_link, Score.MaxCombo.ToString()), maxCombo = new ScoreComponentLabel(FontAwesome.fa_link, Score.MaxCombo.ToString(), "Max Combo"),
accuracy = new ScoreComponentLabel(FontAwesome.fa_crosshairs, string.Format(Score.Accuracy % 1 == 0 ? @"{0:P0}" : @"{0:P2}", Score.Accuracy)), accuracy = new ScoreComponentLabel(FontAwesome.fa_crosshairs, string.Format(Score.Accuracy % 1 == 0 ? @"{0:P0}" : @"{0:P2}", Score.Accuracy), "Accuracy"),
}, },
}, },
}, },
@ -305,37 +310,61 @@ namespace osu.Game.Screens.Select.Leaderboards
} }
} }
private class ScoreComponentLabel : Container private class ScoreComponentLabel : Container, IHasTooltip
{ {
public ScoreComponentLabel(FontAwesome icon, string value) private const float icon_size = 20;
{
Anchor = Anchor.CentreLeft;
Origin = Anchor.CentreLeft;
Size = new Vector2(60f, 20f);
Padding = new MarginPadding { Top = 10f, };
Children = new Drawable[] private readonly string name;
private readonly FillFlowContainer content;
public override bool Contains(Vector2 screenSpacePos) => content.Contains(screenSpacePos);
public string TooltipText => name;
public ScoreComponentLabel(FontAwesome icon, string value, string name)
{
this.name = name;
AutoSizeAxes = Axes.Y;
Width = 60;
Child = content = new FillFlowContainer
{ {
new SpriteIcon AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Children = new Drawable[]
{ {
Origin = Anchor.Centre, new Container
Icon = FontAwesome.fa_square, {
Colour = OsuColour.FromHex(@"3087ac"), Anchor = Anchor.CentreLeft,
Rotation = 45, Origin = Anchor.CentreLeft,
Size = new Vector2(20), AutoSizeAxes = Axes.Both,
Shadow = true, Children = new[]
}, {
new SpriteIcon new SpriteIcon
{ {
Origin = Anchor.Centre, Anchor = Anchor.Centre,
Icon = icon, Origin = Anchor.Centre,
Colour = OsuColour.FromHex(@"a4edff"), Size = new Vector2(icon_size),
Size = new Vector2(14), Rotation = 45,
}, Colour = OsuColour.FromHex(@"3087ac"),
new GlowingSpriteText(value, @"Exo2.0-Bold", 17, Color4.White, OsuColour.FromHex(@"83ccfa")) Icon = FontAwesome.fa_square,
{ Shadow = true,
Origin = Anchor.CentreLeft, },
Margin = new MarginPadding { Left = 15, }, new SpriteIcon
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(icon_size - 6),
Colour = OsuColour.FromHex(@"a4edff"),
Icon = icon,
},
},
},
new GlowingSpriteText(value, @"Exo2.0-Bold", 17, Color4.White, OsuColour.FromHex(@"83ccfa"))
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
},
}, },
}; };
} }

View File

@ -430,7 +430,7 @@ namespace osu.Game.Screens.Select
backgroundModeBeatmap.FadeTo(1, 250); backgroundModeBeatmap.FadeTo(1, 250);
} }
beatmapInfoWedge.UpdateBeatmap(beatmap); beatmapInfoWedge.Beatmap = beatmap;
} }
private void ensurePlayingSelected(bool preview = false) private void ensurePlayingSelected(bool preview = false)