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

Merge branch 'master' into fix-background-screen-crash

This commit is contained in:
Dan Balasescu 2018-07-02 15:01:59 +09:00 committed by GitHub
commit 2c19790a97
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
94 changed files with 1316 additions and 529 deletions

View File

@ -55,7 +55,7 @@ namespace osu.Game.Rulesets.Catch.Tests
private DrawableFruit createDrawable(int index) private DrawableFruit createDrawable(int index)
{ {
Fruit fruit = index == 5 Fruit fruit = index == 5
? new BananaShower.Banana ? new Banana
{ {
StartTime = 1000000000000, StartTime = 1000000000000,
IndexInBeatmap = index, IndexInBeatmap = index,

View File

@ -15,6 +15,8 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
{ {
public class CatchBeatmapProcessor : BeatmapProcessor public class CatchBeatmapProcessor : BeatmapProcessor
{ {
public const int RNG_SEED = 1337;
public CatchBeatmapProcessor(IBeatmap beatmap) public CatchBeatmapProcessor(IBeatmap beatmap)
: base(beatmap) : base(beatmap)
{ {
@ -22,12 +24,12 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
public override void PostProcess() public override void PostProcess()
{ {
base.PostProcess();
applyPositionOffsets(); applyPositionOffsets();
initialiseHyperDash((List<CatchHitObject>)Beatmap.HitObjects); initialiseHyperDash((List<CatchHitObject>)Beatmap.HitObjects);
base.PostProcess();
int index = 0; int index = 0;
foreach (var obj in Beatmap.HitObjects.OfType<CatchHitObject>()) foreach (var obj in Beatmap.HitObjects.OfType<CatchHitObject>())
{ {
@ -37,8 +39,6 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
} }
} }
public const int RNG_SEED = 1337;
private void applyPositionOffsets() private void applyPositionOffsets()
{ {
var rng = new FastRandom(RNG_SEED); var rng = new FastRandom(RNG_SEED);
@ -49,9 +49,9 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
switch (obj) switch (obj)
{ {
case BananaShower bananaShower: case BananaShower bananaShower:
foreach (var nested in bananaShower.NestedHitObjects) foreach (var banana in bananaShower.NestedHitObjects.OfType<Banana>())
{ {
((BananaShower.Banana)nested).X = (float)rng.NextDouble(); banana.X = (float)rng.NextDouble();
rng.Next(); // osu!stable retrieved a random banana type rng.Next(); // osu!stable retrieved a random banana type
rng.Next(); // osu!stable retrieved a random banana rotation rng.Next(); // osu!stable retrieved a random banana rotation
rng.Next(); // osu!stable retrieved a random banana colour rng.Next(); // osu!stable retrieved a random banana colour

View File

@ -0,0 +1,36 @@
// 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.Rulesets.Scoring;
namespace osu.Game.Rulesets.Catch.Judgements
{
public class CatchBananaJudgement : CatchJudgement
{
public override bool AffectsCombo => false;
public override bool ShouldExplode => true;
protected override int NumericResultFor(HitResult result)
{
switch (result)
{
default:
return 0;
case HitResult.Perfect:
return 1100;
}
}
protected override float HealthIncreaseFor(HitResult result)
{
switch (result)
{
default:
return 0;
case HitResult.Perfect:
return 8;
}
}
}
}

View File

@ -0,0 +1,32 @@
// 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.Rulesets.Scoring;
namespace osu.Game.Rulesets.Catch.Judgements
{
public class CatchDropletJudgement : CatchJudgement
{
protected override int NumericResultFor(HitResult result)
{
switch (result)
{
default:
return 0;
case HitResult.Perfect:
return 30;
}
}
protected override float HealthIncreaseFor(HitResult result)
{
switch (result)
{
default:
return 0;
case HitResult.Perfect:
return 7;
}
}
}
}

View File

@ -2,11 +2,51 @@
// 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.Game.Rulesets.Judgements; using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Catch.Judgements namespace osu.Game.Rulesets.Catch.Judgements
{ {
public class CatchJudgement : Judgement public class CatchJudgement : Judgement
{ {
// todo: wangs public override HitResult MaxResult => HitResult.Perfect;
protected override int NumericResultFor(HitResult result)
{
switch (result)
{
default:
return 0;
case HitResult.Perfect:
return 300;
}
}
/// <summary>
/// The base health increase for the result achieved.
/// </summary>
public float HealthIncrease => HealthIncreaseFor(Result);
/// <summary>
/// Whether fruit on the platter should explode or drop.
/// Note that this is only checked if the owning object is also <see cref="IHasComboInformation.LastInCombo" />
/// </summary>
public virtual bool ShouldExplode => IsHit;
/// <summary>
/// Convert a <see cref="HitResult"/> to a base health increase.
/// </summary>
/// <param name="result">The value to convert.</param>
/// <returns>The base health increase.</returns>
protected virtual float HealthIncreaseFor(HitResult result)
{
switch (result)
{
default:
return 0;
case HitResult.Perfect:
return 10.2f;
}
}
} }
} }

View File

@ -0,0 +1,34 @@
// 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.Rulesets.Scoring;
namespace osu.Game.Rulesets.Catch.Judgements
{
public class CatchTinyDropletJudgement : CatchJudgement
{
public override bool AffectsCombo => false;
protected override int NumericResultFor(HitResult result)
{
switch (result)
{
default:
return 0;
case HitResult.Perfect:
return 10;
}
}
protected override float HealthIncreaseFor(HitResult result)
{
switch (result)
{
default:
return 0;
case HitResult.Perfect:
return 4;
}
}
}
}

View File

@ -0,0 +1,10 @@
// 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.Rulesets.Catch.Objects
{
public class Banana : Fruit
{
public override FruitVisualRepresentation VisualRepresentation => FruitVisualRepresentation.Banana;
}
}

View File

@ -37,10 +37,5 @@ namespace osu.Game.Rulesets.Catch.Objects
public double EndTime => StartTime + Duration; public double EndTime => StartTime + Duration;
public double Duration { get; set; } public double Duration { get; set; }
public class Banana : Fruit
{
public override FruitVisualRepresentation VisualRepresentation => FruitVisualRepresentation.Banana;
}
} }
} }

View File

@ -0,0 +1,17 @@
// 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.Rulesets.Catch.Judgements;
namespace osu.Game.Rulesets.Catch.Objects.Drawable
{
public class DrawableBanana : DrawableFruit
{
public DrawableBanana(Banana h)
: base(h)
{
}
protected override CatchJudgement CreateJudgement() => new CatchBananaJudgement();
}
}

View File

@ -5,9 +5,7 @@ using System;
using System.Linq; using System.Linq;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Catch.Objects.Drawable namespace osu.Game.Rulesets.Catch.Objects.Drawable
{ {
@ -24,15 +22,11 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
InternalChild = bananaContainer = new Container { RelativeSizeAxes = Axes.Both }; InternalChild = bananaContainer = new Container { RelativeSizeAxes = Axes.Both };
foreach (var b in s.NestedHitObjects.Cast<BananaShower.Banana>()) foreach (var b in s.NestedHitObjects.Cast<Banana>())
AddNested(getVisualRepresentation?.Invoke(b)); AddNested(getVisualRepresentation?.Invoke(b));
} }
protected override void CheckForJudgements(bool userTriggered, double timeOffset) protected override bool ProvidesJudgement => false;
{
if (timeOffset >= 0)
AddJudgement(new Judgement { Result = NestedHitObjects.Cast<DrawableCatchHitObject>().Any(n => n.Judgements.Any(j => j.IsHit)) ? HitResult.Perfect : HitResult.Miss });
}
protected override void AddNested(DrawableHitObject h) protected override void AddNested(DrawableHitObject h)
{ {

View File

@ -2,14 +2,14 @@
// 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;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Catch.Judgements;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
using OpenTK;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Skinning; using osu.Game.Skinning;
using OpenTK.Graphics;
namespace osu.Game.Rulesets.Catch.Objects.Drawable namespace osu.Game.Rulesets.Catch.Objects.Drawable
{ {
@ -58,9 +58,15 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
if (CheckPosition == null) return; if (CheckPosition == null) return;
if (timeOffset >= 0) if (timeOffset >= 0)
AddJudgement(new Judgement { Result = CheckPosition.Invoke(HitObject) ? HitResult.Perfect : HitResult.Miss }); {
var judgement = CreateJudgement();
judgement.Result = CheckPosition.Invoke(HitObject) ? HitResult.Perfect : HitResult.Miss;
AddJudgement(judgement);
}
} }
protected virtual CatchJudgement CreateJudgement() => new CatchJudgement();
protected override void SkinChanged(ISkinSource skin, bool allowFallback) protected override void SkinChanged(ISkinSource skin, bool allowFallback)
{ {
base.SkinChanged(skin, allowFallback); base.SkinChanged(skin, allowFallback);

View File

@ -6,6 +6,7 @@ using osu.Framework.Graphics;
using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces; using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces;
using OpenTK; using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
using osu.Game.Rulesets.Catch.Judgements;
namespace osu.Game.Rulesets.Catch.Objects.Drawable namespace osu.Game.Rulesets.Catch.Objects.Drawable
{ {
@ -23,6 +24,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
Masking = false; Masking = false;
} }
protected override CatchJudgement CreateJudgement() => new CatchDropletJudgement();
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {

View File

@ -0,0 +1,19 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using osu.Game.Rulesets.Catch.Judgements;
namespace osu.Game.Rulesets.Catch.Objects.Drawable
{
public class DrawableTinyDroplet : DrawableDroplet
{
public DrawableTinyDroplet(Droplet h)
: base(h)
{
Size = new Vector2((float)CatchHitObject.OBJECT_RADIUS) / 8;
}
protected override CatchJudgement CreateJudgement() => new CatchTinyDropletJudgement();
}
}

View File

@ -56,7 +56,7 @@ namespace osu.Game.Rulesets.Catch.Replays
return; return;
} }
if (h is BananaShower.Banana) if (h is Banana)
{ {
// auto bananas unrealistically warp to catch 100% combo. // auto bananas unrealistically warp to catch 100% combo.
Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X)); Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X));
@ -105,7 +105,7 @@ namespace osu.Game.Rulesets.Catch.Replays
{ {
switch (nestedObj) switch (nestedObj)
{ {
case BananaShower.Banana _: case Banana _:
case TinyDroplet _: case TinyDroplet _:
case Droplet _: case Droplet _:
case Fruit _: case Fruit _:

View File

@ -1,10 +1,12 @@
// 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.Linq; using System.Linq;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Judgements; using osu.Game.Rulesets.Catch.Judgements;
using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
@ -17,28 +19,57 @@ namespace osu.Game.Rulesets.Catch.Scoring
{ {
} }
private float hpDrainRate;
protected override void SimulateAutoplay(Beatmap<CatchHitObject> beatmap) protected override void SimulateAutoplay(Beatmap<CatchHitObject> beatmap)
{ {
hpDrainRate = beatmap.BeatmapInfo.BaseDifficulty.DrainRate;
foreach (var obj in beatmap.HitObjects) foreach (var obj in beatmap.HitObjects)
{ {
switch (obj) switch (obj)
{ {
case JuiceStream stream: case JuiceStream stream:
foreach (var _ in stream.NestedHitObjects.Cast<CatchHitObject>()) foreach (var nestedObject in stream.NestedHitObjects)
AddJudgement(new CatchJudgement { Result = HitResult.Perfect }); switch (nestedObject)
{
case TinyDroplet _:
AddJudgement(new CatchTinyDropletJudgement { Result = HitResult.Perfect });
break;
case Droplet _:
AddJudgement(new CatchDropletJudgement { Result = HitResult.Perfect });
break;
case Fruit _:
AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
break;
}
break; break;
case BananaShower shower: case BananaShower shower:
foreach (var _ in shower.NestedHitObjects.Cast<CatchHitObject>()) foreach (var _ in shower.NestedHitObjects.Cast<CatchHitObject>())
AddJudgement(new CatchJudgement { Result = HitResult.Perfect }); AddJudgement(new CatchBananaJudgement { Result = HitResult.Perfect });
AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
break; break;
case Fruit _: case Fruit _:
AddJudgement(new CatchJudgement { Result = HitResult.Perfect }); AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
break; break;
} }
} }
}
base.SimulateAutoplay(beatmap); private const double harshness = 0.01;
protected override void OnNewJudgement(Judgement judgement)
{
base.OnNewJudgement(judgement);
if (judgement.Result == HitResult.Miss)
{
if (!judgement.IsBonus)
Health.Value -= hpDrainRate * (harshness * 2);
return;
}
if (judgement is CatchJudgement catchJudgement)
Health.Value += Math.Max(catchJudgement.HealthIncrease - hpDrainRate, 0) * harshness;
} }
} }
} }

View File

@ -38,14 +38,16 @@ namespace osu.Game.Rulesets.Catch.UI
{ {
switch (h) switch (h)
{ {
case Banana banana:
return new DrawableBanana(banana);
case Fruit fruit: case Fruit fruit:
return new DrawableFruit(fruit); return new DrawableFruit(fruit);
case JuiceStream stream: case JuiceStream stream:
return new DrawableJuiceStream(stream, GetVisualRepresentation); return new DrawableJuiceStream(stream, GetVisualRepresentation);
case BananaShower banana: case BananaShower shower:
return new DrawableBananaShower(banana, GetVisualRepresentation); return new DrawableBananaShower(shower, GetVisualRepresentation);
case TinyDroplet tiny: case TinyDroplet tiny:
return new DrawableDroplet(tiny) { Scale = new Vector2(0.5f) }; return new DrawableTinyDroplet(tiny);
case Droplet droplet: case Droplet droplet:
return new DrawableDroplet(droplet); return new DrawableDroplet(droplet);
} }

View File

@ -11,6 +11,7 @@ using osu.Framework.Graphics.Textures;
using osu.Framework.Input.Bindings; using osu.Framework.Input.Bindings;
using osu.Framework.MathUtils; using osu.Framework.MathUtils;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Judgements;
using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.Objects.Drawable; using osu.Game.Rulesets.Catch.Objects.Drawable;
using osu.Game.Rulesets.Catch.Replays; using osu.Game.Rulesets.Catch.Replays;
@ -78,12 +79,11 @@ namespace osu.Game.Rulesets.Catch.UI
if (!fruit.StaysOnPlate) if (!fruit.StaysOnPlate)
runAfterLoaded(() => MovableCatcher.Explode(caughtFruit)); runAfterLoaded(() => MovableCatcher.Explode(caughtFruit));
} }
if (fruit.HitObject.LastInCombo) if (fruit.HitObject.LastInCombo)
{ {
if (judgement.IsHit) if (((CatchJudgement)judgement).ShouldExplode)
runAfterLoaded(() => MovableCatcher.Explode()); runAfterLoaded(() => MovableCatcher.Explode());
else else
MovableCatcher.Drop(); MovableCatcher.Drop();

View File

@ -69,7 +69,7 @@ namespace osu.Game.Rulesets.Mania.Tests
var obj = new Note { Column = i, StartTime = Time.Current + 2000 }; var obj = new Note { Column = i, StartTime = Time.Current + 2000 };
obj.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); obj.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
columns[i].Add(new DrawableNote(obj, columns[i].Action)); columns[i].Add(new DrawableNote(obj));
} }
} }
@ -80,7 +80,7 @@ namespace osu.Game.Rulesets.Mania.Tests
var obj = new HoldNote { Column = i, StartTime = Time.Current + 2000, Duration = 500 }; var obj = new HoldNote { Column = i, StartTime = Time.Current + 2000, Duration = 500 };
obj.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); obj.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
columns[i].Add(new DrawableHoldNote(obj, columns[i].Action)); columns[i].Add(new DrawableHoldNote(obj));
} }
} }
@ -92,7 +92,7 @@ namespace osu.Game.Rulesets.Mania.Tests
Origin = Anchor.Centre, Origin = Anchor.Centre,
Height = 0.85f, Height = 0.85f,
AccentColour = Color4.OrangeRed, AccentColour = Color4.OrangeRed,
Action = action, Action = { Value = action },
VisibleTimeRange = { Value = 2000 } VisibleTimeRange = { Value = 2000 }
}; };

View File

@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Configuration;
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;
@ -63,7 +64,7 @@ namespace osu.Game.Rulesets.Mania.Tests
AutoSizeAxes = Axes.Both, AutoSizeAxes = Axes.Both,
Child = new NoteContainer(direction, $"note, scrolling {direction.ToString().ToLower()}") Child = new NoteContainer(direction, $"note, scrolling {direction.ToString().ToLower()}")
{ {
Child = new DrawableNote(note, ManiaAction.Key1) { AccentColour = Color4.OrangeRed } Child = new DrawableNote(note) { AccentColour = Color4.OrangeRed }
} }
}; };
} }
@ -78,7 +79,7 @@ namespace osu.Game.Rulesets.Mania.Tests
AutoSizeAxes = Axes.Both, AutoSizeAxes = Axes.Both,
Child = new NoteContainer(direction, $"hold note, scrolling {direction.ToString().ToLower()}") Child = new NoteContainer(direction, $"hold note, scrolling {direction.ToString().ToLower()}")
{ {
Child = new DrawableHoldNote(note, ManiaAction.Key1) Child = new DrawableHoldNote(note)
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
AccentColour = Color4.OrangeRed, AccentColour = Color4.OrangeRed,
@ -136,6 +137,13 @@ namespace osu.Game.Rulesets.Mania.Tests
}; };
} }
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
{
var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
dependencies.CacheAs<IBindable<ManiaAction>>(new Bindable<ManiaAction>());
return dependencies;
}
protected override void Update() protected override void Update()
{ {
base.Update(); base.Update();

View File

@ -65,7 +65,7 @@ namespace osu.Game.Rulesets.Mania.Tests
var obj = new Note { Column = i, StartTime = Time.Current + 2000 }; var obj = new Note { Column = i, StartTime = Time.Current + 2000 };
obj.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); obj.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
stage.Add(new DrawableNote(obj, stage.Columns[i].Action)); stage.Add(new DrawableNote(obj));
} }
} }
} }
@ -79,7 +79,7 @@ namespace osu.Game.Rulesets.Mania.Tests
var obj = new HoldNote { Column = i, StartTime = Time.Current + 2000, Duration = 500 }; var obj = new HoldNote { Column = i, StartTime = Time.Current + 2000, Duration = 500 };
obj.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); obj.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
stage.Add(new DrawableHoldNote(obj, stage.Columns[i].Action)); stage.Add(new DrawableHoldNote(obj));
} }
} }
} }

