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

Merge branch 'user-profile-fixes' of github.com:Jorolf/osu into user-profile-fixes

This commit is contained in:
Jorolf 2017-07-20 01:08:42 +02:00
commit bac8693c81
27 changed files with 298 additions and 200 deletions

@ -1 +1 @@
Subproject commit 2a3b245da9eff604be09d473203f829690d2808c Subproject commit 6b44a9f807fadcb3b3f044780d7e27d62ffe80ac

View File

@ -151,6 +151,8 @@ namespace osu.Desktop.VisualTests.Tests
private int calculateBeatCount(TimingControlPoint current) private int calculateBeatCount(TimingControlPoint current)
{ {
if (timingPoints.Count == 0) return 0;
if (timingPoints[timingPoints.Count - 1] == current) if (timingPoints[timingPoints.Count - 1] == current)
return (int)Math.Ceiling((Beatmap.Value.Track.Length - current.Time) / current.BeatLength); return (int)Math.Ceiling((Beatmap.Value.Track.Length - current.Time) / current.BeatLength);

View File

@ -81,7 +81,7 @@ namespace osu.Desktop.VisualTests.Tests
{ {
return new Player return new Player
{ {
Beatmap = beatmap InitialBeatmap = beatmap
}; };
} }
} }

View File

@ -59,7 +59,7 @@ namespace osu.Desktop.VisualTests.Tests
} }
}) })
{ {
Beatmap = beatmap InitialBeatmap = beatmap
}); });
} }
} }

View File

@ -113,7 +113,7 @@ namespace osu.Game.Rulesets.Mania.UI
{ {
base.ApplyBeatmap(); base.ApplyBeatmap();
PreferredColumns = (int)Math.Round(Beatmap.BeatmapInfo.Difficulty.CircleSize); PreferredColumns = (int)Math.Max(1, Math.Round(Beatmap.BeatmapInfo.Difficulty.CircleSize));
} }
protected override void ApplySpeedAdjustments() protected override void ApplySpeedAdjustments()

View File

@ -5,7 +5,7 @@ using System;
namespace osu.Game.Beatmaps.ControlPoints namespace osu.Game.Beatmaps.ControlPoints
{ {
public class ControlPoint : IComparable<ControlPoint> public class ControlPoint : IComparable<ControlPoint>, IEquatable<ControlPoint>
{ {
/// <summary> /// <summary>
/// The time at which the control point takes effect. /// The time at which the control point takes effect.
@ -13,5 +13,7 @@ namespace osu.Game.Beatmaps.ControlPoints
public double Time; public double Time;
public int CompareTo(ControlPoint other) => Time.CompareTo(other.Time); public int CompareTo(ControlPoint other) => Time.CompareTo(other.Time);
public bool Equals(ControlPoint other) => Time.Equals(other?.Time);
} }
} }

View File

@ -0,0 +1,82 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using osu.Framework.Audio.Track;
using osu.Framework.Graphics.Textures;
using osu.Game.Database;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
using osu.Game.Screens.Play;
namespace osu.Game.Beatmaps
{
internal class DummyWorkingBeatmap : WorkingBeatmap
{
private readonly OsuGameBase game;
public DummyWorkingBeatmap(OsuGameBase game)
: base(new BeatmapInfo
{
Metadata = new BeatmapMetadata
{
Artist = "please load a beatmap!",
Title = "no beatmaps available!",
Author = "no one",
},
BeatmapSet = new BeatmapSetInfo(),
Difficulty = new BeatmapDifficulty
{
DrainRate = 0,
CircleSize = 0,
OverallDifficulty = 0,
ApproachRate = 0,
SliderMultiplier = 0,
SliderTickRate = 0,
},
Ruleset = new DummyRulesetInfo()
})
{
this.game = game;
}
protected override Beatmap GetBeatmap() => new Beatmap
{
HitObjects = new List<HitObject>(),
};
protected override Texture GetBackground() => game.Textures.Get(@"Backgrounds/bg4");
protected override Track GetTrack() => new TrackVirtual();
private class DummyRulesetInfo : RulesetInfo
{
public override Ruleset CreateInstance() => new DummyRuleset();
private class DummyRuleset : Ruleset
{
public override IEnumerable<Mod> GetModsFor(ModType type) => new Mod[] { };
public override HitRenderer CreateHitRendererWith(WorkingBeatmap beatmap, bool isForCurrentRuleset)
{
throw new NotImplementedException();
}
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap) => null;
public override ScoreProcessor CreateScoreProcessor()
{
throw new NotImplementedException();
}
public override string Description => "dummy";
public override IEnumerable<KeyCounter> CreateGameplayKeys() => new List<KeyCounter>();
}
}
}
}

View File