View File

@ -8,6 +8,7 @@ namespace osu.Game.Rulesets.Mania.Judgements
public class HoldNoteJudgement : ManiaJudgement public class HoldNoteJudgement : ManiaJudgement
{ {
public override bool AffectsCombo => false; public override bool AffectsCombo => false;
protected override int NumericResultFor(HitResult result) => 0; protected override int NumericResultFor(HitResult result) => 0;
} }
} }

View File

@ -38,8 +38,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
private readonly Container<DrawableHoldNoteTick> tickContainer; private readonly Container<DrawableHoldNoteTick> tickContainer;
public DrawableHoldNote(HoldNote hitObject, ManiaAction action) public DrawableHoldNote(HoldNote hitObject)
: base(hitObject, action) : base(hitObject)
{ {
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
@ -57,12 +57,12 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
HoldStartTime = () => holdStartTime HoldStartTime = () => holdStartTime
}) })
}, },
head = new DrawableHeadNote(this, action) head = new DrawableHeadNote(this)
{ {
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre Origin = Anchor.TopCentre
}, },
tail = new DrawableTailNote(this, action) tail = new DrawableTailNote(this)
{ {
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre Origin = Anchor.TopCentre
@ -118,7 +118,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
if (Time.Current < HitObject.StartTime || Time.Current > HitObject.EndTime) if (Time.Current < HitObject.StartTime || Time.Current > HitObject.EndTime)
return false; return false;
if (action != Action) if (action != Action.Value)
return false; return false;
// The user has pressed during the body of the hold note, after the head note and its hit windows have passed // The user has pressed during the body of the hold note, after the head note and its hit windows have passed
@ -135,7 +135,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
if (!holdStartTime.HasValue) if (!holdStartTime.HasValue)
return false; return false;
if (action != Action) if (action != Action.Value)
return false; return false;
holdStartTime = null; holdStartTime = null;
@ -154,8 +154,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
{ {
private readonly DrawableHoldNote holdNote; private readonly DrawableHoldNote holdNote;
public DrawableHeadNote(DrawableHoldNote holdNote, ManiaAction action) public DrawableHeadNote(DrawableHoldNote holdNote)
: base(holdNote.HitObject.Head, action) : base(holdNote.HitObject.Head)
{ {
this.holdNote = holdNote; this.holdNote = holdNote;
} }
@ -191,8 +191,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
private readonly DrawableHoldNote holdNote; private readonly DrawableHoldNote holdNote;
public DrawableTailNote(DrawableHoldNote holdNote, ManiaAction action) public DrawableTailNote(DrawableHoldNote holdNote)
: base(holdNote.HitObject.Tail, action) : base(holdNote.HitObject.Tail)
{ {
this.holdNote = holdNote; this.holdNote = holdNote;
} }
@ -235,7 +235,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
if (!holdNote.holdStartTime.HasValue) if (!holdNote.holdStartTime.HasValue)
return false; return false;
if (action != Action) if (action != Action.Value)
return false; return false;
UpdateJudgement(true); UpdateJudgement(true);

View File

@ -1,6 +1,7 @@
// 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 JetBrains.Annotations;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Configuration; using osu.Framework.Configuration;
using osu.Framework.Graphics; using osu.Framework.Graphics;
@ -10,30 +11,26 @@ using osu.Game.Rulesets.UI.Scrolling;
namespace osu.Game.Rulesets.Mania.Objects.Drawables namespace osu.Game.Rulesets.Mania.Objects.Drawables
{ {
public abstract class DrawableManiaHitObject<TObject> : DrawableHitObject<ManiaHitObject> public abstract class DrawableManiaHitObject : DrawableHitObject<ManiaHitObject>
where TObject : ManiaHitObject
{ {
/// <summary> /// <summary>
/// The key that will trigger input for this hit object. /// The <see cref="ManiaAction"/> which causes this <see cref="DrawableManiaHitObject{TObject}"/> to be hit.
/// </summary> /// </summary>
protected ManiaAction Action { get; } protected readonly IBindable<ManiaAction> Action = new Bindable<ManiaAction>();
public new TObject HitObject;
protected readonly IBindable<ScrollingDirection> Direction = new Bindable<ScrollingDirection>(); protected readonly IBindable<ScrollingDirection> Direction = new Bindable<ScrollingDirection>();
protected DrawableManiaHitObject(TObject hitObject, ManiaAction? action = null) protected DrawableManiaHitObject(ManiaHitObject hitObject)
: base(hitObject) : base(hitObject)
{ {
HitObject = hitObject;
if (action != null)
Action = action.Value;
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader(true)]
private void load(IScrollingInfo scrollingInfo) private void load([CanBeNull] IBindable<ManiaAction> action, [NotNull] IScrollingInfo scrollingInfo)
{ {
if (action != null)
Action.BindTo(action);
Direction.BindTo(scrollingInfo.Direction); Direction.BindTo(scrollingInfo.Direction);
Direction.BindValueChanged(OnDirectionChanged, true); Direction.BindValueChanged(OnDirectionChanged, true);
} }
@ -42,6 +39,18 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
{ {
Anchor = Origin = direction == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre; Anchor = Origin = direction == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre;
} }
}
public abstract class DrawableManiaHitObject<TObject> : DrawableManiaHitObject
where TObject : ManiaHitObject
{
public new readonly TObject HitObject;
protected DrawableManiaHitObject(TObject hitObject)
: base(hitObject)
{
HitObject = hitObject;
}
protected override void UpdateState(ArmedState state) protected override void UpdateState(ArmedState state)
{ {

View File

@ -20,8 +20,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
{ {
private readonly NotePiece headPiece; private readonly NotePiece headPiece;
public DrawableNote(Note hitObject, ManiaAction action) public DrawableNote(Note hitObject)
: base(hitObject, action) : base(hitObject)
{ {
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y; AutoSizeAxes = Axes.Y;
@ -74,7 +74,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
public virtual bool OnPressed(ManiaAction action) public virtual bool OnPressed(ManiaAction action)
{ {
if (action != Action) if (action != Action.Value)
return false; return false;
return UpdateJudgement(true); return UpdateJudgement(true);

View File

@ -7,6 +7,8 @@ using osu.Framework.Graphics.Containers;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using System.Linq; using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Input.Bindings; using osu.Framework.Input.Bindings;
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mania.UI.Components; using osu.Game.Rulesets.Mania.UI.Components;
@ -19,21 +21,7 @@ namespace osu.Game.Rulesets.Mania.UI
private const float column_width = 45; private const float column_width = 45;
private const float special_column_width = 70; private const float special_column_width = 70;
private ManiaAction action; public readonly Bindable<ManiaAction> Action = new Bindable<ManiaAction>();
public ManiaAction Action
{
get => action;
set
{
if (action == value)
return;
action = value;
background.Action = value;
keyArea.Action = value;
}
}
private readonly ColumnBackground background; private readonly ColumnBackground background;
private readonly ColumnKeyArea keyArea; private readonly ColumnKeyArea keyArea;
@ -130,6 +118,13 @@ namespace osu.Game.Rulesets.Mania.UI
} }
} }
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
{
var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
dependencies.CacheAs<IBindable<ManiaAction>>(Action);
return dependencies;
}
/// <summary> /// <summary>
/// Adds a DrawableHitObject to this Playfield. /// Adds a DrawableHitObject to this Playfield.
/// </summary> /// </summary>

View File

@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Mania.UI.Components
{ {
public class ColumnBackground : CompositeDrawable, IKeyBindingHandler<ManiaAction>, IHasAccentColour public class ColumnBackground : CompositeDrawable, IKeyBindingHandler<ManiaAction>, IHasAccentColour
{ {
public ManiaAction Action; private readonly IBindable<ManiaAction> action = new Bindable<ManiaAction>();
private Box background; private Box background;
private Box backgroundOverlay; private Box backgroundOverlay;
@ -25,8 +25,10 @@ namespace osu.Game.Rulesets.Mania.UI.Components
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>(); private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(IScrollingInfo scrollingInfo) private void load(IBindable<ManiaAction> action, IScrollingInfo scrollingInfo)
{ {
this.action.BindTo(action);
InternalChildren = new[] InternalChildren = new[]
{ {
background = new Box background = new Box
@ -91,14 +93,14 @@ namespace osu.Game.Rulesets.Mania.UI.Components
public bool OnPressed(ManiaAction action) public bool OnPressed(ManiaAction action)
{ {
if (action == Action) if (action == this.action.Value)
backgroundOverlay.FadeTo(1, 50, Easing.OutQuint).Then().FadeTo(0.5f, 250, Easing.OutQuint); backgroundOverlay.FadeTo(1, 50, Easing.OutQuint).Then().FadeTo(0.5f, 250, Easing.OutQuint);
return false; return false;
} }
public bool OnReleased(ManiaAction action) public bool OnReleased(ManiaAction action)
{ {
if (action == Action) if (action == this.action.Value)
backgroundOverlay.FadeTo(0, 250, Easing.OutQuint); backgroundOverlay.FadeTo(0, 250, Easing.OutQuint);
return false; return false;
} }

View File

@ -21,15 +21,16 @@ namespace osu.Game.Rulesets.Mania.UI.Components
private const float key_icon_size = 10; private const float key_icon_size = 10;
private const float key_icon_corner_radius = 3; private const float key_icon_corner_radius = 3;
public ManiaAction Action; private readonly IBindable<ManiaAction> action = new Bindable<ManiaAction>();
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>(); private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
private Container keyIcon; private Container keyIcon;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(IScrollingInfo scrollingInfo) private void load(IBindable<ManiaAction> action, IScrollingInfo scrollingInfo)
{ {
this.action.BindTo(action);
Drawable gradient; Drawable gradient;
InternalChildren = new[] InternalChildren = new[]
@ -107,14 +108,14 @@ namespace osu.Game.Rulesets.Mania.UI.Components
public bool OnPressed(ManiaAction action) public bool OnPressed(ManiaAction action)
{ {
if (action == Action) if (action == this.action.Value)
keyIcon.ScaleTo(1.4f, 50, Easing.OutQuint).Then().ScaleTo(1.3f, 250, Easing.OutQuint); keyIcon.ScaleTo(1.4f, 50, Easing.OutQuint).Then().ScaleTo(1.3f, 250, Easing.OutQuint);
return false; return false;
} }
public bool OnReleased(ManiaAction action) public bool OnReleased(ManiaAction action)
{ {
if (action == Action) if (action == this.action.Value)
keyIcon.ScaleTo(1f, 125, Easing.OutQuint); keyIcon.ScaleTo(1f, 125, Easing.OutQuint);
return false; return false;
} }

View File

@ -101,17 +101,15 @@ namespace osu.Game.Rulesets.Mania.UI
protected override DrawableHitObject<ManiaHitObject> GetVisualRepresentation(ManiaHitObject h) protected override DrawableHitObject<ManiaHitObject> GetVisualRepresentation(ManiaHitObject h)
{ {
ManiaAction action = Playfield.Columns.ElementAt(h.Column).Action; switch (h)
{
var holdNote = h as HoldNote; case HoldNote holdNote:
if (holdNote != null) return new DrawableHoldNote(holdNote);
return new DrawableHoldNote(holdNote, action); case Note note:
return new DrawableNote(note);
var note = h as Note; default:
if (note != null) return null;
return new DrawableNote(note, action); }
return null;
} }
protected override Vector2 PlayfieldArea => new Vector2(1, 0.8f); protected override Vector2 PlayfieldArea => new Vector2(1, 0.8f);

View File

@ -127,7 +127,7 @@ namespace osu.Game.Rulesets.Mania.UI
var column = new Column(direction) var column = new Column(direction)
{ {
IsSpecial = isSpecial, IsSpecial = isSpecial,
Action = isSpecial ? specialColumnStartAction++ : normalColumnStartAction++ Action = { Value = isSpecial ? specialColumnStartAction++ : normalColumnStartAction++ }
}; };
AddColumn(column); AddColumn(column);

View File

@ -15,10 +15,10 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
{ {
} }
public override void PostProcess() public override void PreProcess()
{ {
base.PreProcess();
applyStacking((Beatmap<OsuHitObject>)Beatmap); applyStacking((Beatmap<OsuHitObject>)Beatmap);
base.PostProcess();
} }
private void applyStacking(Beatmap<OsuHitObject> beatmap) private void applyStacking(Beatmap<OsuHitObject> beatmap)
@ -44,7 +44,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
continue; continue;
double endTime = (stackBaseObject as IHasEndTime)?.EndTime ?? stackBaseObject.StartTime; double endTime = (stackBaseObject as IHasEndTime)?.EndTime ?? stackBaseObject.StartTime;
double stackThreshold = objectN.TimePreempt * beatmap.BeatmapInfo?.StackLeniency ?? 0.7f; double stackThreshold = objectN.TimePreempt * beatmap.BeatmapInfo.StackLeniency;
if (objectN.StartTime - endTime > stackThreshold) if (objectN.StartTime - endTime > stackThreshold)
//We are no longer within stacking range of the next object. //We are no longer within stacking range of the next object.
@ -87,7 +87,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
OsuHitObject objectI = beatmap.HitObjects[i]; OsuHitObject objectI = beatmap.HitObjects[i];
if (objectI.StackHeight != 0 || objectI is Spinner) continue; if (objectI.StackHeight != 0 || objectI is Spinner) continue;
double stackThreshold = objectI.TimePreempt * beatmap.BeatmapInfo?.StackLeniency ?? 0.7f; double stackThreshold = objectI.TimePreempt * beatmap.BeatmapInfo.StackLeniency;
/* If this object is a hitcircle, then we enter this "special" case. /* If this object is a hitcircle, then we enter this "special" case.
* It either ends with a stack of hitcircles only, or a stack of hitcircles that are underneath a slider. * It either ends with a stack of hitcircles only, or a stack of hitcircles that are underneath a slider.

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 OpenTK;
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
@ -12,11 +11,6 @@ namespace osu.Game.Rulesets.Osu.Judgements
{ {
public override HitResult MaxResult => HitResult.Great; public override HitResult MaxResult => HitResult.Great;
/// <summary>
/// The positional hit offset.
/// </summary>
public Vector2 PositionOffset;
protected override int NumericResultFor(HitResult result) protected override int NumericResultFor(HitResult result)
{ {
switch (result) switch (result)

View File

@ -8,6 +8,7 @@ namespace osu.Game.Rulesets.Osu.Judgements
public class OsuSliderTailJudgement : OsuJudgement public class OsuSliderTailJudgement : OsuJudgement
{ {
public override bool AffectsCombo => false; public override bool AffectsCombo => false;
protected override int NumericResultFor(HitResult result) => 0; protected override int NumericResultFor(HitResult result) => 0;
} }
} }

View File

@ -93,7 +93,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
AddJudgement(new OsuJudgement AddJudgement(new OsuJudgement
{ {
Result = result, Result = result,
PositionOffset = Vector2.Zero //todo: set to correct value
}); });
} }

View File

@ -93,6 +93,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
base.AccentColour = value; base.AccentColour = value;
Body.AccentColour = AccentColour; Body.AccentColour = AccentColour;
Ball.AccentColour = AccentColour; Ball.AccentColour = AccentColour;
if (HasNestedHitObjects)
foreach (var drawableHitObject in NestedHitObjects)
drawableHitObject.AccentColour = AccentColour;
} }
} }

View File

@ -54,9 +54,9 @@ namespace osu.Game.Rulesets.Osu.Objects
public virtual bool NewCombo { get; set; } public virtual bool NewCombo { get; set; }
public int IndexInCurrentCombo { get; set; } public virtual int IndexInCurrentCombo { get; set; }
public int ComboIndex { get; set; } public virtual int ComboIndex { get; set; }
public bool LastInCombo { get; set; } public bool LastInCombo { get; set; }

View File

@ -26,6 +26,28 @@ namespace osu.Game.Rulesets.Osu.Objects
public Vector2 StackedPositionAt(double t) => StackedPosition + this.CurvePositionAt(t); public Vector2 StackedPositionAt(double t) => StackedPosition + this.CurvePositionAt(t);
public override Vector2 EndPosition => Position + this.CurvePositionAt(1); public override Vector2 EndPosition => Position + this.CurvePositionAt(1);
public override int ComboIndex
{
get => base.ComboIndex;
set
{
base.ComboIndex = value;
foreach (var n in NestedHitObjects.OfType<IHasComboInformation>())
n.ComboIndex = value;
}
}
public override int IndexInCurrentCombo
{
get => base.IndexInCurrentCombo;
set
{
base.IndexInCurrentCombo = value;
foreach (var n in NestedHitObjects.OfType<IHasComboInformation>())
n.IndexInCurrentCombo = value;
}
}
public SliderCurve Curve { get; } = new SliderCurve(); public SliderCurve Curve { get; } = new SliderCurve();
public List<Vector2> ControlPoints public List<Vector2> ControlPoints
@ -147,7 +169,8 @@ namespace osu.Game.Rulesets.Osu.Objects
var distanceProgress = d / length; var distanceProgress = d / length;
var timeProgress = reversed ? 1 - distanceProgress : distanceProgress; var timeProgress = reversed ? 1 - distanceProgress : distanceProgress;
var firstSample = Samples.FirstOrDefault(s => s.Name == SampleInfo.HIT_NORMAL) ?? Samples.FirstOrDefault(); // TODO: remove this when guaranteed sort is present for samples (https://github.com/ppy/osu/issues/1933) var firstSample = Samples.FirstOrDefault(s => s.Name == SampleInfo.HIT_NORMAL)
?? Samples.FirstOrDefault(); // TODO: remove this when guaranteed sort is present for samples (https://github.com/ppy/osu/issues/1933)
var sampleList = new List<SampleInfo>(); var sampleList = new List<SampleInfo>();
if (firstSample != null) if (firstSample != null)

View File

@ -11,7 +11,6 @@ using osu.Game.Rulesets.Osu.Objects.Drawables.Connections;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using System.Linq; using System.Linq;
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Osu.Judgements;
namespace osu.Game.Rulesets.Osu.UI namespace osu.Game.Rulesets.Osu.UI
{ {
@ -75,7 +74,7 @@ namespace osu.Game.Rulesets.Osu.UI
DrawableOsuJudgement explosion = new DrawableOsuJudgement(judgement, judgedObject) DrawableOsuJudgement explosion = new DrawableOsuJudgement(judgement, judgedObject)
{ {
Origin = Anchor.Centre, Origin = Anchor.Centre,
Position = ((OsuHitObject)judgedObject.HitObject).StackedEndPosition + ((OsuJudgement)judgement).PositionOffset Position = ((OsuHitObject)judgedObject.HitObject).StackedEndPosition
}; };
judgementLayer.Add(explosion); judgementLayer.Add(explosion);

View File

@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Taiko.UI
private void loadBarLines() private void loadBarLines()
{ {
TaikoHitObject lastObject = Beatmap.HitObjects[Beatmap.HitObjects.Count - 1]; TaikoHitObject lastObject = Beatmap.HitObjects[Beatmap.HitObjects.Count - 1];
double lastHitTime = 1 + (lastObject as IHasEndTime)?.EndTime ?? lastObject.StartTime; double lastHitTime = 1 + ((lastObject as IHasEndTime)?.EndTime ?? lastObject.StartTime);
var timingPoints = Beatmap.ControlPointInfo.TimingPoints.ToList(); var timingPoints = Beatmap.ControlPointInfo.TimingPoints.ToList();

View File

@ -1,6 +1,8 @@
// 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.ComponentModel; using System.ComponentModel;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
@ -17,6 +19,12 @@ namespace osu.Game.Tests.Visual
[Description("PlaySongSelect leaderboard")] [Description("PlaySongSelect leaderboard")]
public class TestCaseLeaderboard : OsuTestCase public class TestCaseLeaderboard : OsuTestCase
{ {
public override IReadOnlyList<Type> RequiredTypes => new[] {
typeof(Placeholder),
typeof(MessagePlaceholder),
typeof(RetrievalFailurePlaceholder),
};
private RulesetStore rulesets; private RulesetStore rulesets;
private readonly FailableLeaderboard leaderboard; private readonly FailableLeaderboard leaderboard;

View File

@ -66,8 +66,8 @@ namespace osu.Game.Beatmaps
// General // General
public int AudioLeadIn { get; set; } public int AudioLeadIn { get; set; }
public bool Countdown { get; set; } public bool Countdown { get; set; } = true;
public float StackLeniency { get; set; } public float StackLeniency { get; set; } = 0.7f;
public bool SpecialStyle { get; set; } public bool SpecialStyle { get; set; }
public int RulesetID { get; set; } public int RulesetID { get; set; }

View File

@ -138,7 +138,7 @@ namespace osu.Game.Beatmaps
PostNotification?.Invoke(new SimpleNotification PostNotification?.Invoke(new SimpleNotification
{ {
Icon = FontAwesome.fa_superpowers, Icon = FontAwesome.fa_superpowers,
Text = "You gotta be a supporter to download for now 'yo" Text = "You gotta be an osu!supporter to download for now 'yo"
}); });
return; return;
} }

View File

@ -69,11 +69,22 @@ namespace osu.Game.Beatmaps
} }
catch catch
{ {
return new TrackVirtual(); return null;
} }
} }
protected override Waveform GetWaveform() => new Waveform(store.GetStream(getPathForFile(Metadata.AudioFile))); protected override Waveform GetWaveform()
{
try
{
var trackData = store.GetStream(getPathForFile(Metadata.AudioFile));
return trackData == null ? null : new Waveform(trackData);
}
catch
{
return null;
}
}
protected override Storyboard GetStoryboard() protected override Storyboard GetStoryboard()
{ {

View File

@ -6,23 +6,9 @@ using osu.Game.Rulesets.Objects.Types;
namespace osu.Game.Beatmaps namespace osu.Game.Beatmaps
{ {
public interface IBeatmapProcessor
{
IBeatmap Beatmap { get; }
/// <summary>
/// Post-processes <see cref="Beatmap"/> to add mode-specific components that aren't added during conversion.
/// <para>
/// An example of such a usage is for combo colours.
/// </para>
/// </summary>
void PostProcess();
}
/// <summary> /// <summary>
/// Processes a post-converted Beatmap. /// Provides functionality to alter a <see cref="IBeatmap"/> after it has been converted.
/// </summary> /// </summary>
/// <typeparam name="TObject">The type of HitObject contained in the Beatmap.</typeparam>
public class BeatmapProcessor : IBeatmapProcessor public class BeatmapProcessor : IBeatmapProcessor
{ {
public IBeatmap Beatmap { get; } public IBeatmap Beatmap { get; }
@ -32,13 +18,7 @@ namespace osu.Game.Beatmaps
Beatmap = beatmap; Beatmap = beatmap;
} }
/// <summary> public virtual void PreProcess()
/// Post-processes a Beatmap to add mode-specific components that aren't added during conversion.
/// <para>
/// An example of such a usage is for combo colours.
/// </para>
/// </summary>
public virtual void PostProcess()
{ {
IHasComboInformation lastObj = null; IHasComboInformation lastObj = null;
@ -62,5 +42,9 @@ namespace osu.Game.Beatmaps
lastObj = obj; lastObj = obj;
} }
} }
public virtual void PostProcess()
{
}
} }
} }

View File

@ -13,7 +13,13 @@ namespace osu.Game.Beatmaps
[DatabaseGenerated(DatabaseGeneratedOption.Identity)] [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; } public int ID { get; set; }
public int? OnlineBeatmapSetID { get; set; } private int? onlineBeatmapSetID;
public int? OnlineBeatmapSetID
{
get { return onlineBeatmapSetID; }
set { onlineBeatmapSetID = value > 0 ? value : null; }
}
public BeatmapMetadata Metadata { get; set; } public BeatmapMetadata Metadata { get; set; }

View File

@ -45,7 +45,7 @@ namespace osu.Game.Beatmaps
protected override Texture GetBackground() => game?.Textures.Get(@"Backgrounds/bg4"); protected override Texture GetBackground() => game?.Textures.Get(@"Backgrounds/bg4");
protected override Track GetTrack() => new TrackVirtual(); protected override Track GetTrack() => new TrackVirtual { Length = 1000 };
private class DummyRulesetInfo : RulesetInfo private class DummyRulesetInfo : RulesetInfo
{ {

View File

@ -7,6 +7,9 @@ using osu.Game.Rulesets.Objects;
namespace osu.Game.Beatmaps namespace osu.Game.Beatmaps
{ {
/// <summary>
/// Provides functionality to convert a <see cref="IBeatmap"/> for a <see cref="Ruleset"/>.
/// </summary>
public interface IBeatmapConverter public interface IBeatmapConverter
{ {
/// <summary> /// <summary>

View File

@ -0,0 +1,40 @@
// 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.Beatmaps
{
/// <summary>
/// Provides functionality to alter a <see cref="IBeatmap"/> after it has been converted.
/// </summary>
public interface IBeatmapProcessor
{
/// <summary>
/// The <see cref="IBeatmap"/> to process. This should already be converted to the applicable <see cref="Ruleset"/>.
/// </summary>
IBeatmap Beatmap { get; }
/// <summary>
/// Processes the converted <see cref="Beatmap"/> prior to <see cref="HitObject.ApplyDefaults"/> being invoked.
/// <para>
/// Nested <see cref="HitObject"/>s generated during <see cref="HitObject.ApplyDefaults"/> will not be present by this point,
/// and no mods will have been applied to the <see cref="HitObject"/>s.
/// </para>
/// </summary>
/// <remarks>
/// This can only be used to add alterations to <see cref="HitObject"/>s generated directly through the conversion process.
/// </remarks>
void PreProcess();
/// <summary>
/// Processes the converted <see cref="Beatmap"/> after <see cref="HitObject.ApplyDefaults"/> has been invoked.
/// <para>
/// Nested <see cref="HitObject"/>s generated during <see cref="HitObject.ApplyDefaults"/> will be present by this point,
/// and mods will have been applied to all <see cref="HitObject"/>s.
/// </para>
/// </summary>
/// <remarks>
/// This should be used to add alterations to <see cref="HitObject"/>s while they are in their most playable state.
/// </remarks>
void PostProcess();
}
}

View File

@ -19,7 +19,7 @@ using osu.Game.Skinning;
namespace osu.Game.Beatmaps namespace osu.Game.Beatmaps
{ {
public abstract class WorkingBeatmap : IDisposable public abstract partial class WorkingBeatmap : IDisposable
{ {
public readonly BeatmapInfo BeatmapInfo; public readonly BeatmapInfo BeatmapInfo;
@ -116,6 +116,10 @@ namespace osu.Game.Beatmaps
mod.ApplyToDifficulty(converted.BeatmapInfo.BaseDifficulty); mod.ApplyToDifficulty(converted.BeatmapInfo.BaseDifficulty);
} }
IBeatmapProcessor processor = rulesetInstance.CreateBeatmapProcessor(converted);
processor?.PreProcess();
// Compute default values for hitobjects, including creating nested hitobjects in-case they're needed // Compute default values for hitobjects, including creating nested hitobjects in-case they're needed
foreach (var obj in converted.HitObjects) foreach (var obj in converted.HitObjects)
obj.ApplyDefaults(converted.ControlPointInfo, converted.BeatmapInfo.BaseDifficulty); obj.ApplyDefaults(converted.ControlPointInfo, converted.BeatmapInfo.BaseDifficulty);
@ -124,8 +128,7 @@ namespace osu.Game.Beatmaps
foreach (var obj in converted.HitObjects) foreach (var obj in converted.HitObjects)
mod.ApplyToHitObject(obj); mod.ApplyToHitObject(obj);
// Post-process processor?.PostProcess();
rulesetInstance.CreateBeatmapProcessor(converted)?.PostProcess();
return converted; return converted;
} }
@ -145,7 +148,7 @@ namespace osu.Game.Beatmaps
private Track populateTrack() private Track populateTrack()
{ {
// we want to ensure that we always have a track, even if it's a fake one. // we want to ensure that we always have a track, even if it's a fake one.
var t = GetTrack() ?? new TrackVirtual(); var t = GetTrack() ?? new VirtualBeatmapTrack(Beatmap);
applyRateAdjustments(t); applyRateAdjustments(t);
return t; return t;
} }

View File

@ -0,0 +1,38 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Linq;
using osu.Framework.Audio.Track;
using osu.Game.Rulesets.Objects.Types;
namespace osu.Game.Beatmaps
{
public partial class WorkingBeatmap
{
/// <summary>
/// A type of <see cref="TrackVirtual"/> which provides a valid length based on the <see cref="HitObject"/>s of an <see cref="IBeatmap"/>.
/// </summary>
protected class VirtualBeatmapTrack : TrackVirtual
{
private const double excess_length = 1000;
public VirtualBeatmapTrack(IBeatmap beatmap)
{
var lastObject = beatmap.HitObjects.LastOrDefault();
switch (lastObject)
{
case null:
Length = excess_length;
break;
case IHasEndTime endTime:
Length = endTime.EndTime + excess_length;
break;
default:
Length = lastObject.StartTime + excess_length;
break;
}
}
}
}
}

View File

@ -8,16 +8,20 @@ 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.Framework.Input.Bindings;
using osu.Game.Audio; using osu.Game.Audio;
using osu.Game.Input.Bindings;
using osu.Game.Overlays; using osu.Game.Overlays;
namespace osu.Game.Graphics.Containers namespace osu.Game.Graphics.Containers
{ {
public class OsuFocusedOverlayContainer : FocusedOverlayContainer, IPreviewTrackOwner public class OsuFocusedOverlayContainer : FocusedOverlayContainer, IPreviewTrackOwner, IKeyBindingHandler<GlobalAction>
{ {
private SampleChannel samplePopIn; private SampleChannel samplePopIn;
private SampleChannel samplePopOut; private SampleChannel samplePopOut;
protected virtual bool PlaySamplesOnStateChange => true;
private PreviewTrackManager previewTrackManager; private PreviewTrackManager previewTrackManager;
protected readonly Bindable<OverlayActivation> OverlayActivationMode = new Bindable<OverlayActivation>(OverlayActivation.All); protected readonly Bindable<OverlayActivation> OverlayActivationMode = new Bindable<OverlayActivation>(OverlayActivation.All);
@ -63,18 +67,33 @@ namespace osu.Game.Graphics.Containers
return base.OnClick(state); return base.OnClick(state);
} }
public bool OnPressed(GlobalAction action)
{
if (action == GlobalAction.Back)
{
State = Visibility.Hidden;
return true;
}
return false;
}
public bool OnReleased(GlobalAction action) => false;
private void onStateChanged(Visibility visibility) private void onStateChanged(Visibility visibility)
{ {
switch (visibility) switch (visibility)
{ {
case Visibility.Visible: case Visibility.Visible:
if (OverlayActivationMode != OverlayActivation.Disabled) if (OverlayActivationMode != OverlayActivation.Disabled)
samplePopIn?.Play(); {
if (PlaySamplesOnStateChange) samplePopIn?.Play();
}
else else
State = Visibility.Hidden; State = Visibility.Hidden;
break; break;
case Visibility.Hidden: case Visibility.Hidden:
samplePopOut?.Play(); if (PlaySamplesOnStateChange) samplePopOut?.Play();
break; break;
} }
} }

View File

@ -2,6 +2,7 @@
// 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;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
@ -16,6 +17,8 @@ namespace osu.Game.Graphics.Containers
protected override SpriteText CreateSpriteText() => new OsuSpriteText(); protected override SpriteText CreateSpriteText() => new OsuSpriteText();
public void AddArbitraryDrawable(Drawable drawable) => AddInternal(drawable);
public void AddIcon(FontAwesome icon, Action<SpriteText> creationParameters = null) => AddText(((char)icon).ToString(), creationParameters); public void AddIcon(FontAwesome icon, Action<SpriteText> creationParameters = null) => AddText(((char)icon).ToString(), creationParameters);
} }
} }

View File

@ -12,14 +12,14 @@ namespace osu.Game.Graphics
{ {
public class DrawableDate : OsuSpriteText, IHasTooltip public class DrawableDate : OsuSpriteText, IHasTooltip
{ {
private readonly DateTimeOffset date; protected readonly DateTimeOffset Date;
public DrawableDate(DateTimeOffset date) public DrawableDate(DateTimeOffset date)
{ {
AutoSizeAxes = Axes.Both; AutoSizeAxes = Axes.Both;
Font = "Exo2.0-RegularItalic"; Font = "Exo2.0-RegularItalic";
this.date = date.ToLocalTime(); Date = date.ToLocalTime();
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
@ -38,7 +38,7 @@ namespace osu.Game.Graphics
{ {
updateTime(); updateTime();
var diffToNow = DateTimeOffset.Now.Subtract(date); var diffToNow = DateTimeOffset.Now.Subtract(Date);
double timeUntilNextUpdate = 1000; double timeUntilNextUpdate = 1000;
if (diffToNow.TotalSeconds > 60) if (diffToNow.TotalSeconds > 60)
@ -58,8 +58,10 @@ namespace osu.Game.Graphics
public override bool HandleMouseInput => true; public override bool HandleMouseInput => true;
private void updateTime() => Text = date.Humanize(); protected virtual string Format() => Date.Humanize();
public string TooltipText => date.ToString(); private void updateTime() => Text = Format();
public virtual string TooltipText => string.Format($"{Date:MMMM d, yyyy h:mm tt \"UTC\"z}");
} }
} }

View File

@ -2,9 +2,10 @@
// 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 OpenTK.Graphics; using OpenTK.Graphics;
using OpenTK.Input;
using osu.Framework.Input; using osu.Framework.Input;
using System; using System;
using osu.Game.Input.Bindings;
using OpenTK.Input;
namespace osu.Game.Graphics.UserInterface namespace osu.Game.Graphics.UserInterface
{ {
@ -19,6 +20,7 @@ namespace osu.Game.Graphics.UserInterface
public Action Exit; public Action Exit;
private bool focus; private bool focus;
public bool HoldFocus public bool HoldFocus
{ {
get { return focus; } get { return focus; }
@ -26,7 +28,7 @@ namespace osu.Game.Graphics.UserInterface
{ {
focus = value; focus = value;
if (!focus && HasFocus) if (!focus && HasFocus)
GetContainingInputManager().ChangeFocus(null); base.KillFocus();
} }
} }
@ -41,18 +43,34 @@ namespace osu.Game.Graphics.UserInterface
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{ {
if (!args.Repeat && args.Key == Key.Escape) if (!HasFocus) return false;
{
if (Text.Length > 0) if (args.Key == Key.Escape)
Text = string.Empty; return false; // disable the framework-level handling of escape key for confority (we use GlobalAction.Back).
else
Exit?.Invoke();
return true;
}
return base.OnKeyDown(state, args); return base.OnKeyDown(state, args);
} }
public override bool OnPressed(GlobalAction action)
{
if (action == GlobalAction.Back)
{
if (Text.Length > 0)
{
Text = string.Empty;
return true;
}
}
return base.OnPressed(action);
}
protected override void KillFocus()
{
base.KillFocus();
Exit?.Invoke();
}
public override bool RequestsFocus => HoldFocus; public override bool RequestsFocus => HoldFocus;
} }
} }

View File

@ -18,7 +18,7 @@ namespace osu.Game.Graphics.UserInterface
{ {
protected override Drawable GetDrawableCharacter(char c) => new PasswordMaskChar(CalculatedTextSize); protected override Drawable GetDrawableCharacter(char c) => new PasswordMaskChar(CalculatedTextSize);
public override bool AllowClipboardExport => false; protected override bool AllowClipboardExport => false;
private readonly CapsWarning warning; private readonly CapsWarning warning;

View File

@ -9,10 +9,12 @@ using osu.Framework.Input;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using OpenTK.Graphics; using OpenTK.Graphics;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Input.Bindings;
using osu.Game.Input.Bindings;
namespace osu.Game.Graphics.UserInterface namespace osu.Game.Graphics.UserInterface
{ {
public class OsuTextBox : TextBox public class OsuTextBox : TextBox, IKeyBindingHandler<GlobalAction>
{ {
protected override Color4 BackgroundUnfocused => Color4.Black.Opacity(0.5f); protected override Color4 BackgroundUnfocused => Color4.Black.Opacity(0.5f);
protected override Color4 BackgroundFocused => OsuColour.Gray(0.3f).Opacity(0.8f); protected override Color4 BackgroundFocused => OsuColour.Gray(0.3f).Opacity(0.8f);
@ -33,10 +35,7 @@ namespace osu.Game.Graphics.UserInterface
TextContainer.Height = 0.5f; TextContainer.Height = 0.5f;
CornerRadius = 5; CornerRadius = 5;
Current.DisabledChanged += disabled => Current.DisabledChanged += disabled => { Alpha = disabled ? 0.3f : 1; };
{
Alpha = disabled ? 0.3f : 1;
};
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
@ -59,5 +58,18 @@ namespace osu.Game.Graphics.UserInterface
} }
protected override Drawable GetDrawableCharacter(char c) => new OsuSpriteText { Text = c.ToString(), TextSize = CalculatedTextSize }; protected override Drawable GetDrawableCharacter(char c) => new OsuSpriteText { Text = c.ToString(), TextSize = CalculatedTextSize };
public virtual bool OnPressed(GlobalAction action)
{
if (action == GlobalAction.Back)
{
KillFocus();
return true;
}
return false;
}
public bool OnReleased(GlobalAction action) => false;
} }
} }

View File

@ -34,8 +34,6 @@ namespace osu.Game.Graphics.UserInterface
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{ {
if (HandlePendingText(state)) return true;
if (!state.Keyboard.ControlPressed && !state.Keyboard.ShiftPressed) if (!state.Keyboard.ControlPressed && !state.Keyboard.ShiftPressed)
{ {
switch (args.Key) switch (args.Key)

View File

@ -0,0 +1,376 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using osu.Game.Database;
namespace osu.Game.Migrations
{
[DbContext(typeof(OsuDbContext))]
[Migration("20180628011956_RemoveNegativeSetIDs")]
partial class RemoveNegativeSetIDs
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "2.1.1-rtm-30846");
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd();
b.Property<float>("ApproachRate");
b.Property<float>("CircleSize");
b.Property<float>("DrainRate");
b.Property<float>("OverallDifficulty");
b.Property<double>("SliderMultiplier");
b.Property<double>("SliderTickRate");
b.HasKey("ID");
b.ToTable("BeatmapDifficulty");
});
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd();
b.Property<int>("AudioLeadIn");
b.Property<int>("BaseDifficultyID");
b.Property<int>("BeatDivisor");
b.Property<int>("BeatmapSetInfoID");
b.Property<bool>("Countdown");
b.Property<double>("DistanceSpacing");
b.Property<int>("GridSize");
b.Property<string>("Hash");
b.Property<bool>("Hidden");
b.Property<bool>("LetterboxInBreaks");
b.Property<string>("MD5Hash");
b.Property<int?>("MetadataID");
b.Property<int?>("OnlineBeatmapID");
b.Property<string>("Path");
b.Property<int>("RulesetID");
b.Property<bool>("SpecialStyle");
b.Property<float>("StackLeniency");
b.Property<double>("StarDifficulty");
b.Property<string>("StoredBookmarks");
b.Property<double>("TimelineZoom");
b.Property<string>("Version");
b.Property<bool>("WidescreenStoryboard");
b.HasKey("ID");
b.HasIndex("BaseDifficultyID");
b.HasIndex("BeatmapSetInfoID");
b.HasIndex("Hash");
b.HasIndex("MD5Hash");
b.HasIndex("MetadataID");
b.HasIndex("OnlineBeatmapID")
.IsUnique();
b.HasIndex("RulesetID");
b.ToTable("BeatmapInfo");
});
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd();
b.Property<string>("Artist");
b.Property<string>("ArtistUnicode");
b.Property<string>("AudioFile");
b.Property<string>("AuthorString")
.HasColumnName("Author");
b.Property<string>("BackgroundFile");
b.Property<int>("PreviewTime");
b.Property<string>("Source");
b.Property<string>("Tags");
b.Property<string>("Title");
b.Property<string>("TitleUnicode");
b.HasKey("ID");
b.ToTable("BeatmapMetadata");
});
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd();
b.Property<int>("BeatmapSetInfoID");
b.Property<int>("FileInfoID");
b.Property<string>("Filename")
.IsRequired();
b.HasKey("ID");
b.HasIndex("BeatmapSetInfoID");
b.HasIndex("FileInfoID");
b.ToTable("BeatmapSetFileInfo");
});
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd();
b.Property<bool>("DeletePending");
b.Property<string>("Hash");
b.Property<int?>("MetadataID");
b.Property<int?>("OnlineBeatmapSetID");
b.Property<bool>("Protected");
b.HasKey("ID");
b.HasIndex("DeletePending");
b.HasIndex("Hash")
.IsUnique();
b.HasIndex("MetadataID");
b.HasIndex("OnlineBeatmapSetID")
.IsUnique();
b.ToTable("BeatmapSetInfo");
});
modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd();
b.Property<int>("IntKey")
.HasColumnName("Key");
b.Property<int?>("RulesetID");
b.Property<string>("StringValue")
.HasColumnName("Value");
b.Property<int?>("Variant");
b.HasKey("ID");
b.HasIndex("RulesetID", "Variant");
b.ToTable("Settings");
});
modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd();
b.Property<int>("IntAction")
.HasColumnName("Action");
b.Property<string>("KeysString")
.HasColumnName("Keys");
b.Property<int?>("RulesetID");
b.Property<int?>("Variant");
b.HasKey("ID");
b.HasIndex("IntAction");
b.HasIndex("RulesetID", "Variant");
b.ToTable("KeyBinding");
});
modelBuilder.Entity("osu.Game.IO.FileInfo", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd();
b.Property<string>("Hash");
b.Property<int>("ReferenceCount");
b.HasKey("ID");
b.HasIndex("Hash")
.IsUnique();
b.HasIndex("ReferenceCount");
b.ToTable("FileInfo");
});
modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b =>
{
b.Property<int?>("ID")
.ValueGeneratedOnAdd();
b.Property<bool>("Available");
b.Property<string>("InstantiationInfo");
b.Property<string>("Name");
b.Property<string>("ShortName");
b.HasKey("ID");
b.HasIndex("Available");
b.HasIndex("ShortName")
.IsUnique();
b.ToTable("RulesetInfo");
});
modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd();
b.Property<int>("FileInfoID");
b.Property<string>("Filename")
.IsRequired();
b.Property<int>("SkinInfoID");
b.HasKey("ID");
b.HasIndex("FileInfoID");
b.HasIndex("SkinInfoID");
b.ToTable("SkinFileInfo");
});
modelBuilder.Entity("osu.Game.Skinning.SkinInfo", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd();
b.Property<string>("Creator");
b.Property<bool>("DeletePending");
b.Property<string>("Name");
b.HasKey("ID");
b.ToTable("SkinInfo");
});
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b =>
{
b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty")
.WithMany()
.HasForeignKey("BaseDifficultyID")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet")
.WithMany("Beatmaps")
.HasForeignKey("BeatmapSetInfoID")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata")
.WithMany("Beatmaps")
.HasForeignKey("MetadataID");
b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset")
.WithMany()
.HasForeignKey("RulesetID")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b =>
{
b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo")
.WithMany("Files")
.HasForeignKey("BeatmapSetInfoID")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("osu.Game.IO.FileInfo", "FileInfo")
.WithMany()
.HasForeignKey("FileInfoID")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b =>
{
b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata")
.WithMany("BeatmapSets")
.HasForeignKey("MetadataID");
});
modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b =>
{
b.HasOne("osu.Game.IO.FileInfo", "FileInfo")
.WithMany()
.HasForeignKey("FileInfoID")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("osu.Game.Skinning.SkinInfo")
.WithMany("Files")
.HasForeignKey("SkinInfoID")
.OnDelete(DeleteBehavior.Cascade);
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,19 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace osu.Game.Migrations
{
public partial class RemoveNegativeSetIDs : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
// There was a change that baetmaps were being loaded with "-1" online IDs, which is completely incorrect.
// This ensures there will not be unique key conflicts as a result of these incorrectly imported beatmaps.
migrationBuilder.Sql("UPDATE BeatmapSetInfo SET OnlineBeatmapSetID = null WHERE OnlineBeatmapSetID <= 0");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
}
}
}

View File

@ -85,7 +85,7 @@ namespace osu.Game
private OnScreenDisplay onscreenDisplay; private OnScreenDisplay onscreenDisplay;
private Bindable<int> configRuleset; private Bindable<int> configRuleset;
public Bindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>(); private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>();
private Bindable<int> configSkin; private Bindable<int> configSkin;
@ -147,10 +147,13 @@ namespace osu.Game
dependencies.CacheAs(this); dependencies.CacheAs(this);
dependencies.CacheAs(ruleset);
dependencies.CacheAs<IBindable<RulesetInfo>>(ruleset);
// bind config int to database RulesetInfo // bind config int to database RulesetInfo
configRuleset = LocalConfig.GetBindable<int>(OsuSetting.Ruleset); configRuleset = LocalConfig.GetBindable<int>(OsuSetting.Ruleset);
Ruleset.Value = RulesetStore.GetRuleset(configRuleset.Value) ?? RulesetStore.AvailableRulesets.First(); ruleset.Value = RulesetStore.GetRuleset(configRuleset.Value) ?? RulesetStore.AvailableRulesets.First();
Ruleset.ValueChanged += r => configRuleset.Value = r.ID ?? 0; ruleset.ValueChanged += r => configRuleset.Value = r.ID ?? 0;
// bind config int to database SkinInfo // bind config int to database SkinInfo
configSkin = LocalConfig.GetBindable<int>(OsuSetting.Skin); configSkin = LocalConfig.GetBindable<int>(OsuSetting.Skin);
@ -216,7 +219,7 @@ namespace osu.Game
return; return;
} }
Ruleset.Value = s.Ruleset; ruleset.Value = s.Ruleset;
Beatmap.Value = BeatmapManager.GetWorkingBeatmap(s.Beatmap); Beatmap.Value = BeatmapManager.GetWorkingBeatmap(s.Beatmap);
Beatmap.Value.Mods.Value = s.Mods; Beatmap.Value.Mods.Value = s.Mods;
@ -550,7 +553,7 @@ namespace osu.Game
// the use case for not applying is in visual/unit tests. // the use case for not applying is in visual/unit tests.
bool applyRestrictions = !currentScreen?.AllowBeatmapRulesetChange ?? false; bool applyRestrictions = !currentScreen?.AllowBeatmapRulesetChange ?? false;
Ruleset.Disabled = applyRestrictions; ruleset.Disabled = applyRestrictions;
Beatmap.Disabled = applyRestrictions; Beatmap.Disabled = applyRestrictions;
mainContent.Padding = new MarginPadding { Top = ToolbarOffset }; mainContent.Padding = new MarginPadding { Top = ToolbarOffset };

View File

@ -30,6 +30,8 @@ namespace osu.Game.Overlays
State = Visibility.Visible; State = Visibility.Visible;
} }
protected override bool PlaySamplesOnStateChange => false;
private void onDialogOnStateChanged(VisibilityContainer dialog, Visibility v) private void onDialogOnStateChanged(VisibilityContainer dialog, Visibility v)
{ {
if (v != Visibility.Hidden) return; if (v != Visibility.Hidden) return;

View File

@ -35,15 +35,13 @@ namespace osu.Game.Overlays.Direct
} }
[BackgroundDependencyLoader(true)] [BackgroundDependencyLoader(true)]
private void load(OsuGame game, RulesetStore rulesets, OsuColour colours) private void load(RulesetStore rulesets, OsuColour colours, Bindable<RulesetInfo> ruleset)
{ {
DisplayStyleControl.Dropdown.AccentColour = colours.BlueDark; DisplayStyleControl.Dropdown.AccentColour = colours.BlueDark;
Ruleset.Value = game?.Ruleset.Value ?? rulesets.GetRuleset(0); Ruleset.Value = ruleset ?? rulesets.GetRuleset(0);
foreach (var r in rulesets.AvailableRulesets) foreach (var r in rulesets.AvailableRulesets)
{
modeButtons.Add(new RulesetToggleButton(Ruleset, r)); modeButtons.Add(new RulesetToggleButton(Ruleset, r));
}
} }
private class RulesetToggleButton : OsuClickableContainer private class RulesetToggleButton : OsuClickableContainer

View File

@ -202,9 +202,6 @@ namespace osu.Game.Overlays.KeyBinding
switch (args.Key) switch (args.Key)
{ {
case Key.Escape:
finalise();
return true;
case Key.Delete: case Key.Delete:
{ {
if (state.Keyboard.ShiftPressed) if (state.Keyboard.ShiftPressed)

View File

@ -52,7 +52,7 @@ namespace osu.Game.Overlays.Mods
} }
[BackgroundDependencyLoader(permitNulls: true)] [BackgroundDependencyLoader(permitNulls: true)]
private void load(OsuColour colours, OsuGame osu, RulesetStore rulesets, AudioManager audio) private void load(OsuColour colours, Bindable<RulesetInfo> ruleset, RulesetStore rulesets, AudioManager audio)
{ {
SelectedMods.ValueChanged += selectedModsChanged; SelectedMods.ValueChanged += selectedModsChanged;
@ -60,8 +60,8 @@ namespace osu.Game.Overlays.Mods
HighMultiplierColour = colours.Green; HighMultiplierColour = colours.Green;
UnrankedLabel.Colour = colours.Blue; UnrankedLabel.Colour = colours.Blue;
if (osu != null) if (ruleset != null)
Ruleset.BindTo(osu.Ruleset); Ruleset.BindTo(ruleset);
else else
Ruleset.Value = rulesets.AvailableRulesets.First(); Ruleset.Value = rulesets.AvailableRulesets.First();

View File

@ -0,0 +1,20 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Game.Graphics;
namespace osu.Game.Overlays.Profile.Components
{
public class DrawableJoinDate : DrawableDate
{
public DrawableJoinDate(DateTimeOffset date)
: base(date)
{
}
protected override string Format() => Text = Date.ToUniversalTime().Year < 2008 ? "Here since the beginning" : $"{Date:MMMM yyyy}";
public override string TooltipText => $"{Date:MMMM d, yyyy}";
}
}

View File

@ -0,0 +1,50 @@
// 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.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Overlays.Profile.Components
{
public class GradeBadge : Container
{
private const float width = 50;
private readonly string grade;
private readonly Sprite badge;
private readonly SpriteText numberText;
public int DisplayCount
{
set => numberText.Text = value.ToString(@"#,0");
}
public GradeBadge(string grade)
{
this.grade = grade;
Width = width;
Height = 41;
Add(badge = new Sprite
{
Width = width,
Height = 26
});
Add(numberText = new OsuSpriteText
{
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
TextSize = 14,
Font = @"Exo2.0-Bold"
});
}
[BackgroundDependencyLoader]
private void load(TextureStore textures)
{
badge.Texture = textures.Get($"Grades/{grade}");
}
}
}

View File

@ -16,6 +16,7 @@ using osu.Game.Graphics;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Overlays.Profile.Components;
using osu.Game.Overlays.Profile.Header; using osu.Game.Overlays.Profile.Header;
using osu.Game.Users; using osu.Game.Users;
@ -375,12 +376,12 @@ namespace osu.Game.Overlays.Profile
if (user.JoinDate.ToUniversalTime().Year < 2008) if (user.JoinDate.ToUniversalTime().Year < 2008)
{ {
infoTextLeft.AddText("Here since the beginning", boldItalic); infoTextLeft.AddText(new DrawableJoinDate(user.JoinDate), lightText);
} }
else else
{ {
infoTextLeft.AddText("Joined ", lightText); infoTextLeft.AddText("Joined ", lightText);
infoTextLeft.AddText(new DrawableDate(user.JoinDate), boldItalic); infoTextLeft.AddText(new DrawableJoinDate(user.JoinDate), boldItalic);
} }
infoTextLeft.NewLine(); infoTextLeft.NewLine();
@ -470,43 +471,5 @@ namespace osu.Game.Overlays.Profile
infoTextRight.NewLine(); infoTextRight.NewLine();
} }
private class GradeBadge : Container
{
private const float width = 50;
private readonly string grade;
private readonly Sprite badge;
private readonly SpriteText numberText;
public int DisplayCount
{
set { numberText.Text = value.ToString(@"#,0"); }
}
public GradeBadge(string grade)
{
this.grade = grade;
Width = width;
Height = 41;
Add(badge = new Sprite
{
Width = width,
Height = 26
});
Add(numberText = new OsuSpriteText
{
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
TextSize = 14,
Font = @"Exo2.0-Bold"
});
}
[BackgroundDependencyLoader]
private void load(TextureStore textures)
{
badge.Texture = textures.Get($"Grades/{grade}");
}
}
} }
} }

View File

@ -141,11 +141,11 @@ namespace osu.Game.Overlays.Profile.Sections.Recent
break; break;
case RecentActivityType.UserSupportFirst: case RecentActivityType.UserSupportFirst:
message = $"{userLinkTemplate()} has become an osu! supporter - thanks for your generosity!"; message = $"{userLinkTemplate()} has become an osu!supporter - thanks for your generosity!";
break; break;
case RecentActivityType.UserSupportGift: case RecentActivityType.UserSupportGift:
message = $"{userLinkTemplate()} has received the gift of osu! supporter!"; message = $"{userLinkTemplate()} has received the gift of osu!supporter!";
break; break;
case RecentActivityType.UsernameChange: case RecentActivityType.UsernameChange:

View File

@ -68,7 +68,7 @@ namespace osu.Game.Overlays.Toolbar
} }
[BackgroundDependencyLoader(true)] [BackgroundDependencyLoader(true)]
private void load(RulesetStore rulesets, OsuGame game) private void load(RulesetStore rulesets, Bindable<RulesetInfo> parentRuleset)
{ {
this.rulesets = rulesets; this.rulesets = rulesets;
foreach (var r in rulesets.AvailableRulesets) foreach (var r in rulesets.AvailableRulesets)
@ -83,8 +83,8 @@ namespace osu.Game.Overlays.Toolbar
ruleset.ValueChanged += rulesetChanged; ruleset.ValueChanged += rulesetChanged;
ruleset.DisabledChanged += disabledChanged; ruleset.DisabledChanged += disabledChanged;
if (game != null) if (parentRuleset != null)
ruleset.BindTo(game.Ruleset); ruleset.BindTo(parentRuleset);
else else
ruleset.Value = rulesets.AvailableRulesets.FirstOrDefault(); ruleset.Value = rulesets.AvailableRulesets.FirstOrDefault();
} }

View File

@ -45,11 +45,15 @@ namespace osu.Game.Rulesets.Judgements
public double TimeOffset { get; set; } public double TimeOffset { get; set; }
/// <summary> /// <summary>
/// Whether the <see cref="Result"/> should affect the combo portion of the score. /// Whether the <see cref="Result"/> should affect the current combo.
/// If false, the <see cref="Result"/> will be considered for the bonus portion of the score.
/// </summary> /// </summary>
public virtual bool AffectsCombo => true; public virtual bool AffectsCombo => true;
/// <summary>
/// Whether the <see cref="Result"/> should be counted as base (combo) or bonus score.
/// </summary>
public virtual bool IsBonus => !AffectsCombo;
/// <summary> /// <summary>
/// The numeric representation for the result achieved. /// The numeric representation for the result achieved.
/// </summary> /// </summary>

View File

@ -1,26 +0,0 @@
// 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.Rulesets.Objects.Types
{
/// <summary>
/// A HitObject that is part of a combo and has extended information about its position relative to other combo objects.
/// </summary>
public interface IHasComboIndex : IHasCombo
{
/// <summary>
/// The offset of this hitobject in the current combo.
/// </summary>
int IndexInCurrentCombo { get; set; }
/// <summary>
/// The offset of this hitobject in the current combo.
/// </summary>
int ComboIndex { get; set; }
/// <summary>
/// Whether this is the last object in the current combo.
/// </summary>
bool LastInCombo { get; set; }
}
}

View File

@ -57,8 +57,18 @@ namespace osu.Game.Rulesets
/// <returns></returns> /// <returns></returns>
public abstract RulesetContainer CreateRulesetContainerWith(WorkingBeatmap beatmap); public abstract RulesetContainer CreateRulesetContainerWith(WorkingBeatmap beatmap);
/// <summary>
/// Creates a <see cref="IBeatmapConverter"/> to convert a <see cref="IBeatmap"/> to one that is applicable for this <see cref="Ruleset"/>.
/// </summary>
/// <param name="beatmap">The <see cref="IBeatmap"/> to be converted.</param>
/// <returns>The <see cref="IBeatmapConverter"/>.</returns>
public abstract IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap); public abstract IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap);
/// <summary>
/// Optionally creates a <see cref="IBeatmapProcessor"/> to alter a <see cref="IBeatmap"/> after it has been converted.
/// </summary>
/// <param name="beatmap">The <see cref="IBeatmap"/> to be processed.</param>
/// <returns>The <see cref="IBeatmapProcessor"/>.</returns>
public virtual IBeatmapProcessor CreateBeatmapProcessor(IBeatmap beatmap) => null; public virtual IBeatmapProcessor CreateBeatmapProcessor(IBeatmap beatmap) => null;
public abstract DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap); public abstract DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap);

View File

@ -84,10 +84,17 @@ namespace osu.Game.Rulesets
{ {
try try
{ {
var instance = r.CreateInstance(); var instanceInfo = ((Ruleset)Activator.CreateInstance(Type.GetType(r.InstantiationInfo, asm =>
{
// for the time being, let's ignore the version being loaded.
// this allows for debug builds to successfully load rulesets (even though debug rulesets have a 0.0.0 version).
asm.Version = null;
return Assembly.Load(asm);
}, null), (RulesetInfo)null)).RulesetInfo;
r.Name = instance.Description; r.Name = instanceInfo.Name;
r.ShortName = instance.ShortName; r.ShortName = instanceInfo.ShortName;
r.InstantiationInfo = instanceInfo.InstantiationInfo;
r.Available = true; r.Available = true;
} }

View File

@ -261,13 +261,19 @@ namespace osu.Game.Rulesets.Scoring
break; break;
} }
baseScore += judgement.NumericResult;
rollingMaxBaseScore += judgement.MaxNumericResult;
JudgedHits++; JudgedHits++;
} }
else if (judgement.IsHit)
bonusScore += judgement.NumericResult; if (judgement.IsBonus)
{
if (judgement.IsHit)
bonusScore += judgement.NumericResult;
}
else
{
baseScore += judgement.NumericResult;
rollingMaxBaseScore += judgement.MaxNumericResult;
}
} }
/// <summary> /// <summary>
@ -280,14 +286,18 @@ namespace osu.Game.Rulesets.Scoring
HighestCombo.Value = judgement.HighestComboAtJudgement; HighestCombo.Value = judgement.HighestComboAtJudgement;
if (judgement.AffectsCombo) if (judgement.AffectsCombo)
JudgedHits--;
if (judgement.IsBonus)
{
if (judgement.IsHit)
bonusScore -= judgement.NumericResult;
}
else
{ {
baseScore -= judgement.NumericResult; baseScore -= judgement.NumericResult;
rollingMaxBaseScore -= judgement.MaxNumericResult; rollingMaxBaseScore -= judgement.MaxNumericResult;
JudgedHits--;
} }
else if (judgement.IsHit)
bonusScore -= judgement.NumericResult;
} }
private void updateScore() private void updateScore()

View File

@ -52,8 +52,6 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts
if (Beatmap.Value == null) if (Beatmap.Value == null)
return; return;
if (Beatmap.Value.Track.Length == double.PositiveInfinity) return;
float markerPos = MathHelper.Clamp(ToLocalSpace(screenPosition).X, 0, DrawWidth); float markerPos = MathHelper.Clamp(ToLocalSpace(screenPosition).X, 0, DrawWidth);
adjustableClock.Seek(markerPos / DrawWidth * Beatmap.Value.Track.Length); adjustableClock.Seek(markerPos / DrawWidth * Beatmap.Value.Track.Length);
} }

View File

@ -47,8 +47,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts
return; return;
} }
// Todo: This should be handled more gracefully timeline.RelativeChildSize = new Vector2((float)Math.Max(1, Beatmap.Value.Track.Length), 1);
timeline.RelativeChildSize = Beatmap.Value.Track.Length == double.PositiveInfinity ? Vector2.One : new Vector2((float)Math.Max(1, Beatmap.Value.Track.Length), 1);
} }
protected void Add(Drawable visualisation) => timeline.Add(visualisation); protected void Add(Drawable visualisation) => timeline.Add(visualisation);

View File

@ -52,13 +52,11 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline
WaveformVisible.ValueChanged += visible => waveform.FadeTo(visible ? 1 : 0, 200, Easing.OutQuint); WaveformVisible.ValueChanged += visible => waveform.FadeTo(visible ? 1 : 0, 200, Easing.OutQuint);
Beatmap.BindTo(beatmap); Beatmap.BindTo(beatmap);
} Beatmap.BindValueChanged(b =>
{
protected override void LoadComplete() waveform.Waveform = b.Waveform;
{ track = b.Track;
base.LoadComplete(); }, true);
Beatmap.BindValueChanged(b => waveform.Waveform = b.Waveform);
waveform.Waveform = Beatmap.Value.Waveform;
} }
/// <summary> /// <summary>
@ -81,6 +79,8 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline
/// </summary> /// </summary>
private bool trackWasPlaying; private bool trackWasPlaying;
private Track track;
protected override void Update() protected override void Update()
{ {
base.Update(); base.Update();
@ -118,21 +118,18 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline
private void seekTrackToCurrent() private void seekTrackToCurrent()
{ {
var track = Beatmap.Value.Track; if (!track.IsLoaded)
if (track is TrackVirtual || !track.IsLoaded)
return; return;
if (!(Beatmap.Value.Track is TrackVirtual)) adjustableClock.Seek(Current / Content.DrawWidth * track.Length);
adjustableClock.Seek(Current / Content.DrawWidth * Beatmap.Value.Track.Length);
} }
private void scrollToTrackTime() private void scrollToTrackTime()
{ {
var track = Beatmap.Value.Track; if (!track.IsLoaded)
if (track is TrackVirtual || !track.IsLoaded)
return; return;
ScrollTo((float)(adjustableClock.CurrentTime / Beatmap.Value.Track.Length) * Content.DrawWidth, false); ScrollTo((float)(adjustableClock.CurrentTime / track.Length) * Content.DrawWidth, false);
} }
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)

View File

@ -148,8 +148,6 @@ namespace osu.Game.Screens.Menu
case Key.Space: case Key.Space:
logo?.TriggerOnClick(state); logo?.TriggerOnClick(state);
return true; return true;
case Key.Escape:
return goBack();
} }
return false; return false;
@ -181,16 +179,7 @@ namespace osu.Game.Screens.Menu
} }
} }
public bool OnReleased(GlobalAction action) public bool OnReleased(GlobalAction action) => false;
{
switch (action)
{
case GlobalAction.Back:
return true;
default:
return false;
}
}
private void onPlay() private void onPlay()
{ {

View File

@ -1,34 +1,34 @@
// 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.Input; using osu.Framework.Input.Bindings;
using osu.Game.Input.Bindings;
using osu.Game.Overlays; using osu.Game.Overlays;
using OpenTK.Input;
namespace osu.Game.Screens.Menu namespace osu.Game.Screens.Menu
{ {
public class ExitConfirmOverlay : HoldToConfirmOverlay public class ExitConfirmOverlay : HoldToConfirmOverlay, IKeyBindingHandler<GlobalAction>
{ {
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) public bool OnPressed(GlobalAction action)
{ {
if (args.Key == Key.Escape && !args.Repeat) if (action == GlobalAction.Back)
{ {
BeginConfirm(); BeginConfirm();
return true; return true;
} }
return base.OnKeyDown(state, args); return false;
} }
protected override bool OnKeyUp(InputState state, KeyUpEventArgs args) public bool OnReleased(GlobalAction action)
{ {
if (args.Key == Key.Escape) if (action == GlobalAction.Back)
{ {
AbortConfirm(); AbortConfirm();
return true; return true;
} }
return base.OnKeyUp(state, args); return false;
} }
} }
} }

View File

@ -8,7 +8,6 @@ using osu.Framework.Audio;
using osu.Framework.Audio.Sample; using osu.Framework.Audio.Sample;
using osu.Framework.Configuration; using osu.Framework.Configuration;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Input;
using osu.Framework.Input.Bindings; using osu.Framework.Input.Bindings;
using osu.Framework.Screens; using osu.Framework.Screens;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
@ -17,7 +16,6 @@ using osu.Game.Input.Bindings;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Screens.Menu; using osu.Game.Screens.Menu;
using OpenTK; using OpenTK;
using OpenTK.Input;
using osu.Game.Overlays; using osu.Game.Overlays;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
@ -82,22 +80,24 @@ namespace osu.Game.Screens
private SampleChannel sampleExit; private SampleChannel sampleExit;
[BackgroundDependencyLoader(true)] [BackgroundDependencyLoader(true)]
private void load(BindableBeatmap beatmap, OsuGame osuGame, AudioManager audio) private void load(BindableBeatmap beatmap, OsuGame osu, AudioManager audio, Bindable<RulesetInfo> ruleset)
{ {
if (beatmap != null) if (beatmap != null)
Beatmap.BindTo(beatmap); Beatmap.BindTo(beatmap);
if (osuGame != null) if (ruleset != null)
Ruleset.BindTo(ruleset);
if (osu != null)
{ {
Ruleset.BindTo(osuGame.Ruleset); OverlayActivationMode.BindTo(osu.OverlayActivationMode);
OverlayActivationMode.BindTo(osuGame.OverlayActivationMode);
updateOverlayStates = () => updateOverlayStates = () =>
{ {
if (HideOverlaysOnEnter) if (HideOverlaysOnEnter)
osuGame.CloseAllOverlays(); osu.CloseAllOverlays();
else else
osuGame.Toolbar.State = Visibility.Visible; osu.Toolbar.State = Visibility.Visible;
}; };
} }
@ -106,6 +106,8 @@ namespace osu.Game.Screens
public bool OnPressed(GlobalAction action) public bool OnPressed(GlobalAction action)
{ {
if (!IsCurrentScreen) return false;
if (action == GlobalAction.Back && AllowBackButton) if (action == GlobalAction.Back && AllowBackButton)
{ {
Exit(); Exit();
@ -117,20 +119,6 @@ namespace osu.Game.Screens
public bool OnReleased(GlobalAction action) => action == GlobalAction.Back && AllowBackButton; public bool OnReleased(GlobalAction action) => action == GlobalAction.Back && AllowBackButton;
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{
if (args.Repeat || !IsCurrentScreen) return false;
switch (args.Key)
{
case Key.Escape:
Exit();
return true;
}
return base.OnKeyDown(state, args);
}
protected override void OnResuming(Screen last) protected override void OnResuming(Screen last)
{ {
sampleExit?.Play(); sampleExit?.Play();

View File

@ -1,12 +1,9 @@
// 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.Input;
using OpenTK.Input;
using osu.Game.Graphics; using osu.Game.Graphics;
using OpenTK.Graphics; using OpenTK.Graphics;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using System.Linq;
namespace osu.Game.Screens.Play namespace osu.Game.Screens.Play
{ {
@ -21,16 +18,5 @@ namespace osu.Game.Screens.Play
AddButton("Retry", colours.YellowDark, () => OnRetry?.Invoke()); AddButton("Retry", colours.YellowDark, () => OnRetry?.Invoke());
AddButton("Quit", new Color4(170, 27, 39, 255), () => OnQuit?.Invoke()); AddButton("Quit", new Color4(170, 27, 39, 255), () => OnQuit?.Invoke());
} }
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{
if (!args.Repeat && args.Key == Key.Escape)
{
InternalButtons.Children.Last().TriggerOnClick();
return true;
}
return base.OnKeyDown(state, args);
}
} }
} }

View File

@ -15,10 +15,13 @@ using osu.Game.Graphics.UserInterface;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using OpenTK.Input; using OpenTK.Input;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using osu.Framework.Input.Bindings;
using osu.Game.Input.Bindings;
namespace osu.Game.Screens.Play namespace osu.Game.Screens.Play
{ {
public abstract class GameplayMenuOverlay : OverlayContainer public abstract class GameplayMenuOverlay : OverlayContainer, IKeyBindingHandler<GlobalAction>
{ {
private const int transition_duration = 200; private const int transition_duration = 200;
private const int button_height = 70; private const int button_height = 70;
@ -31,6 +34,11 @@ namespace osu.Game.Screens.Play
public Action OnRetry; public Action OnRetry;
public Action OnQuit; public Action OnQuit;
/// <summary>
/// Action that is invoked when <see cref="GlobalAction.Back"/> is triggered.
/// </summary>
protected virtual Action BackAction => () => InternalButtons.Children.Last().TriggerOnClick();
public abstract string Header { get; } public abstract string Header { get; }
public abstract string Description { get; } public abstract string Description { get; }
@ -219,6 +227,19 @@ namespace osu.Game.Screens.Play
return base.OnKeyDown(state, args); return base.OnKeyDown(state, args);
} }
public bool OnPressed(GlobalAction action)
{
if (action == GlobalAction.Back)
{
BackAction.Invoke();
return true;
}
return false;
}
public bool OnReleased(GlobalAction action) => action == GlobalAction.Back;
private void buttonSelectionChanged(DialogButton button, bool isSelected) private void buttonSelectionChanged(DialogButton button, bool isSelected)
{ {
if (!isSelected) if (!isSelected)

View File

@ -6,11 +6,9 @@ using System.Linq;
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.Framework.Input;
using osu.Framework.Timing; using osu.Framework.Timing;
using osu.Game.Graphics; using osu.Game.Graphics;
using OpenTK.Graphics; using OpenTK.Graphics;
using OpenTK.Input;
namespace osu.Game.Screens.Play namespace osu.Game.Screens.Play
{ {
@ -138,16 +136,7 @@ namespace osu.Game.Screens.Play
public override string Header => "paused"; public override string Header => "paused";
public override string Description => "you're not going to do what i think you're going to do, are ya?"; public override string Description => "you're not going to do what i think you're going to do, are ya?";
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) protected override Action BackAction => () => InternalButtons.Children.First().TriggerOnClick();
{
if (!args.Repeat && args.Key == Key.Escape)
{
InternalButtons.Children.First().TriggerOnClick();
return true;
}
return base.OnKeyDown(state, args);
}
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuColour colours) private void load(OsuColour colours)

View File

@ -49,8 +49,6 @@ namespace osu.Game.Screens.Play
public bool AllowLeadIn { get; set; } = true; public bool AllowLeadIn { get; set; } = true;
public bool AllowResults { get; set; } = true; public bool AllowResults { get; set; } = true;
protected override bool AllowBackButton => false;
private Bindable<bool> mouseWheelDisabled; private Bindable<bool> mouseWheelDisabled;
private Bindable<double> userAudioOffset; private Bindable<double> userAudioOffset;
@ -158,7 +156,8 @@ namespace osu.Game.Screens.Play
userAudioOffset.TriggerChange(); userAudioOffset.TriggerChange();
ScoreProcessor = RulesetContainer.CreateScoreProcessor(); ScoreProcessor = RulesetContainer.CreateScoreProcessor();
config.BindWith(OsuSetting.ScoreDisplayMode, ScoreProcessor.Mode); if (!ScoreProcessor.Mode.Disabled)
config.BindWith(OsuSetting.ScoreDisplayMode, ScoreProcessor.Mode);
Children = new Drawable[] Children = new Drawable[]
{ {

View File

@ -53,10 +53,10 @@ namespace osu.Game.Screens.Select
} }
[BackgroundDependencyLoader(true)] [BackgroundDependencyLoader(true)]
private void load([CanBeNull] OsuGame osuGame) private void load([CanBeNull] Bindable<RulesetInfo> parentRuleset)
{ {
if (osuGame != null) if (parentRuleset != null)
ruleset.BindTo(osuGame.Ruleset); ruleset.BindTo(parentRuleset);
ruleset.ValueChanged += _ => updateDisplay(); ruleset.ValueChanged += _ => updateDisplay();
} }

View File

@ -62,7 +62,7 @@ namespace osu.Game.Screens.Select
Sort = sort, Sort = sort,
SearchText = searchTextBox.Text, SearchText = searchTextBox.Text,
AllowConvertedBeatmaps = showConverted, AllowConvertedBeatmaps = showConverted,
Ruleset = ruleset Ruleset = ruleset.Value
}; };
public Action Exit; public Action Exit;
@ -163,24 +163,23 @@ namespace osu.Game.Screens.Select
searchTextBox.HoldFocus = true; searchTextBox.HoldFocus = true;
} }
private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>(); private readonly IBindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>();
private Bindable<bool> showConverted; private Bindable<bool> showConverted;
public readonly Box Background; public readonly Box Background;
[BackgroundDependencyLoader(permitNulls: true)] [BackgroundDependencyLoader(permitNulls: true)]
private void load(OsuColour colours, OsuGame osu, OsuConfigManager config) private void load(OsuColour colours, IBindable<RulesetInfo> parentRuleset, OsuConfigManager config)
{ {
sortTabs.AccentColour = colours.GreenLight; sortTabs.AccentColour = colours.GreenLight;
showConverted = config.GetBindable<bool>(OsuSetting.ShowConvertedBeatmaps); showConverted = config.GetBindable<bool>(OsuSetting.ShowConvertedBeatmaps);
showConverted.ValueChanged += val => updateCriteria(); showConverted.ValueChanged += val => updateCriteria();
if (osu != null) if (parentRuleset != null)
ruleset.BindTo(osu.Ruleset); ruleset.BindTo(parentRuleset);
ruleset.ValueChanged += val => updateCriteria(); ruleset.BindValueChanged(val => updateCriteria(), true);
ruleset.TriggerChange();
} }
private void updateCriteria() => FilterChanged?.Invoke(CreateCriteria()); private void updateCriteria() => FilterChanged?.Invoke(CreateCriteria());

View File

@ -19,7 +19,6 @@ using osu.Game.Online.API;
using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests;
using System.Linq; using System.Linq;
using osu.Framework.Configuration; using osu.Framework.Configuration;
using osu.Framework.Logging;
using osu.Game.Rulesets; using osu.Game.Rulesets;
namespace osu.Game.Screens.Select.Leaderboards namespace osu.Game.Screens.Select.Leaderboards
@ -33,7 +32,7 @@ namespace osu.Game.Screens.Select.Leaderboards
private FillFlowContainer<LeaderboardScore> scrollFlow; private FillFlowContainer<LeaderboardScore> scrollFlow;
private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>(); private readonly IBindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>();
public Action<Score> ScoreSelected; public Action<Score> ScoreSelected;
@ -146,7 +145,7 @@ namespace osu.Game.Screens.Select.Leaderboards
replacePlaceholder(new MessagePlaceholder(@"Please sign in to view online leaderboards!")); replacePlaceholder(new MessagePlaceholder(@"Please sign in to view online leaderboards!"));
break; break;
case PlaceholderState.NotSupporter: case PlaceholderState.NotSupporter:
replacePlaceholder(new MessagePlaceholder(@"Please invest in a supporter tag to view this leaderboard!")); replacePlaceholder(new MessagePlaceholder(@"Please invest in an osu!supporter tag to view this leaderboard!"));
break; break;
default: default:
replacePlaceholder(null); replacePlaceholder(null);
@ -174,9 +173,8 @@ namespace osu.Game.Screens.Select.Leaderboards
private APIAccess api; private APIAccess api;
private BeatmapInfo beatmap; private BeatmapInfo beatmap;
private OsuGame osuGame;
private ScheduledDelegate pendingBeatmapSwitch; private ScheduledDelegate pendingUpdateScores;
public BeatmapInfo Beatmap public BeatmapInfo Beatmap
{ {
@ -189,21 +187,19 @@ namespace osu.Game.Screens.Select.Leaderboards
beatmap = value; beatmap = value;
Scores = null; Scores = null;
pendingBeatmapSwitch?.Cancel(); updateScores();
pendingBeatmapSwitch = Schedule(updateScores);
} }
} }
[BackgroundDependencyLoader(permitNulls: true)] [BackgroundDependencyLoader(permitNulls: true)]
private void load(APIAccess api, OsuGame osuGame) private void load(APIAccess api, IBindable<RulesetInfo> parentRuleset)
{ {
this.api = api; this.api = api;
this.osuGame = osuGame;
if (osuGame != null) if (parentRuleset != null)
ruleset.BindTo(osuGame.Ruleset); ruleset.BindTo(parentRuleset);
ruleset.ValueChanged += r => updateScores(); ruleset.ValueChanged += _ => updateScores();
if (api != null) if (api != null)
api.OnStateChange += handleApiStateChange; api.OnStateChange += handleApiStateChange;
@ -231,51 +227,57 @@ namespace osu.Game.Screens.Select.Leaderboards
private void updateScores() private void updateScores()
{ {
if (Scope == LeaderboardScope.Local) getScoresRequest?.Cancel();
{ getScoresRequest = null;
// TODO: get local scores from wherever here.
PlaceholderState = PlaceholderState.NoScores;
return;
}
if (Beatmap?.OnlineBeatmapID == null) pendingUpdateScores?.Cancel();
pendingUpdateScores = Schedule(() =>
{ {
PlaceholderState = PlaceholderState.Unavailable; if (Scope == LeaderboardScope.Local)
return; {
} // TODO: get local scores from wherever here.
PlaceholderState = PlaceholderState.NoScores;
if (api?.IsLoggedIn != true)
{
PlaceholderState = PlaceholderState.NotLoggedIn;
return;
}
if (Scope != LeaderboardScope.Global && !api.LocalUser.Value.IsSupporter)
{
PlaceholderState = PlaceholderState.NotSupporter;
return;
}
PlaceholderState = PlaceholderState.Retrieving;
loading.Show();
getScoresRequest = new GetScoresRequest(Beatmap, osuGame?.Ruleset.Value ?? Beatmap.Ruleset, Scope);
getScoresRequest.Success += r => Schedule(() =>
{
Scores = r.Scores;
PlaceholderState = Scores.Any() ? PlaceholderState.Successful : PlaceholderState.NoScores;
});
getScoresRequest.Failure += e => Schedule(() =>
{
if (e is OperationCanceledException)
return; return;
}
PlaceholderState = PlaceholderState.NetworkFailure; if (Beatmap?.OnlineBeatmapID == null)
Logger.Error(e, @"Couldn't fetch beatmap scores!"); {
PlaceholderState = PlaceholderState.Unavailable;
return;
}
if (api?.IsLoggedIn != true)
{
PlaceholderState = PlaceholderState.NotLoggedIn;
return;
}
if (Scope != LeaderboardScope.Global && !api.LocalUser.Value.IsSupporter)
{
PlaceholderState = PlaceholderState.NotSupporter;
return;
}
PlaceholderState = PlaceholderState.Retrieving;
loading.Show();
getScoresRequest = new GetScoresRequest(Beatmap, ruleset.Value ?? Beatmap.Ruleset, Scope);
getScoresRequest.Success += r => Schedule(() =>
{
Scores = r.Scores;
PlaceholderState = Scores.Any() ? PlaceholderState.Successful : PlaceholderState.NoScores;
});
getScoresRequest.Failure += e => Schedule(() =>
{
if (e is OperationCanceledException)
return;
PlaceholderState = PlaceholderState.NetworkFailure;
});
api.Queue(getScoresRequest);
}); });
api.Queue(getScoresRequest);
} }
private Placeholder currentPlaceholder; private Placeholder currentPlaceholder;
@ -331,23 +333,4 @@ namespace osu.Game.Screens.Select.Leaderboards
} }
} }
} }
public enum LeaderboardScope
{
Local,
Country,
Global,
Friend,
}
public enum PlaceholderState
{
Successful,
Retrieving,
NetworkFailure,
Unavailable,
NoScores,
NotLoggedIn,
NotSupporter,
}
} }

View File

@ -0,0 +1,13 @@
// 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.Screens.Select.Leaderboards
{
public enum LeaderboardScope
{
Local,
Country,
Global,
Friend,
}
}

View File

@ -2,10 +2,7 @@
// 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.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using OpenTK;
namespace osu.Game.Screens.Select.Leaderboards namespace osu.Game.Screens.Select.Leaderboards
{ {
@ -15,22 +12,13 @@ namespace osu.Game.Screens.Select.Leaderboards
public MessagePlaceholder(string message) public MessagePlaceholder(string message)
{ {
Direction = FillDirection.Horizontal; AddIcon(FontAwesome.fa_exclamation_circle, cp =>
AutoSizeAxes = Axes.Both;
Children = new Drawable[]
{ {
new SpriteIcon cp.TextSize = TEXT_SIZE;
{ cp.Padding = new MarginPadding { Right = 10 };
Icon = FontAwesome.fa_exclamation_circle, });
Size = new Vector2(26),
Margin = new MarginPadding { Right = 10 }, AddText(this.message = message);
},
new OsuSpriteText
{
Text = this.message = message,
TextSize = 22,
},
};
} }
public override bool Equals(Placeholder other) => (other as MessagePlaceholder)?.message == message; public override bool Equals(Placeholder other) => (other as MessagePlaceholder)?.message == message;

View File

@ -3,16 +3,27 @@
using System; using System;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Game.Graphics.Containers;
namespace osu.Game.Screens.Select.Leaderboards namespace osu.Game.Screens.Select.Leaderboards
{ {
public abstract class Placeholder : FillFlowContainer, IEquatable<Placeholder> public abstract class Placeholder : OsuTextFlowContainer, IEquatable<Placeholder>
{ {
protected const float TEXT_SIZE = 22;
public override bool HandleMouseInput => true;
protected Placeholder() protected Placeholder()
: base(cp => cp.TextSize = TEXT_SIZE)
{ {
Anchor = Anchor.Centre; Anchor = Anchor.Centre;
Origin = Anchor.Centre; Origin = Anchor.Centre;
TextAnchor = Anchor.TopCentre;
Padding = new MarginPadding(20);
AutoSizeAxes = Axes.Y;
RelativeSizeAxes = Axes.X;
} }
public virtual bool Equals(Placeholder other) => GetType() == other?.GetType(); public virtual bool Equals(Placeholder other) => GetType() == other?.GetType();

View File

@ -0,0 +1,16 @@
// 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.Screens.Select.Leaderboards
{
public enum PlaceholderState
{
Successful,
Retrieving,
NetworkFailure,
Unavailable,
NoScores,
NotLoggedIn,
NotSupporter,
}
}

View File

@ -3,11 +3,9 @@
using System; using System;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input; using osu.Framework.Input;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using OpenTK; using OpenTK;
namespace osu.Game.Screens.Select.Leaderboards namespace osu.Game.Screens.Select.Leaderboards
@ -18,22 +16,13 @@ namespace osu.Game.Screens.Select.Leaderboards
public RetrievalFailurePlaceholder() public RetrievalFailurePlaceholder()
{ {
Direction = FillDirection.Horizontal; AddArbitraryDrawable(new RetryButton
AutoSizeAxes = Axes.Both;
Children = new Drawable[]
{ {
new RetryButton Action = () => OnRetry?.Invoke(),
{ Padding = new MarginPadding { Right = 10 }
Action = () => OnRetry?.Invoke(), });
Margin = new MarginPadding { Right = 10 },
}, AddText(@"Couldn't retrieve scores!");
new OsuSpriteText
{
Anchor = Anchor.TopLeft,
Text = @"Couldn't retrieve scores!",
TextSize = 22,
},
};
} }
public class RetryButton : OsuHoverContainer public class RetryButton : OsuHoverContainer
@ -44,18 +33,16 @@ namespace osu.Game.Screens.Select.Leaderboards
public RetryButton() public RetryButton()
{ {
Height = 26; AutoSizeAxes = Axes.Both;
Width = 26;
Child = new OsuClickableContainer Child = new OsuClickableContainer
{ {
AutoSizeAxes = Axes.Both, AutoSizeAxes = Axes.Both,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Action = () => Action?.Invoke(), Action = () => Action?.Invoke(),
Child = icon = new SpriteIcon Child = icon = new SpriteIcon
{ {
Icon = FontAwesome.fa_refresh, Icon = FontAwesome.fa_refresh,
Size = new Vector2(26), Size = new Vector2(TEXT_SIZE),
Shadow = true, Shadow = true,
}, },
}; };

View File

@ -8,6 +8,7 @@ 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.Audio.Track; using osu.Framework.Audio.Track;
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.Input; using osu.Framework.Input;
@ -17,6 +18,7 @@ using osu.Game.Beatmaps;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Overlays; using osu.Game.Overlays;
using osu.Game.Rulesets;
using osu.Game.Screens.Backgrounds; using osu.Game.Screens.Backgrounds;
using osu.Game.Screens.Edit; using osu.Game.Screens.Edit;
using osu.Game.Screens.Menu; using osu.Game.Screens.Menu;
@ -62,6 +64,8 @@ namespace osu.Game.Screens.Select
private SampleChannel sampleChangeDifficulty; private SampleChannel sampleChangeDifficulty;
private SampleChannel sampleChangeBeatmap; private SampleChannel sampleChangeBeatmap;
protected new readonly Bindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>();
private DependencyContainer dependencies; private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
=> dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); => dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
@ -123,7 +127,7 @@ 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 = carouselSelectionChanged, SelectionChanged = updateSelectedBeatmap,
BeatmapSetsChanged = carouselBeatmapsLoaded, BeatmapSetsChanged = carouselBeatmapsLoaded,
}, },
FilterControl = new FilterControl FilterControl = new FilterControl
@ -177,9 +181,13 @@ namespace osu.Game.Screens.Select
} }
[BackgroundDependencyLoader(true)] [BackgroundDependencyLoader(true)]
private void load(BeatmapManager beatmaps, AudioManager audio, DialogOverlay dialog, OsuGame osu, OsuColour colours) private void load(BeatmapManager beatmaps, AudioManager audio, DialogOverlay dialog, OsuColour colours)
{ {
dependencies.CacheAs(this); dependencies.CacheAs(this);
dependencies.CacheAs(Ruleset);
dependencies.CacheAs<IBindable<RulesetInfo>>(Ruleset);
base.Ruleset.ValueChanged += r => updateSelectedBeatmap(beatmapNoDebounce);
if (Footer != null) if (Footer != null)
{ {
@ -192,9 +200,6 @@ namespace osu.Game.Screens.Select
if (this.beatmaps == null) if (this.beatmaps == null)
this.beatmaps = beatmaps; this.beatmaps = beatmaps;
if (osu != null)
Ruleset.BindTo(osu.Ruleset);
this.beatmaps.ItemAdded += onBeatmapSetAdded; this.beatmaps.ItemAdded += onBeatmapSetAdded;
this.beatmaps.ItemRemoved += onBeatmapSetRemoved; this.beatmaps.ItemRemoved += onBeatmapSetRemoved;
this.beatmaps.BeatmapHidden += onBeatmapHidden; this.beatmaps.BeatmapHidden += onBeatmapHidden;
@ -250,9 +255,6 @@ namespace osu.Game.Screens.Select
private ScheduledDelegate selectionChangedDebounce; private ScheduledDelegate selectionChangedDebounce;
// We need to keep track of the last selected beatmap ignoring debounce to play the correct selection sounds.
private BeatmapInfo beatmapNoDebounce;
private void workingBeatmapChanged(WorkingBeatmap beatmap) private void workingBeatmapChanged(WorkingBeatmap beatmap)
{ {
if (beatmap is DummyWorkingBeatmap) return; if (beatmap is DummyWorkingBeatmap) return;
@ -266,11 +268,17 @@ namespace osu.Game.Screens.Select
} }
} }
// We need to keep track of the last selected beatmap ignoring debounce to play the correct selection sounds.
private BeatmapInfo beatmapNoDebounce;
private RulesetInfo rulesetNoDebounce;
/// <summary> /// <summary>
/// selection has been changed as the result of interaction with the carousel. /// selection has been changed as the result of a user interaction.
/// </summary> /// </summary>
private void carouselSelectionChanged(BeatmapInfo beatmap) private void updateSelectedBeatmap(BeatmapInfo beatmap)
{ {
var ruleset = base.Ruleset.Value;
void performLoad() void performLoad()
{ {
// We may be arriving here due to another component changing the bindable Beatmap. // We may be arriving here due to another component changing the bindable Beatmap.
@ -283,15 +291,18 @@ namespace osu.Game.Screens.Select
ensurePlayingSelected(preview); ensurePlayingSelected(preview);
} }
Ruleset.Value = ruleset;
UpdateBeatmap(Beatmap.Value); UpdateBeatmap(Beatmap.Value);
} }
if (beatmap?.Equals(beatmapNoDebounce) == true) if (beatmap?.Equals(beatmapNoDebounce) == true && ruleset?.Equals(rulesetNoDebounce) == true)
return; return;
selectionChangedDebounce?.Cancel(); selectionChangedDebounce?.Cancel();
beatmapNoDebounce = beatmap; beatmapNoDebounce = beatmap;
rulesetNoDebounce = ruleset;
if (beatmap == null) if (beatmap == null)
performLoad(); performLoad();
@ -460,7 +471,7 @@ namespace osu.Game.Screens.Select
{ {
// in the case random selection failed, we want to trigger selectionChanged // in the case random selection failed, we want to trigger selectionChanged
// to show the dummy beatmap (we have nothing else to display). // to show the dummy beatmap (we have nothing else to display).
carouselSelectionChanged(null); updateSelectedBeatmap(null);
} }
} }

View File

@ -1,12 +1,10 @@
// 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.Linq;
using osu.Framework.Audio.Track; using osu.Framework.Audio.Track;
using osu.Framework.Graphics.Textures; using osu.Framework.Graphics.Textures;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Objects.Types;
namespace osu.Game.Tests.Beatmaps namespace osu.Game.Tests.Beatmaps
{ {
@ -26,21 +24,6 @@ namespace osu.Game.Tests.Beatmaps
private readonly IBeatmap beatmap; private readonly IBeatmap beatmap;
protected override IBeatmap GetBeatmap() => beatmap; protected override IBeatmap GetBeatmap() => beatmap;
protected override Texture GetBackground() => null; protected override Texture GetBackground() => null;
protected override Track GetTrack() => null;
protected override Track GetTrack()
{
var lastObject = beatmap.HitObjects.LastOrDefault();
if (lastObject != null)
return new TestTrack(((lastObject as IHasEndTime)?.EndTime ?? lastObject.StartTime) + 1000);
return new TrackVirtual();
}
private class TestTrack : TrackVirtual
{
public TestTrack(double length)
{
Length = length;
}
}
} }
} }

View File

@ -18,8 +18,8 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.1" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.1.1" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.1.1" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" /> <PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="ppy.osu.Framework" Version="2018.626.0" /> <PackageReference Include="ppy.osu.Framework" Version="2018.629.0" />
<PackageReference Include="SharpCompress" Version="0.21.1" /> <PackageReference Include="SharpCompress" Version="0.17.1" />
<PackageReference Include="NUnit" Version="3.10.1" /> <PackageReference Include="NUnit" Version="3.10.1" />
<PackageReference Include="System.ComponentModel.Annotations" Version="4.5.0" /> <PackageReference Include="System.ComponentModel.Annotations" Version="4.5.0" />
</ItemGroup> </ItemGroup>