@ -28,6 +28,11 @@ namespace osu.Game.Database
// ReSharper disable once NotAccessedField.Local (we should keep a reference to this so it is not finalised) // ReSharper disable once NotAccessedField.Local (we should keep a reference to this so it is not finalised)
private BeatmapIPCChannel ipc; private BeatmapIPCChannel ipc;
/// <summary>
/// A default representation of a WorkingBeatmap to use when no beatmap is available.
/// </summary>
public WorkingBeatmap DefaultBeatmap { private get; set; }
public BeatmapDatabase(Storage storage, SQLiteConnection connection, RulesetDatabase rulesets, IIpcHost importHost = null) : base(storage, connection) public BeatmapDatabase(Storage storage, SQLiteConnection connection, RulesetDatabase rulesets, IIpcHost importHost = null) : base(storage, connection)
{ {
this.rulesets = rulesets; this.rulesets = rulesets;
@ -274,6 +279,9 @@ namespace osu.Game.Database
public WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo, WorkingBeatmap previous = null, bool withStoryboard = false) public WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo, WorkingBeatmap previous = null, bool withStoryboard = false)
{ {
if (beatmapInfo == null || beatmapInfo == DefaultBeatmap?.BeatmapInfo)
return DefaultBeatmap;
if (beatmapInfo.BeatmapSet == null || beatmapInfo.Ruleset == null) if (beatmapInfo.BeatmapSet == null || beatmapInfo.Ruleset == null)
beatmapInfo = GetChildren(beatmapInfo, true); beatmapInfo = GetChildren(beatmapInfo, true);

View File

@ -21,6 +21,6 @@ namespace osu.Game.Database
[Indexed] [Indexed]
public bool Available { get; set; } public bool Available { get; set; }
public Ruleset CreateInstance() => (Ruleset)Activator.CreateInstance(Type.GetType(InstantiationInfo)); public virtual Ruleset CreateInstance() => (Ruleset)Activator.CreateInstance(Type.GetType(InstantiationInfo));
} }
} }

View File

@ -35,10 +35,12 @@ namespace osu.Game.Graphics.Containers
protected override void Update() protected override void Update()
{ {
if (Beatmap.Value?.Track == null) var track = Beatmap.Value.Track;
if (track == null)
return; return;
double currentTrackTime = Beatmap.Value.Track.CurrentTime + EarlyActivationMilliseconds; double currentTrackTime = track.Length > 0 ? track.CurrentTime + EarlyActivationMilliseconds : Clock.CurrentTime;
TimingControlPoint timingPoint = Beatmap.Value.Beatmap.ControlPointInfo.TimingPointAt(currentTrackTime); TimingControlPoint timingPoint = Beatmap.Value.Beatmap.ControlPointInfo.TimingPointAt(currentTrackTime);
EffectControlPoint effectPoint = Beatmap.Value.Beatmap.ControlPointInfo.EffectPointAt(currentTrackTime); EffectControlPoint effectPoint = Beatmap.Value.Beatmap.ControlPointInfo.EffectPointAt(currentTrackTime);
@ -58,7 +60,7 @@ namespace osu.Game.Graphics.Containers
TimeSinceLastBeat = timingPoint.BeatLength - TimeUntilNextBeat; TimeSinceLastBeat = timingPoint.BeatLength - TimeUntilNextBeat;
if (timingPoint == lastTimingPoint && beatIndex == lastBeat) if (timingPoint.Equals(lastTimingPoint) && beatIndex == lastBeat)
return; return;
using (BeginDelayedSequence(-TimeSinceLastBeat, true)) using (BeginDelayedSequence(-TimeSinceLastBeat, true))

View File

@ -43,7 +43,7 @@ namespace osu.Game
protected MenuCursor Cursor; protected MenuCursor Cursor;
public readonly Bindable<WorkingBeatmap> Beatmap = new Bindable<WorkingBeatmap>(); public Bindable<WorkingBeatmap> Beatmap { get; private set; }
private Bindable<bool> fpsDisplayVisible; private Bindable<bool> fpsDisplayVisible;
@ -121,6 +121,10 @@ namespace osu.Game
Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Venera")); Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Venera"));
Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Venera-Light")); Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Venera-Light"));
var defaultBeatmap = new DummyWorkingBeatmap(this);
Beatmap = new NonNullableBindable<WorkingBeatmap>(defaultBeatmap);
BeatmapDatabase.DefaultBeatmap = defaultBeatmap;
OszArchiveReader.Register(); OszArchiveReader.Register();
Dependencies.Cache(API = new APIAccess Dependencies.Cache(API = new APIAccess

View File

@ -83,11 +83,12 @@ namespace osu.Game.Overlays.Music
}, },
}; };
list.BeatmapSets = BeatmapSets = beatmaps.GetAllWithChildren<BeatmapSetInfo>().ToList(); list.BeatmapSets = BeatmapSets = beatmaps.GetAllWithChildren<BeatmapSetInfo>(b => !b.DeletePending).ToList();
beatmapBacking.BindTo(game.Beatmap); beatmapBacking.BindTo(game.Beatmap);
filter.Search.OnCommit = (sender, newText) => { filter.Search.OnCommit = (sender, newText) =>
{
var beatmap = list.FirstVisibleSet?.Beatmaps?.FirstOrDefault(); var beatmap = list.FirstVisibleSet?.Beatmaps?.FirstOrDefault();
if (beatmap != null) playSpecified(beatmap); if (beatmap != null) playSpecified(beatmap);
}; };

View File

@ -3,6 +3,7 @@
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Textures;
using OpenTK; using OpenTK;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Graphics.Backgrounds; using osu.Game.Graphics.Backgrounds;
@ -26,11 +27,12 @@ namespace osu.Game.Screens.Backgrounds
{ {
if (beatmap == value && beatmap != null) if (beatmap == value && beatmap != null)
return; return;
beatmap = value; beatmap = value;
Schedule(() => Schedule(() =>
{ {
var newBackground = beatmap == null ? new Background(@"Backgrounds/bg1") : new BeatmapBackground(beatmap); var newBackground = new BeatmapBackground(beatmap);
LoadComponentAsync(newBackground, delegate LoadComponentAsync(newBackground, delegate
{ {
@ -51,7 +53,7 @@ namespace osu.Game.Screens.Backgrounds
} }
} }
public BackgroundScreenBeatmap(WorkingBeatmap beatmap) public BackgroundScreenBeatmap(WorkingBeatmap beatmap = null)
{ {
Beatmap = beatmap; Beatmap = beatmap;
} }
@ -80,9 +82,9 @@ namespace osu.Game.Screens.Backgrounds
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load(TextureStore textures)
{ {
Sprite.Texture = beatmap?.Background; Sprite.Texture = beatmap?.Background ?? textures.Get(@"Backgrounds/bg1");
} }
} }
} }

View File

@ -18,7 +18,7 @@ namespace osu.Game.Screens.Edit
protected override void OnResuming(Screen last) protected override void OnResuming(Screen last)
{ {
Beatmap?.Track?.Stop(); Beatmap.Value.Track?.Stop();
base.OnResuming(last); base.OnResuming(last);
} }
@ -26,13 +26,13 @@ namespace osu.Game.Screens.Edit
{ {
base.OnEntering(last); base.OnEntering(last);
Background.FadeColour(Color4.DarkGray, 500); Background.FadeColour(Color4.DarkGray, 500);
Beatmap?.Track?.Stop(); Beatmap.Value.Track?.Stop();
} }
protected override bool OnExiting(Screen next) protected override bool OnExiting(Screen next)
{ {
Background.FadeColour(Color4.White, 500); Background.FadeColour(Color4.White, 500);
Beatmap?.Track?.Start(); Beatmap.Value.Track?.Start();
return base.OnExiting(next); return base.OnExiting(next);
} }
} }

View File

@ -103,9 +103,9 @@ namespace osu.Game.Screens.Menu
} }
beatmaps.GetChildren(setInfo); beatmaps.GetChildren(setInfo);
Beatmap = beatmaps.GetWorkingBeatmap(setInfo.Beatmaps[0]); Beatmap.Value = beatmaps.GetWorkingBeatmap(setInfo.Beatmaps[0]);
track = Beatmap.Track; track = Beatmap.Value.Track;
trackManager.SetExclusive(track); trackManager.SetExclusive(track);
welcome = audio.Sample.Get(@"welcome"); welcome = audio.Sample.Get(@"welcome");

View File

@ -4,7 +4,6 @@
using OpenTK; using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
using OpenTK.Graphics.ES30; using OpenTK.Graphics.ES30;
using osu.Framework.Allocation;
using osu.Framework.Configuration; using osu.Framework.Configuration;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Batches; using osu.Framework.Graphics.Batches;
@ -16,6 +15,7 @@ using osu.Framework.Graphics.Textures;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Graphics; using osu.Game.Graphics;
using System; using System;
using osu.Framework.Allocation;
namespace osu.Game.Screens.Menu namespace osu.Game.Screens.Menu
{ {
@ -76,23 +76,24 @@ namespace osu.Game.Screens.Menu
BlendingMode = BlendingMode.Additive; BlendingMode = BlendingMode.Additive;
} }
[BackgroundDependencyLoader(true)] [BackgroundDependencyLoader]
private void load(ShaderManager shaders, OsuGame game) private void load(ShaderManager shaders, OsuGameBase game)
{ {
if (game?.Beatmap != null)
beatmap.BindTo(game.Beatmap); beatmap.BindTo(game.Beatmap);
shader = shaders?.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE_ROUNDED); shader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE_ROUNDED);
} }
private void updateAmplitudes() private void updateAmplitudes()
{ {
float[] temporalAmplitudes = beatmap.Value?.Track?.CurrentAmplitudes.FrequencyAmplitudes ?? new float[256]; var track = beatmap.Value.Track;
var effect = beatmap.Value?.Beatmap.ControlPointInfo.EffectPointAt(beatmap.Value.Track?.CurrentTime ?? Time.Current); float[] temporalAmplitudes = track?.CurrentAmplitudes.FrequencyAmplitudes ?? new float[256];
var effect = beatmap.Value.Beatmap.ControlPointInfo.EffectPointAt(track?.CurrentTime ?? Time.Current);
for (int i = 0; i < bars_per_visualiser; i++) for (int i = 0; i < bars_per_visualiser; i++)
{ {
if (beatmap?.Value?.Track?.IsRunning ?? false) if (track?.IsRunning ?? false)
{ {
float targetAmplitude = temporalAmplitudes[(i + indexOffset) % bars_per_visualiser] * (effect?.KiaiMode == true ? 1 : 0.5f); float targetAmplitude = temporalAmplitudes[(i + indexOffset) % bars_per_visualiser] * (effect?.KiaiMode == true ? 1 : 0.5f);
if (targetAmplitude > frequencyAmplitudes[i]) if (targetAmplitude > frequencyAmplitudes[i])

View File

@ -69,12 +69,6 @@ namespace osu.Game.Screens.Menu
preloadSongSelect(); preloadSongSelect();
} }
protected override void OnBeatmapChanged(WorkingBeatmap beatmap)
{
base.OnBeatmapChanged(beatmap);
background.Next();
}
private void preloadSongSelect() private void preloadSongSelect()
{ {
if (songSelect == null) if (songSelect == null)
@ -92,16 +86,30 @@ namespace osu.Game.Screens.Menu
{ {
base.OnEntering(last); base.OnEntering(last);
buttons.FadeInFromZero(500); buttons.FadeInFromZero(500);
if (last is Intro && Beatmap != null)
var track = Beatmap.Value.Track;
var metadata = Beatmap.Value.Metadata;
if (last is Intro && track != null)
{ {
if (!Beatmap.Track.IsRunning) if (!track.IsRunning)
{ {
Beatmap.Track.Seek(Beatmap.Metadata.PreviewTime); track.Seek(metadata.PreviewTime);
if (Beatmap.Metadata.PreviewTime == -1) if (metadata.PreviewTime == -1)
Beatmap.Track.Seek(Beatmap.Track.Length * 0.4f); track.Seek(track.Length * 0.4f);
Beatmap.Track.Start(); track.Start();
} }
} }
Beatmap.ValueChanged += beatmap_ValueChanged;
}
private void beatmap_ValueChanged(WorkingBeatmap newValue)
{
if (!IsCurrentScreen)
return;
background.Next();
} }
protected override void OnSuspending(Screen next) protected override void OnSuspending(Screen next)

View File

@ -275,7 +275,7 @@ namespace osu.Game.Screens.Menu
const float scale_adjust_cutoff = 0.4f; const float scale_adjust_cutoff = 0.4f;
const float velocity_adjust_cutoff = 0.98f; const float velocity_adjust_cutoff = 0.98f;
var maxAmplitude = lastBeatIndex >= 0 ? Beatmap.Value?.Track?.CurrentAmplitudes.Maximum ?? 0 : 0; var maxAmplitude = lastBeatIndex >= 0 ? Beatmap.Value.Track?.CurrentAmplitudes.Maximum ?? 0 : 0;
logoAmplitudeContainer.ScaleTo(1 - Math.Max(0, maxAmplitude - scale_adjust_cutoff) * 0.04f, 75, EasingTypes.OutQuint); logoAmplitudeContainer.ScaleTo(1 - Math.Max(0, maxAmplitude - scale_adjust_cutoff) * 0.04f, 75, EasingTypes.OutQuint);
if (maxAmplitude > velocity_adjust_cutoff) if (maxAmplitude > velocity_adjust_cutoff)

View File

@ -1,6 +1,7 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 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 osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Configuration; using osu.Framework.Configuration;
using osu.Framework.Screens; using osu.Framework.Screens;
@ -35,34 +36,31 @@ namespace osu.Game.Screens
/// </summary> /// </summary>
internal virtual bool AllowBeatmapRulesetChange => true; internal virtual bool AllowBeatmapRulesetChange => true;
private readonly Bindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>(); protected readonly Bindable<WorkingBeatmap> Beatmap = new Bindable<WorkingBeatmap>();
public WorkingBeatmap InitialBeatmap
{
set
{
if (IsLoaded) throw new InvalidOperationException($"Cannot set {nameof(InitialBeatmap)} post-load.");
Beatmap.Value = value;
}
}
private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>(); private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>();
private SampleChannel sampleExit; private SampleChannel sampleExit;
public WorkingBeatmap Beatmap
{
get
{
return beatmap.Value;
}
set
{
beatmap.Value = value;
}
}
[BackgroundDependencyLoader(permitNulls: true)] [BackgroundDependencyLoader(permitNulls: true)]
private void load(OsuGameBase game, OsuGame osuGame, AudioManager audio) private void load(OsuGameBase game, OsuGame osuGame, AudioManager audio)
{ {
if (game != null) if (game != null)
{ {
//if we were given a beatmap at ctor time, we want to pass this on to the game-wide beatmap. //if we were given a beatmap at ctor time, we want to pass this on to the game-wide beatmap.
var localMap = beatmap.Value; var localMap = Beatmap.Value;
beatmap.BindTo(game.Beatmap); Beatmap.BindTo(game.Beatmap);
if (localMap != null) if (localMap != null)
beatmap.Value = localMap; Beatmap.Value = localMap;
} }
if (osuGame != null) if (osuGame != null)
@ -71,20 +69,6 @@ namespace osu.Game.Screens
sampleExit = audio.Sample.Get(@"UI/melodic-1"); sampleExit = audio.Sample.Get(@"UI/melodic-1");
} }
protected override void LoadComplete()
{
base.LoadComplete();
beatmap.ValueChanged += OnBeatmapChanged;
}
/// <summary>
/// The global Beatmap was changed.
/// </summary>
protected virtual void OnBeatmapChanged(WorkingBeatmap beatmap)
{
}
protected override void Update() protected override void Update()
{ {
if (!IsCurrentScreen) return; if (!IsCurrentScreen) return;
@ -94,7 +78,7 @@ namespace osu.Game.Screens
// we only want to apply these restrictions when we are inside a screen stack. // we only want to apply these restrictions when we are inside a screen stack.
// the use case for not applying is in visual/unit tests. // the use case for not applying is in visual/unit tests.
ruleset.Disabled = !AllowBeatmapRulesetChange; ruleset.Disabled = !AllowBeatmapRulesetChange;
beatmap.Disabled = !AllowBeatmapRulesetChange; Beatmap.Disabled = !AllowBeatmapRulesetChange;
} }
} }
@ -110,8 +94,6 @@ namespace osu.Game.Screens
BackgroundScreen bg = CreateBackground(); BackgroundScreen bg = CreateBackground();
OnBeatmapChanged(Beatmap);
if (lastOsu?.Background != null) if (lastOsu?.Background != null)
{ {
if (bg == null || lastOsu.Background.Equals(bg)) if (bg == null || lastOsu.Background.Equals(bg))
@ -156,11 +138,7 @@ namespace osu.Game.Screens
if (base.OnExiting(next)) if (base.OnExiting(next))
return true; return true;
// while this is not necessary as we are constructing our own bindable, there are cases where Beatmap.UnbindAll();
// the GC doesn't run as fast as expected and this is triggered post-exit.
// added to resolve https://github.com/ppy/osu/issues/829
beatmap.ValueChanged -= OnBeatmapChanged;
return false; return false;
} }
} }

View File

@ -69,6 +69,8 @@ namespace osu.Game.Screens.Play
private HUDOverlay hudOverlay; private HUDOverlay hudOverlay;
private FailOverlay failOverlay; private FailOverlay failOverlay;
private bool loadedSuccessfully => HitRenderer?.Objects.Any() == true;
[BackgroundDependencyLoader(permitNulls: true)] [BackgroundDependencyLoader(permitNulls: true)]
private void load(AudioManager audio, BeatmapDatabase beatmaps, OsuConfigManager config, OsuGame osu) private void load(AudioManager audio, BeatmapDatabase beatmaps, OsuConfigManager config, OsuGame osu)
{ {
@ -81,24 +83,25 @@ namespace osu.Game.Screens.Play
try try
{ {
if (Beatmap == null) if (!Beatmap.Value.WithStoryboard)
Beatmap = beatmaps.GetWorkingBeatmap(BeatmapInfo, withStoryboard: true); // we need to ensure the storyboard is loaded.
Beatmap.Value = beatmaps.GetWorkingBeatmap(BeatmapInfo, withStoryboard: true);
if (Beatmap?.Beatmap == null) if (Beatmap.Value.Beatmap == null)
throw new InvalidOperationException("Beatmap was not loaded"); throw new InvalidOperationException("Beatmap was not loaded");
ruleset = osu?.Ruleset.Value ?? Beatmap.BeatmapInfo.Ruleset; ruleset = osu?.Ruleset.Value ?? Beatmap.Value.BeatmapInfo.Ruleset;
rulesetInstance = ruleset.CreateInstance(); rulesetInstance = ruleset.CreateInstance();
try try
{ {
HitRenderer = rulesetInstance.CreateHitRendererWith(Beatmap, ruleset.ID == Beatmap.BeatmapInfo.Ruleset.ID); HitRenderer = rulesetInstance.CreateHitRendererWith(Beatmap, ruleset.ID == Beatmap.Value.BeatmapInfo.Ruleset.ID);
} }
catch (BeatmapInvalidForRulesetException) catch (BeatmapInvalidForRulesetException)
{ {
// we may fail to create a HitRenderer if the beatmap cannot be loaded with the user's preferred ruleset // we may fail to create a HitRenderer if the beatmap cannot be loaded with the user's preferred ruleset
// let's try again forcing the beatmap's ruleset. // let's try again forcing the beatmap's ruleset.
ruleset = Beatmap.BeatmapInfo.Ruleset; ruleset = Beatmap.Value.BeatmapInfo.Ruleset;
rulesetInstance = ruleset.CreateInstance(); rulesetInstance = ruleset.CreateInstance();
HitRenderer = rulesetInstance.CreateHitRendererWith(Beatmap, true); HitRenderer = rulesetInstance.CreateHitRendererWith(Beatmap, true);
} }
@ -115,7 +118,7 @@ namespace osu.Game.Screens.Play
return; return;
} }
Track track = Beatmap.Track; Track track = Beatmap.Value.Track;
if (track != null) if (track != null)
{ {
@ -128,7 +131,7 @@ namespace osu.Game.Screens.Play
decoupledClock = new DecoupleableInterpolatingFramedClock { IsCoupled = false }; decoupledClock = new DecoupleableInterpolatingFramedClock { IsCoupled = false };
var firstObjectTime = HitRenderer.Objects.First().StartTime; var firstObjectTime = HitRenderer.Objects.First().StartTime;
decoupledClock.Seek(Math.Min(0, firstObjectTime - Math.Max(Beatmap.Beatmap.ControlPointInfo.TimingPointAt(firstObjectTime).BeatLength * 4, Beatmap.BeatmapInfo.AudioLeadIn))); decoupledClock.Seek(Math.Min(0, firstObjectTime - Math.Max(Beatmap.Value.Beatmap.ControlPointInfo.TimingPointAt(firstObjectTime).BeatLength * 4, Beatmap.Value.BeatmapInfo.AudioLeadIn)));
decoupledClock.ProcessFrame(); decoupledClock.ProcessFrame();
offsetClock = new FramedOffsetClock(decoupledClock); offsetClock = new FramedOffsetClock(decoupledClock);
@ -141,7 +144,7 @@ namespace osu.Game.Screens.Play
{ {
adjustableSourceClock.Reset(); adjustableSourceClock.Reset();
foreach (var mod in Beatmap.Mods.Value.OfType<IApplicableToClock>()) foreach (var mod in Beatmap.Value.Mods.Value.OfType<IApplicableToClock>())
mod.ApplyToClock(adjustableSourceClock); mod.ApplyToClock(adjustableSourceClock);
decoupledClock.ChangeSource(adjustableSourceClock); decoupledClock.ChangeSource(adjustableSourceClock);
@ -209,7 +212,7 @@ namespace osu.Game.Screens.Play
hudOverlay.Progress.AllowSeeking = HitRenderer.HasReplayLoaded; hudOverlay.Progress.AllowSeeking = HitRenderer.HasReplayLoaded;
hudOverlay.Progress.OnSeek = pos => decoupledClock.Seek(pos); hudOverlay.Progress.OnSeek = pos => decoupledClock.Seek(pos);
hudOverlay.ModDisplay.Current.BindTo(Beatmap.Mods); hudOverlay.ModDisplay.Current.BindTo(Beatmap.Value.Mods);
//bind HitRenderer to ScoreProcessor and ourselves (for a pass situation) //bind HitRenderer to ScoreProcessor and ourselves (for a pass situation)
HitRenderer.OnAllJudged += onCompletion; HitRenderer.OnAllJudged += onCompletion;
@ -242,7 +245,7 @@ namespace osu.Game.Screens.Play
{ {
var score = new Score var score = new Score
{ {
Beatmap = Beatmap.BeatmapInfo, Beatmap = Beatmap.Value.BeatmapInfo,
Ruleset = ruleset Ruleset = ruleset
}; };
scoreProcessor.PopulateScore(score); scoreProcessor.PopulateScore(score);
@ -265,6 +268,9 @@ namespace osu.Game.Screens.Play
{ {
base.OnEntering(last); base.OnEntering(last);
if (!loadedSuccessfully)
return;
(Background as BackgroundScreenBeatmap)?.BlurTo(Vector2.Zero, 1500, EasingTypes.OutQuint); (Background as BackgroundScreenBeatmap)?.BlurTo(Vector2.Zero, 1500, EasingTypes.OutQuint);
Background?.FadeTo(1 - (float)dimLevel, 1500, EasingTypes.OutQuint); Background?.FadeTo(1 - (float)dimLevel, 1500, EasingTypes.OutQuint);
@ -304,7 +310,11 @@ namespace osu.Game.Screens.Play
return base.OnExiting(next); return base.OnExiting(next);
} }
if (loadedSuccessfully)
{
pauseContainer.Pause(); pauseContainer.Pause();
}
return true; return true;
} }

View File

@ -35,7 +35,8 @@ namespace osu.Game.Screens.Play
{ {
this.player = player; this.player = player;
player.RestartRequested = () => { player.RestartRequested = () =>
{
showOverlays = false; showOverlays = false;
ValidForResume = true; ValidForResume = true;
}; };
@ -74,7 +75,6 @@ namespace osu.Game.Screens.Play
{ {
RestartCount = player.RestartCount + 1, RestartCount = player.RestartCount + 1,
RestartRequested = player.RestartRequested, RestartRequested = player.RestartRequested,
Beatmap = player.Beatmap,
}); });
Delay(400); Delay(400);

View File

@ -165,7 +165,7 @@ namespace osu.Game.Screens.Ranking
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Alpha = 0.2f, Alpha = 0.2f,
Texture = Beatmap?.Background, Texture = Beatmap.Value.Background,
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
FillMode = FillMode.Fill FillMode = FillMode.Fill

View File

@ -137,6 +137,7 @@ namespace osu.Game.Screens.Select
{ {
selectedGroup = null; selectedGroup = null;
selectedPanel = null; selectedPanel = null;
SelectionChanged?.Invoke(null);
return; return;
} }
@ -284,6 +285,7 @@ namespace osu.Game.Screens.Select
private void load(BeatmapDatabase database, OsuConfigManager config) private void load(BeatmapDatabase database, OsuConfigManager config)
{ {
this.database = database; this.database = database;
randomType = config.GetBindable<SelectionRandomType>(OsuSetting.SelectionRandomType); randomType = config.GetBindable<SelectionRandomType>(OsuSetting.SelectionRandomType);
} }

View File

@ -45,6 +45,12 @@ namespace osu.Game.Screens.Select
}; };
} }
protected override void LoadComplete()
{
base.LoadComplete();
AlwaysPresent = true;
}
protected override bool HideOnEscape => false; protected override bool HideOnEscape => false;
protected override bool BlockPassThroughMouse => false; protected override bool BlockPassThroughMouse => false;
@ -63,18 +69,6 @@ namespace osu.Game.Screens.Select
public void UpdateBeatmap(WorkingBeatmap beatmap) public void UpdateBeatmap(WorkingBeatmap beatmap)
{ {
if (beatmap?.BeatmapInfo == null)
{
State = Visibility.Hidden;
beatmapInfoContainer?.FadeOut(250);
beatmapInfoContainer?.Expire();
beatmapInfoContainer = null;
return;
}
State = Visibility.Visible;
AlwaysPresent = true;
var lastContainer = beatmapInfoContainer; var lastContainer = beatmapInfoContainer;
float newDepth = lastContainer?.Depth + 1 ?? 0; float newDepth = lastContainer?.Depth + 1 ?? 0;

View File

@ -51,28 +51,27 @@ namespace osu.Game.Screens.Select
ValidForResume = false; ValidForResume = false;
Push(new Editor()); Push(new Editor());
}, Key.Number3); }, Key.Number3);
Beatmap.ValueChanged += beatmap_ValueChanged;
} }
protected override void OnBeatmapChanged(WorkingBeatmap beatmap) private void beatmap_ValueChanged(WorkingBeatmap beatmap)
{ {
beatmap?.Mods.BindTo(modSelect.SelectedMods); if (!IsCurrentScreen) return;
if (Beatmap?.Track != null) beatmap.Mods.BindTo(modSelect.SelectedMods);
Beatmap.Track.Looping = false;
beatmapDetails.Beatmap = beatmap; beatmapDetails.Beatmap = beatmap;
if (beatmap?.Track != null) if (beatmap.Track != null)
beatmap.Track.Looping = true; beatmap.Track.Looping = true;
base.OnBeatmapChanged(beatmap);
} }
protected override void OnResuming(Screen last) protected override void OnResuming(Screen last)
{ {
player = null; player = null;
Beatmap.Track.Looping = true; Beatmap.Value.Track.Looping = true;
base.OnResuming(last); base.OnResuming(last);
} }
@ -95,8 +94,8 @@ namespace osu.Game.Screens.Select
if (base.OnExiting(next)) if (base.OnExiting(next))
return true; return true;
if (Beatmap?.Track != null) if (Beatmap.Value.Track != null)
Beatmap.Track.Looping = false; Beatmap.Value.Track.Looping = false;
return false; return false;
} }
@ -105,12 +104,9 @@ namespace osu.Game.Screens.Select
{ {
if (player != null) return; if (player != null) return;
Beatmap.Track.Looping = false; Beatmap.Value.Track.Looping = false;
LoadComponentAsync(player = new PlayerLoader(new Player LoadComponentAsync(player = new PlayerLoader(new Player()), l => Push(player));
{
Beatmap = Beatmap, //eagerly set this so it's present before push.
}), l => Push(player));
} }
} }
} }

View File

@ -1,6 +1,7 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 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.Threading; using System.Threading;
using OpenTK; using OpenTK;
using OpenTK.Input; using OpenTK.Input;
@ -28,7 +29,7 @@ namespace osu.Game.Screens.Select
{ {
private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>(); private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>();
private BeatmapDatabase database; private BeatmapDatabase database;
protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap); protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap();
private readonly BeatmapCarousel carousel; private readonly BeatmapCarousel carousel;
private TrackManager trackManager; private TrackManager trackManager;
@ -107,8 +108,9 @@ namespace osu.Game.Screens.Select
Size = new Vector2(carousel_width, 1), Size = new Vector2(carousel_width, 1),
Anchor = Anchor.CentreRight, Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight, Origin = Anchor.CentreRight,
SelectionChanged = selectionChanged, SelectionChanged = carouselSelectionChanged,
StartRequested = raiseSelect BeatmapsChanged = carouselBeatmapsLoaded,
StartRequested = carouselRaisedStart
}); });
Add(FilterControl = new FilterControl Add(FilterControl = new FilterControl
{ {
@ -127,7 +129,6 @@ namespace osu.Game.Screens.Select
Top = left_area_padding, Top = left_area_padding,
Right = left_area_padding, Right = left_area_padding,
}, },
X = -50,
}); });
if (ShowFooter) if (ShowFooter)
@ -146,7 +147,7 @@ namespace osu.Game.Screens.Select
Add(Footer = new Footer Add(Footer = new Footer
{ {
OnBack = Exit, OnBack = Exit,
OnStart = raiseSelect, OnStart = carouselRaisedStart,
}); });
FooterPanels.Add(BeatmapOptions = new BeatmapOptionsOverlay()); FooterPanels.Add(BeatmapOptions = new BeatmapOptionsOverlay());
@ -181,34 +182,79 @@ namespace osu.Game.Screens.Select
initialAddSetsTask = new CancellationTokenSource(); initialAddSetsTask = new CancellationTokenSource();
carousel.BeatmapsChanged = beatmapsLoaded;
carousel.Beatmaps = database.GetAllWithChildren<BeatmapSetInfo>(b => !b.DeletePending); carousel.Beatmaps = database.GetAllWithChildren<BeatmapSetInfo>(b => !b.DeletePending);
Beatmap.ValueChanged += beatmap_ValueChanged;
} }
private void beatmapsLoaded() private void carouselBeatmapsLoaded()
{ {
if (Beatmap != null) if (Beatmap.Value != null && !Beatmap.Value.BeatmapSetInfo.DeletePending)
carousel.SelectBeatmap(Beatmap.BeatmapInfo, false); carousel.SelectBeatmap(Beatmap.Value.BeatmapInfo, false);
else else
carousel.SelectNext(); carousel.SelectNext();
} }
private void raiseSelect() private void carouselRaisedStart()
{ {
var pendingSelection = selectionChangedDebounce; var pendingSelection = selectionChangedDebounce;
selectionChangedDebounce = null; selectionChangedDebounce = null;
if (pendingSelection?.Completed == false) if (pendingSelection?.Completed == false)
{ {
pendingSelection?.RunTask(); pendingSelection.RunTask();
pendingSelection?.Cancel(); // cancel the already scheduled task. pendingSelection.Cancel(); // cancel the already scheduled task.
} }
if (Beatmap == null) return;
OnSelected(); OnSelected();
} }
private ScheduledDelegate selectionChangedDebounce;
// We need to keep track of the last selected beatmap ignoring debounce to play the correct selection sounds.
private BeatmapInfo beatmapNoDebounce;
/// <summary>
/// selection has been changed as the result of interaction with the carousel.
/// </summary>
private void carouselSelectionChanged(BeatmapInfo beatmap)
{
Action performLoad = delegate
{
bool preview = beatmap?.BeatmapSetInfoID != Beatmap.Value.BeatmapInfo.BeatmapSetInfoID;
Beatmap.Value = database.GetWorkingBeatmap(beatmap, Beatmap);
ensurePlayingSelected(preview);
changeBackground(Beatmap.Value);
};
if (beatmap == null)
{
if (!Beatmap.IsDefault)
performLoad();
}
else
{
selectionChangedDebounce?.Cancel();
if (beatmap.Equals(beatmapNoDebounce))
return;
if (beatmap.BeatmapSetInfoID == beatmapNoDebounce?.BeatmapSetInfoID)
sampleChangeDifficulty.Play();
else
sampleChangeBeatmap.Play();
beatmapNoDebounce = beatmap;
if (beatmap == Beatmap.Value.BeatmapInfo)
performLoad();
else
selectionChangedDebounce = Scheduler.AddDelayed(performLoad, 100);
}
}
private void triggerRandom(UserInputManager input) private void triggerRandom(UserInputManager input)
{ {
if (input.CurrentState.Keyboard.ShiftPressed) if (input.CurrentState.Keyboard.ShiftPressed)
@ -231,23 +277,27 @@ namespace osu.Game.Screens.Select
protected override void OnEntering(Screen last) protected override void OnEntering(Screen last)
{ {
base.OnEntering(last); base.OnEntering(last);
ensurePlayingSelected();
changeBackground(Beatmap);
selectionChangeNoBounce = Beatmap?.BeatmapInfo;
Content.FadeInFromZero(250); Content.FadeInFromZero(250);
beatmapInfoWedge.State = Visibility.Visible;
FilterControl.Activate(); FilterControl.Activate();
} }
private void beatmap_ValueChanged(WorkingBeatmap beatmap)
{
if (!IsCurrentScreen) return;
carousel.SelectBeatmap(beatmap?.BeatmapInfo);
}
protected override void OnResuming(Screen last) protected override void OnResuming(Screen last)
{
if (Beatmap != null && !Beatmap.Value.BeatmapSetInfo.DeletePending)
{ {
changeBackground(Beatmap); changeBackground(Beatmap);
ensurePlayingSelected(); ensurePlayingSelected();
}
base.OnResuming(last); base.OnResuming(last);
Content.FadeIn(250); Content.FadeIn(250);
@ -300,70 +350,25 @@ namespace osu.Game.Screens.Select
backgroundModeBeatmap.FadeTo(1, 250); backgroundModeBeatmap.FadeTo(1, 250);
} }
beatmapInfoWedge.State = Visibility.Visible;
beatmapInfoWedge.UpdateBeatmap(beatmap); beatmapInfoWedge.UpdateBeatmap(beatmap);
} }
/// <summary>
/// The global Beatmap was changed.
/// </summary>
protected override void OnBeatmapChanged(WorkingBeatmap beatmap)
{
base.OnBeatmapChanged(beatmap);
//todo: change background in selectionChanged instead; support per-difficulty backgrounds.
changeBackground(beatmap);
carousel.SelectBeatmap(beatmap?.BeatmapInfo);
}
private ScheduledDelegate selectionChangedDebounce;
// We need to keep track of the last selected beatmap ignoring debounce to play the correct selection sounds.
private BeatmapInfo selectionChangeNoBounce;
/// <summary>
/// selection has been changed as the result of interaction with the carousel.
/// </summary>
private void selectionChanged(BeatmapInfo beatmap)
{
selectionChangedDebounce?.Cancel();
if (beatmap.Equals(Beatmap?.BeatmapInfo))
return;
bool preview = beatmap.BeatmapSetInfoID != Beatmap?.BeatmapInfo.BeatmapSetInfoID;
if (beatmap.BeatmapSetInfoID == selectionChangeNoBounce?.BeatmapSetInfoID)
sampleChangeDifficulty.Play();
else
sampleChangeBeatmap.Play();
selectionChangeNoBounce = beatmap;
selectionChangedDebounce = Scheduler.AddDelayed(delegate
{
Beatmap = database.GetWorkingBeatmap(beatmap, Beatmap);
ensurePlayingSelected(preview);
}, 100);
}
private void ensurePlayingSelected(bool preview = false) private void ensurePlayingSelected(bool preview = false)
{ {
Track track = Beatmap?.Track; Track track = Beatmap.Value.Track;
if (track != null)
{
trackManager.SetExclusive(track); trackManager.SetExclusive(track);
if (preview)
track.Seek(Beatmap.Metadata.PreviewTime); if (preview) track.Seek(Beatmap.Value.Metadata.PreviewTime);
track.Start(); track.Start();
} }
}
private void removeBeatmapSet(BeatmapSetInfo beatmapSet) private void removeBeatmapSet(BeatmapSetInfo beatmapSet)
{ {
carousel.RemoveBeatmap(beatmapSet); carousel.RemoveBeatmap(beatmapSet);
if (carousel.SelectedBeatmap == null) if (carousel.SelectedBeatmap == null)
Beatmap = null; Beatmap.SetDefault();
} }
private void promptDelete() private void promptDelete()
@ -380,7 +385,7 @@ namespace osu.Game.Screens.Select
{ {
case Key.KeypadEnter: case Key.KeypadEnter:
case Key.Enter: case Key.Enter:
raiseSelect(); carouselRaisedStart();
return true; return true;
case Key.Delete: case Key.Delete:
if (state.Keyboard.ShiftPressed) if (state.Keyboard.ShiftPressed)

View File

@ -76,6 +76,7 @@
<Compile Include="Audio\SampleInfoList.cs" /> <Compile Include="Audio\SampleInfoList.cs" />
<Compile Include="Beatmaps\Drawables\BeatmapBackgroundSprite.cs" /> <Compile Include="Beatmaps\Drawables\BeatmapBackgroundSprite.cs" />
<Compile Include="Beatmaps\DifficultyCalculator.cs" /> <Compile Include="Beatmaps\DifficultyCalculator.cs" />
<Compile Include="Beatmaps\DummyWorkingBeatmap.cs" />
<Compile Include="Graphics\Containers\OsuClickableContainer.cs" /> <Compile Include="Graphics\Containers\OsuClickableContainer.cs" />
<Compile Include="Graphics\Containers\OsuFocusedOverlayContainer.cs" /> <Compile Include="Graphics\Containers\OsuFocusedOverlayContainer.cs" />
<Compile Include="Graphics\Containers\OsuScrollContainer.cs" /> <Compile Include="Graphics\Containers\OsuScrollContainer.cs" />