1
0
mirror of https://github.com/ppy/osu.git synced 2025-02-21 03:02:54 +08:00

Merge branch 'master' into decoders

This commit is contained in:
Dean Herbert 2018-03-12 13:38:22 +09:00 committed by GitHub
commit ab4c527ebc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 424 additions and 266 deletions

View File

@ -1,9 +1,11 @@
osu!lazer is currently in early stages of development and is not yet ready for end users. Please avoid creating issues or bugs if you do not personally intend to fix them. Some acceptable topics include: osu!lazer is currently still under heavy development!
Please ensure that you are making an issue for one of the following:
- A bug with currently implemented features (not features that don't exist)
- A feature you are considering adding, so we can collaborate on feedback and design.
- Discussions about technical design decisions - Discussions about technical design decisions
- Bugs that you have found and are personally willing and able to fix
- TODO lists of smaller tasks around larger features
Basically, issues are not a place for you to get help. They are a place for developers to collaborate on the game.
If your issue qualifies, replace this text with a detailed description of your issue with as much relevant information as you can provide. If your issue qualifies, replace this text with a detailed description of your issue with as much relevant information as you can provide.
Screenshots and log files are highly welcomed.

@ -1 +1 @@
Subproject commit 6915954abdba64e72f698aa58698b00159f3678d Subproject commit 59004b46f2c96ac02fec712e66f9f96fe252f2fa

View File

@ -91,6 +91,7 @@ namespace osu.Game.Rulesets.Mania
}, },
new ManiaModRandom(), new ManiaModRandom(),
new ManiaModDualStages(), new ManiaModDualStages(),
new ManiaModMirror(),
new MultiMod new MultiMod
{ {
Mods = new Mod[] Mods = new Mod[]

View File

@ -0,0 +1,28 @@
// 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.Extensions.IEnumerableExtensions;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI;
using System.Linq;
namespace osu.Game.Rulesets.Mania.Mods
{
public class ManiaModMirror : Mod, IApplicableToRulesetContainer<ManiaHitObject>
{
public override string Name => "Mirror";
public override string ShortenedName => "MR";
public override ModType Type => ModType.Special;
public override double ScoreMultiplier => 1;
public override bool Ranked => true;
public void ApplyToRulesetContainer(RulesetContainer<ManiaHitObject> rulesetContainer)
{
var availableColumns = ((ManiaRulesetContainer)rulesetContainer).Beatmap.TotalColumns;
rulesetContainer.Objects.OfType<ManiaHitObject>().ForEach(h => h.Column = availableColumns - 1 - h.Column);
}
}
}

View File

@ -3,13 +3,14 @@
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Mania.UI namespace osu.Game.Rulesets.Mania.UI
{ {
internal class DrawableManiaJudgement : DrawableJudgement internal class DrawableManiaJudgement : DrawableJudgement
{ {
public DrawableManiaJudgement(Judgement judgement) public DrawableManiaJudgement(Judgement judgement, DrawableHitObject judgedObject)
: base(judgement) : base(judgement, judgedObject)
{ {
JudgementText.TextSize = 25; JudgementText.TextSize = 25;
} }

View File

@ -15,6 +15,7 @@ using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.UI;
using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Rulesets.UI.Scrolling;
using OpenTK; using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
@ -40,7 +41,7 @@ namespace osu.Game.Rulesets.Mania.UI
private readonly Container<Drawable> content; private readonly Container<Drawable> content;
public Container<DrawableManiaJudgement> Judgements => judgements; public Container<DrawableManiaJudgement> Judgements => judgements;
private readonly Container<DrawableManiaJudgement> judgements; private readonly JudgementContainer<DrawableManiaJudgement> judgements;
private readonly Container topLevelContainer; private readonly Container topLevelContainer;
@ -114,7 +115,7 @@ namespace osu.Game.Rulesets.Mania.UI
Padding = new MarginPadding { Top = HIT_TARGET_POSITION } Padding = new MarginPadding { Top = HIT_TARGET_POSITION }
} }
}, },
judgements = new Container<DrawableManiaJudgement> judgements = new JudgementContainer<DrawableManiaJudgement>
{ {
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
@ -171,7 +172,7 @@ namespace osu.Game.Rulesets.Mania.UI
internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement) internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
{ {
judgements.Clear(); judgements.Clear();
judgements.Add(new DrawableManiaJudgement(judgement) judgements.Add(new DrawableManiaJudgement(judgement, judgedObject)
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,

View File

@ -81,6 +81,7 @@
<Compile Include="Judgements\ManiaJudgement.cs" /> <Compile Include="Judgements\ManiaJudgement.cs" />
<Compile Include="ManiaDifficultyCalculator.cs" /> <Compile Include="ManiaDifficultyCalculator.cs" />
<Compile Include="Mods\IPlayfieldTypeMod.cs" /> <Compile Include="Mods\IPlayfieldTypeMod.cs" />
<Compile Include="Mods\ManiaModMirror.cs" />
<Compile Include="Mods\ManiaKeyMod.cs" /> <Compile Include="Mods\ManiaKeyMod.cs" />
<Compile Include="Mods\ManiaModAutoplay.cs" /> <Compile Include="Mods\ManiaModAutoplay.cs" />
<Compile Include="Mods\ManiaModDaycore.cs" /> <Compile Include="Mods\ManiaModDaycore.cs" />

View File

@ -2,17 +2,17 @@
// 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.Game.Rulesets.Osu.Judgements;
using OpenTK; using OpenTK;
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Osu.Objects.Drawables namespace osu.Game.Rulesets.Osu.Objects.Drawables
{ {
public class DrawableOsuJudgement : DrawableJudgement public class DrawableOsuJudgement : DrawableJudgement
{ {
public DrawableOsuJudgement(OsuJudgement judgement) public DrawableOsuJudgement(Judgement judgement, DrawableHitObject judgedObject)
: base(judgement) : base(judgement, judgedObject)
{ {
} }

View File

@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Osu.UI
public class OsuPlayfield : Playfield public class OsuPlayfield : Playfield
{ {
private readonly Container approachCircles; private readonly Container approachCircles;
private readonly Container judgementLayer; private readonly JudgementContainer<DrawableOsuJudgement> judgementLayer;
private readonly ConnectionRenderer<OsuHitObject> connectionLayer; private readonly ConnectionRenderer<OsuHitObject> connectionLayer;
// Todo: This should not be a thing, but is currently required for the editor // Todo: This should not be a thing, but is currently required for the editor
@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Osu.UI
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Depth = 2, Depth = 2,
}, },
judgementLayer = new Container judgementLayer = new JudgementContainer<DrawableOsuJudgement>
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Depth = 1, Depth = 1,
@ -75,16 +75,13 @@ namespace osu.Game.Rulesets.Osu.UI
private void onJudgement(DrawableHitObject judgedObject, Judgement judgement) private void onJudgement(DrawableHitObject judgedObject, Judgement judgement)
{ {
var osuJudgement = (OsuJudgement)judgement;
var osuObject = (OsuHitObject)judgedObject.HitObject;
if (!judgedObject.DisplayJudgement) if (!judgedObject.DisplayJudgement)
return; return;
DrawableOsuJudgement explosion = new DrawableOsuJudgement(osuJudgement) DrawableOsuJudgement explosion = new DrawableOsuJudgement(judgement, judgedObject)
{ {
Origin = Anchor.Centre, Origin = Anchor.Centre,
Position = osuObject.StackedEndPosition + osuJudgement.PositionOffset Position = ((OsuHitObject)judgedObject.HitObject).StackedEndPosition + ((OsuJudgement)judgement).PositionOffset
}; };
judgementLayer.Add(explosion); judgementLayer.Add(explosion);

View File

@ -15,17 +15,14 @@ namespace osu.Game.Rulesets.Taiko.UI
/// </summary> /// </summary>
public class DrawableTaikoJudgement : DrawableJudgement public class DrawableTaikoJudgement : DrawableJudgement
{ {
public readonly DrawableHitObject JudgedObject;
/// <summary> /// <summary>
/// Creates a new judgement text. /// Creates a new judgement text.
/// </summary> /// </summary>
/// <param name="judgedObject">The object which is being judged.</param> /// <param name="judgedObject">The object which is being judged.</param>
/// <param name="judgement">The judgement to visualise.</param> /// <param name="judgement">The judgement to visualise.</param>
public DrawableTaikoJudgement(DrawableHitObject judgedObject, Judgement judgement) public DrawableTaikoJudgement(Judgement judgement, DrawableHitObject judgedObject)
: base(judgement) : base(judgement, judgedObject)
{ {
JudgedObject = judgedObject;
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]

View File

@ -16,6 +16,7 @@ using System.Linq;
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Taiko.Objects.Drawables; using osu.Game.Rulesets.Taiko.Objects.Drawables;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.UI;
using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Rulesets.UI.Scrolling;
namespace osu.Game.Rulesets.Taiko.UI namespace osu.Game.Rulesets.Taiko.UI
@ -41,7 +42,7 @@ namespace osu.Game.Rulesets.Taiko.UI
private readonly Container<HitExplosion> hitExplosionContainer; private readonly Container<HitExplosion> hitExplosionContainer;
private readonly Container<KiaiHitExplosion> kiaiExplosionContainer; private readonly Container<KiaiHitExplosion> kiaiExplosionContainer;
private readonly Container<DrawableTaikoJudgement> judgementContainer; private readonly JudgementContainer<DrawableTaikoJudgement> judgementContainer;
protected override Container<Drawable> Content => content; protected override Container<Drawable> Content => content;
private readonly Container content; private readonly Container content;
@ -131,7 +132,7 @@ namespace osu.Game.Rulesets.Taiko.UI
Margin = new MarginPadding { Left = HIT_TARGET_OFFSET }, Margin = new MarginPadding { Left = HIT_TARGET_OFFSET },
Blending = BlendingMode.Additive Blending = BlendingMode.Additive
}, },
judgementContainer = new Container<DrawableTaikoJudgement> judgementContainer = new JudgementContainer<DrawableTaikoJudgement>
{ {
Name = "Judgements", Name = "Judgements",
RelativeSizeAxes = Axes.Y, RelativeSizeAxes = Axes.Y,
@ -227,7 +228,7 @@ namespace osu.Game.Rulesets.Taiko.UI
{ {
if (judgedObject.DisplayJudgement && judgementContainer.FirstOrDefault(j => j.JudgedObject == judgedObject) == null) if (judgedObject.DisplayJudgement && judgementContainer.FirstOrDefault(j => j.JudgedObject == judgedObject) == null)
{ {
judgementContainer.Add(new DrawableTaikoJudgement(judgedObject, judgement) judgementContainer.Add(new DrawableTaikoJudgement(judgement, judgedObject)
{ {
Anchor = judgement.IsHit ? Anchor.TopLeft : Anchor.CentreLeft, Anchor = judgement.IsHit ? Anchor.TopLeft : Anchor.CentreLeft,
Origin = judgement.IsHit ? Anchor.BottomCentre : Anchor.Centre, Origin = judgement.IsHit ? Anchor.BottomCentre : Anchor.Centre,

View File

@ -12,6 +12,7 @@ using osu.Framework.Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Rulesets;
using osu.Game.Screens.Select; using osu.Game.Screens.Select;
using osu.Game.Screens.Select.Carousel; using osu.Game.Screens.Select.Carousel;
using osu.Game.Screens.Select.Filter; using osu.Game.Screens.Select.Filter;
@ -22,6 +23,7 @@ namespace osu.Game.Tests.Visual
public class TestCaseBeatmapCarousel : OsuTestCase public class TestCaseBeatmapCarousel : OsuTestCase
{ {
private TestBeatmapCarousel carousel; private TestBeatmapCarousel carousel;
private RulesetStore rulesets;
public override IReadOnlyList<Type> RequiredTypes => new[] public override IReadOnlyList<Type> RequiredTypes => new[]
{ {
@ -46,8 +48,10 @@ namespace osu.Game.Tests.Visual
private const int set_count = 5; private const int set_count = 5;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load(RulesetStore rulesets)
{ {
this.rulesets = rulesets;
Add(carousel = new TestBeatmapCarousel Add(carousel = new TestBeatmapCarousel
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
@ -75,6 +79,7 @@ namespace osu.Game.Tests.Visual
testRemoveAll(); testRemoveAll();
testEmptyTraversal(); testEmptyTraversal();
testHiding(); testHiding();
testSelectingFilteredRuleset();
} }
private void ensureRandomFetchSuccess() => private void ensureRandomFetchSuccess() =>
@ -363,6 +368,41 @@ namespace osu.Game.Tests.Visual
} }
} }
private void testSelectingFilteredRuleset()
{
var testMixed = createTestBeatmapSet(set_count + 1);
AddStep("add mixed ruleset beatmapset", () =>
{
for (int i = 0; i <= 2; i++)
{
testMixed.Beatmaps[i].Ruleset = rulesets.AvailableRulesets.ElementAt(i);
testMixed.Beatmaps[i].RulesetID = i;
}
carousel.UpdateBeatmapSet(testMixed);
});
AddStep("filter to ruleset 0", () =>
carousel.Filter(new FilterCriteria { Ruleset = rulesets.AvailableRulesets.ElementAt(0) }, false));
AddStep("select filtered map skipping filtered", () => carousel.SelectBeatmap(testMixed.Beatmaps[1], false));
AddAssert("unfiltered beatmap selected", () => carousel.SelectedBeatmap.Equals(testMixed.Beatmaps[0]));
AddStep("remove mixed set", () =>
{
carousel.RemoveBeatmapSet(testMixed);
testMixed = null;
});
var testSingle = createTestBeatmapSet(set_count + 2);
testSingle.Beatmaps.ForEach(b =>
{
b.Ruleset = rulesets.AvailableRulesets.ElementAt(1);
b.RulesetID = b.Ruleset.ID ?? 1;
});
AddStep("add single ruleset beatmapset", () => carousel.UpdateBeatmapSet(testSingle));
AddStep("select filtered map skipping filtered", () => carousel.SelectBeatmap(testSingle.Beatmaps[0], false));
checkNoSelection();
AddStep("remove single ruleset set", () => carousel.RemoveBeatmapSet(testSingle));
}
private BeatmapSetInfo createTestBeatmapSet(int id) private BeatmapSetInfo createTestBeatmapSet(int id)
{ {
return new BeatmapSetInfo return new BeatmapSetInfo

View File

@ -3,9 +3,9 @@
using osu.Framework.Timing; using osu.Framework.Timing;
using osu.Game.Beatmaps.Timing; using osu.Game.Beatmaps.Timing;
using osu.Game.Screens.Play.BreaksOverlay;
using System.Collections.Generic; using System.Collections.Generic;
using NUnit.Framework; using NUnit.Framework;
using osu.Game.Screens.Play;
namespace osu.Game.Tests.Visual namespace osu.Game.Tests.Visual
{ {

View File

@ -58,6 +58,12 @@ namespace osu.Game.Tests.Visual
checkSupporterTag(false); checkSupporterTag(false);
AddStep("Show null dummy", () => profile.ShowUser(new User
{
Username = @"Null",
Id = 1,
}, false));
AddStep("Show ppy", () => profile.ShowUser(new User AddStep("Show ppy", () => profile.ShowUser(new User
{ {
Username = @"peppy", Username = @"peppy",

View File

@ -66,8 +66,10 @@ namespace osu.Game.Graphics.Containers
{ {
Vector2 offset = (input.CurrentState.Mouse == null ? Vector2.Zero : ToLocalSpace(input.CurrentState.Mouse.NativeState.Position) - DrawSize / 2) * ParallaxAmount; Vector2 offset = (input.CurrentState.Mouse == null ? Vector2.Zero : ToLocalSpace(input.CurrentState.Mouse.NativeState.Position) - DrawSize / 2) * ParallaxAmount;
content.Position = Interpolation.ValueAt(MathHelper.Clamp(Clock.ElapsedFrameTime, 0, 1000), content.Position, offset, 0, 1000, Easing.OutQuint); double elapsed = MathHelper.Clamp(Clock.ElapsedFrameTime, 0, 1000);
content.Scale = new Vector2(1 + ParallaxAmount);
content.Position = Interpolation.ValueAt(elapsed, content.Position, offset, 0, 1000, Easing.OutQuint);
content.Scale = Interpolation.ValueAt(elapsed, content.Scale, new Vector2(1 + ParallaxAmount), 0, 1000, Easing.OutQuint);
} }
firstUpdate = false; firstUpdate = false;

View File

@ -0,0 +1,66 @@
// 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 Humanizer;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Threading;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Graphics
{
public class DrawableDate : OsuSpriteText, IHasTooltip
{
private readonly DateTimeOffset date;
private ScheduledDelegate updateTask;
public DrawableDate(DateTimeOffset date)
{
AutoSizeAxes = Axes.Both;
Font = "Exo2.0-RegularItalic";
this.date = date.ToLocalTime();
}
[BackgroundDependencyLoader]
private void load()
{
updateTime();
}
protected override void LoadComplete()
{
base.LoadComplete();
Scheduler.Add(updateTimeWithReschedule);
}
private void updateTimeWithReschedule()
{
updateTime();
var diffToNow = DateTimeOffset.Now.Subtract(date);
double timeUntilNextUpdate = 1000;
if (diffToNow.TotalSeconds > 60)
{
timeUntilNextUpdate *= 60;
if (diffToNow.TotalMinutes > 60)
{
timeUntilNextUpdate *= 60;
if (diffToNow.TotalHours > 24)
timeUntilNextUpdate *= 24;
}
}
Scheduler.AddDelayed(updateTimeWithReschedule, timeUntilNextUpdate);
}
public override bool HandleMouseInput => true;
private void updateTime() => Text = date.Humanize();
public string TooltipText => date.ToString();
}
}

View File

@ -130,11 +130,7 @@ namespace osu.Game.Overlays.Profile
} }
} }
}, },
infoTextLeft = new OsuTextFlowContainer(t => infoTextLeft = new OsuTextFlowContainer(t => t.TextSize = 14)
{
t.TextSize = 14;
t.Alpha = 0.8f;
})
{ {
X = UserProfileOverlay.CONTENT_X_MARGIN, X = UserProfileOverlay.CONTENT_X_MARGIN,
Y = cover_height + 20, Y = cover_height + 20,
@ -318,11 +314,23 @@ namespace osu.Game.Overlays.Profile
colourBar.Show(); colourBar.Show();
} }
void boldItalic(SpriteText t) void boldItalic(SpriteText t) => t.Font = @"Exo2.0-BoldItalic";
void lightText(SpriteText t) => t.Alpha = 0.8f;
OsuSpriteText createScoreText(string text) => new OsuSpriteText
{ {
t.Font = @"Exo2.0-BoldItalic"; TextSize = 14,
t.Alpha = 1; Text = text
} };
OsuSpriteText createScoreNumberText(string text) => new OsuSpriteText
{
TextSize = 14,
Font = @"Exo2.0-Bold",
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
Text = text
};
if (user.Age != null) if (user.Age != null)
{ {
@ -331,7 +339,7 @@ namespace osu.Game.Overlays.Profile
if (user.Country != null) if (user.Country != null)
{ {
infoTextLeft.AddText("from "); infoTextLeft.AddText("from ", lightText);
infoTextLeft.AddText(user.Country.FullName, boldItalic); infoTextLeft.AddText(user.Country.FullName, boldItalic);
countryFlag.Country = user.Country; countryFlag.Country = user.Country;
} }
@ -344,18 +352,18 @@ namespace osu.Game.Overlays.Profile
} }
else else
{ {
infoTextLeft.AddText("Joined "); infoTextLeft.AddText("Joined ", lightText);
infoTextLeft.AddText(user.JoinDate.LocalDateTime.ToShortDateString(), boldItalic); infoTextLeft.AddText(new DrawableDate(user.JoinDate), boldItalic);
} }
infoTextLeft.NewLine(); infoTextLeft.NewLine();
infoTextLeft.AddText("Last seen "); infoTextLeft.AddText("Last seen ", lightText);
infoTextLeft.AddText(user.LastVisit.LocalDateTime.ToShortDateString(), boldItalic); infoTextLeft.AddText(new DrawableDate(user.LastVisit), boldItalic);
infoTextLeft.NewParagraph(); infoTextLeft.NewParagraph();
if (user.PlayStyle?.Length > 0) if (user.PlayStyle?.Length > 0)
{ {
infoTextLeft.AddText("Plays with "); infoTextLeft.AddText("Plays with ", lightText);
infoTextLeft.AddText(string.Join(", ", user.PlayStyle), boldItalic); infoTextLeft.AddText(string.Join(", ", user.PlayStyle), boldItalic);
} }
@ -411,23 +419,6 @@ namespace osu.Game.Overlays.Profile
} }
} }
// These could be local functions when C# 7 enabled
private OsuSpriteText createScoreText(string text) => new OsuSpriteText
{
TextSize = 14,
Text = text
};
private OsuSpriteText createScoreNumberText(string text) => new OsuSpriteText
{
TextSize = 14,
Font = @"Exo2.0-Bold",
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
Text = text
};
private void tryAddInfoRightLine(FontAwesome icon, string str, string url = null) private void tryAddInfoRightLine(FontAwesome icon, string str, string url = null)
{ {
if (string.IsNullOrEmpty(str)) return; if (string.IsNullOrEmpty(str)) return;
@ -436,10 +427,12 @@ namespace osu.Game.Overlays.Profile
if (url != null) if (url != null)
{ {
infoTextRight.AddLink(" " + str, url); infoTextRight.AddLink(" " + str, url);
} else }
else
{ {
infoTextRight.AddText(" " + str); infoTextRight.AddText(" " + str);
} }
infoTextRight.NewLine(); infoTextRight.NewLine();
} }

View File

@ -95,7 +95,7 @@ namespace osu.Game.Overlays.Profile
{ {
placeholder.FadeIn(fade_duration, Easing.Out); placeholder.FadeIn(fade_duration, Easing.Out);
if (user == null) if (user?.Statistics?.Ranks.Global == null)
{ {
rankText.Text = string.Empty; rankText.Text = string.Empty;
performanceText.Text = string.Empty; performanceText.Text = string.Empty;
@ -105,7 +105,7 @@ namespace osu.Game.Overlays.Profile
return; return;
} }
int[] userRanks = user.RankHistory?.Data ?? new[] { user.Statistics.Ranks.Global }; int[] userRanks = user.RankHistory?.Data ?? new[] { user.Statistics.Ranks.Global.Value };
ranks = userRanks.Select((x, index) => new KeyValuePair<int, int>(index, x)).Where(x => x.Value != 0).ToArray(); ranks = userRanks.Select((x, index) => new KeyValuePair<int, int>(index, x)).Where(x => x.Value != 0).ToArray();
if (ranks.Length > 1) if (ranks.Length > 1)

View File

@ -54,12 +54,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
RightFlowContainer.SetLayoutPosition(text, 1); RightFlowContainer.SetLayoutPosition(text, 1);
LeftFlowContainer.Add(new BeatmapMetadataContainer(Score.Beatmap)); LeftFlowContainer.Add(new BeatmapMetadataContainer(Score.Beatmap));
LeftFlowContainer.Add(new OsuSpriteText LeftFlowContainer.Add(new DrawableDate(Score.Date));
{
Text = Score.Date.LocalDateTime.ToShortDateString(),
TextSize = 11,
Colour = OsuColour.Gray(0xAA),
});
foreach (Mod mod in Score.Mods) foreach (Mod mod in Score.Mods)
modsContainer.Add(new ModIcon(mod) { Scale = new Vector2(0.5f) }); modsContainer.Add(new ModIcon(mod) { Scale = new Vector2(0.5f) });

View File

@ -6,7 +6,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Online.API; using osu.Game.Online.API;
using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests;
using osu.Game.Online.Chat; using osu.Game.Online.Chat;
@ -40,14 +39,12 @@ namespace osu.Game.Overlays.Profile.Sections.Recent
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
}); });
RightFlowContainer.Add(new OsuSpriteText RightFlowContainer.Add(new DrawableDate(activity.CreatedAt)
{ {
Text = activity.CreatedAt.LocalDateTime.ToShortDateString(), TextSize = 13,
Colour = OsuColour.Gray(0xAA),
Anchor = Anchor.TopRight, Anchor = Anchor.TopRight,
Origin = Anchor.TopRight, Origin = Anchor.TopRight,
Font = "Exo2.0-RegularItalic",
TextSize = 12,
Colour = OsuColour.Gray(0xAA),
}); });
var formatted = createMessage(); var formatted = createMessage();

View File

@ -169,6 +169,8 @@ namespace osu.Game.Overlays
{ {
Header.User = user; Header.User = user;
if (user.ProfileOrder != null)
{
foreach (string id in user.ProfileOrder) foreach (string id in user.ProfileOrder)
{ {
var sec = sections.FirstOrDefault(s => s.Identifier == id); var sec = sections.FirstOrDefault(s => s.Identifier == id);
@ -181,6 +183,7 @@ namespace osu.Game.Overlays
} }
} }
} }
}
private class ProfileTabControl : PageTabControl<ProfileSection> private class ProfileTabControl : PageTabControl<ProfileSection>
{ {

View File

@ -9,6 +9,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Judgements namespace osu.Game.Rulesets.Judgements
@ -20,15 +21,18 @@ namespace osu.Game.Rulesets.Judgements
{ {
protected readonly Judgement Judgement; protected readonly Judgement Judgement;
public readonly DrawableHitObject JudgedObject;
protected readonly SpriteText JudgementText; protected readonly SpriteText JudgementText;
/// <summary> /// <summary>
/// Creates a drawable which visualises a <see cref="Judgements.Judgement"/>. /// Creates a drawable which visualises a <see cref="Judgements.Judgement"/>.
/// </summary> /// </summary>
/// <param name="judgement">The judgement to visualise.</param> /// <param name="judgement">The judgement to visualise.</param>
public DrawableJudgement(Judgement judgement) public DrawableJudgement(Judgement judgement, DrawableHitObject judgedObject)
{ {
Judgement = judgement; Judgement = judgement;
JudgedObject = judgedObject;
AutoSizeAxes = Axes.Both; AutoSizeAxes = Axes.Both;

View File

@ -63,7 +63,7 @@ namespace osu.Game.Rulesets
var instances = loaded_assemblies.Values.Select(r => (Ruleset)Activator.CreateInstance(r, (RulesetInfo)null)).ToList(); var instances = loaded_assemblies.Values.Select(r => (Ruleset)Activator.CreateInstance(r, (RulesetInfo)null)).ToList();
//add all legacy modes in correct order //add all legacy modes in correct order
foreach (var r in instances.Where(r => r.LegacyID >= 0).OrderBy(r => r.LegacyID)) foreach (var r in instances.Where(r => r.LegacyID != null).OrderBy(r => r.LegacyID))
{ {
if (context.RulesetInfo.SingleOrDefault(rsi => rsi.ID == r.RulesetInfo.ID) == null) if (context.RulesetInfo.SingleOrDefault(rsi => rsi.ID == r.RulesetInfo.ID) == null)
context.RulesetInfo.Add(r.RulesetInfo); context.RulesetInfo.Add(r.RulesetInfo);
@ -72,7 +72,7 @@ namespace osu.Game.Rulesets
context.SaveChanges(); context.SaveChanges();
//add any other modes //add any other modes
foreach (var r in instances.Where(r => r.LegacyID < 0)) foreach (var r in instances.Where(r => r.LegacyID == null))
if (context.RulesetInfo.FirstOrDefault(ri => ri.InstantiationInfo == r.RulesetInfo.InstantiationInfo) == null) if (context.RulesetInfo.FirstOrDefault(ri => ri.InstantiationInfo == r.RulesetInfo.InstantiationInfo) == null)
context.RulesetInfo.Add(r.RulesetInfo); context.RulesetInfo.Add(r.RulesetInfo);

View File

@ -0,0 +1,24 @@
// 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.Framework.Graphics.Containers;
using osu.Game.Rulesets.Judgements;
namespace osu.Game.Rulesets.UI
{
public class JudgementContainer<T> : Container<T>
where T : DrawableJudgement
{
public override void Add(T judgement)
{
if (judgement == null) throw new ArgumentNullException(nameof(judgement));
// remove any existing judgements for the judged object.
// this can be the case when rewinding.
RemoveAll(c => c.JudgedObject == judgement.JudgedObject);
base.Add(judgement);
}
}
}

View File

@ -1,13 +1,13 @@
// 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.Framework.Graphics.Containers;
using osu.Framework.Graphics;
using osu.Game.Graphics;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics;
using OpenTK;
namespace osu.Game.Screens.Play.BreaksOverlay namespace osu.Game.Screens.Play.Break
{ {
public class BlurredIcon : BufferedContainer public class BlurredIcon : BufferedContainer
{ {

View File

@ -1,18 +1,15 @@
// 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.Graphics.Containers;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using OpenTK; using osu.Framework.Graphics.Containers;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Beatmaps.Timing; using OpenTK;
namespace osu.Game.Screens.Play.BreaksOverlay namespace osu.Game.Screens.Play.Break
{ {
public class ArrowsOverlay : VisibilityContainer public class BreakArrows : CompositeDrawable
{ {
private const double fade_duration = BreakPeriod.MIN_BREAK_DURATION / 2;
private const int glow_icon_size = 60; private const int glow_icon_size = 60;
private const int glow_icon_blur_sigma = 10; private const int glow_icon_blur_sigma = 10;
private const float glow_icon_final_offset = 0.22f; private const float glow_icon_final_offset = 0.22f;
@ -29,10 +26,10 @@ namespace osu.Game.Screens.Play.BreaksOverlay
private readonly BlurredIcon leftBlurredIcon; private readonly BlurredIcon leftBlurredIcon;
private readonly BlurredIcon rightBlurredIcon; private readonly BlurredIcon rightBlurredIcon;
public ArrowsOverlay() public BreakArrows()
{ {
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.Both;
Children = new Drawable[] InternalChildren = new Drawable[]
{ {
leftGlowIcon = new GlowIcon leftGlowIcon = new GlowIcon
{ {
@ -82,22 +79,22 @@ namespace osu.Game.Screens.Play.BreaksOverlay
}; };
} }
protected override void PopIn() public void Show(double duration)
{ {
leftGlowIcon.MoveToX(-glow_icon_final_offset, fade_duration, Easing.OutQuint); leftGlowIcon.MoveToX(-glow_icon_final_offset, duration, Easing.OutQuint);
rightGlowIcon.MoveToX(glow_icon_final_offset, fade_duration, Easing.OutQuint); rightGlowIcon.MoveToX(glow_icon_final_offset, duration, Easing.OutQuint);
leftBlurredIcon.MoveToX(-blurred_icon_final_offset, fade_duration, Easing.OutQuint); leftBlurredIcon.MoveToX(-blurred_icon_final_offset, duration, Easing.OutQuint);
rightBlurredIcon.MoveToX(blurred_icon_final_offset, fade_duration, Easing.OutQuint); rightBlurredIcon.MoveToX(blurred_icon_final_offset, duration, Easing.OutQuint);
} }
protected override void PopOut() public void Hide(double duration)
{ {
leftGlowIcon.MoveToX(-glow_icon_offscreen_offset, fade_duration, Easing.OutQuint); leftGlowIcon.MoveToX(-glow_icon_offscreen_offset, duration, Easing.OutQuint);
rightGlowIcon.MoveToX(glow_icon_offscreen_offset, fade_duration, Easing.OutQuint); rightGlowIcon.MoveToX(glow_icon_offscreen_offset, duration, Easing.OutQuint);
leftBlurredIcon.MoveToX(-blurred_icon_offscreen_offset, fade_duration, Easing.OutQuint); leftBlurredIcon.MoveToX(-blurred_icon_offscreen_offset, duration, Easing.OutQuint);
rightBlurredIcon.MoveToX(blurred_icon_offscreen_offset, fade_duration, Easing.OutQuint); rightBlurredIcon.MoveToX(blurred_icon_offscreen_offset, duration, Easing.OutQuint);
} }
} }
} }

View File

@ -1,24 +1,21 @@
// 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.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Beatmaps.Timing; using OpenTK;
namespace osu.Game.Screens.Play.BreaksOverlay namespace osu.Game.Screens.Play.Break
{ {
public class InfoContainer : VisibilityContainer public class BreakInfo : Container
{ {
private const double fade_duration = BreakPeriod.MIN_BREAK_DURATION / 2; public PercentageBreakInfoLine AccuracyDisplay;
public BreakInfoLine<int> RankDisplay;
public BreakInfoLine<ScoreRank> GradeDisplay;
public PercentageInfoLine AccuracyDisplay; public BreakInfo()
public InfoLine<int> RankDisplay;
public InfoLine<ScoreRank> GradeDisplay;
public InfoContainer()
{ {
AutoSizeAxes = Axes.Both; AutoSizeAxes = Axes.Both;
Child = new FillFlowContainer Child = new FillFlowContainer
@ -43,16 +40,13 @@ namespace osu.Game.Screens.Play.BreaksOverlay
Direction = FillDirection.Vertical, Direction = FillDirection.Vertical,
Children = new Drawable[] Children = new Drawable[]
{ {
AccuracyDisplay = new PercentageInfoLine("Accuracy"), AccuracyDisplay = new PercentageBreakInfoLine("Accuracy"),
RankDisplay = new InfoLine<int>("Rank"), RankDisplay = new BreakInfoLine<int>("Rank"),
GradeDisplay = new InfoLine<ScoreRank>("Grade"), GradeDisplay = new BreakInfoLine<ScoreRank>("Grade"),
}, },
} }
}, },
}; };
} }
protected override void PopIn() => this.FadeIn(fade_duration);
protected override void PopOut() => this.FadeOut(fade_duration);
} }
} }

View File

@ -8,9 +8,9 @@ using osu.Framework.Graphics.Containers;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
namespace osu.Game.Screens.Play.BreaksOverlay namespace osu.Game.Screens.Play.Break
{ {
public class InfoLine<T> : Container public class BreakInfoLine<T> : Container
where T : struct where T : struct
{ {
private const int margin = 2; private const int margin = 2;
@ -22,7 +22,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay
private readonly string prefix; private readonly string prefix;
public InfoLine(string name, string prefix = @"") public BreakInfoLine(string name, string prefix = @"")
{ {
this.prefix = prefix; this.prefix = prefix;
@ -71,9 +71,9 @@ namespace osu.Game.Screens.Play.BreaksOverlay
} }
} }
public class PercentageInfoLine : InfoLine<double> public class PercentageBreakInfoLine : BreakInfoLine<double>
{ {
public PercentageInfoLine(string name, string prefix = "") : base(name, prefix) public PercentageBreakInfoLine(string name, string prefix = "") : base(name, prefix)
{ {
} }

View File

@ -1,13 +1,13 @@
// 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.Graphics.Containers; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics; using osu.Game.Graphics;
using OpenTK; using OpenTK;
using osu.Framework.Allocation;
namespace osu.Game.Screens.Play.BreaksOverlay namespace osu.Game.Screens.Play.Break
{ {
public class GlowIcon : Container public class GlowIcon : Container
{ {
@ -16,24 +16,24 @@ namespace osu.Game.Screens.Play.BreaksOverlay
public override Vector2 Size public override Vector2 Size
{ {
get { return base.Size; }
set set
{ {
blurredIcon.Size = spriteIcon.Size = value; blurredIcon.Size = spriteIcon.Size = value;
blurredIcon.ForceRedraw(); blurredIcon.ForceRedraw();
} }
get { return base.Size; }
} }
public Vector2 BlurSigma public Vector2 BlurSigma
{ {
set { blurredIcon.BlurSigma = value; }
get { return blurredIcon.BlurSigma; } get { return blurredIcon.BlurSigma; }
set { blurredIcon.BlurSigma = value; }
} }
public FontAwesome Icon public FontAwesome Icon
{ {
set { spriteIcon.Icon = blurredIcon.Icon = value; }
get { return spriteIcon.Icon; } get { return spriteIcon.Icon; }
set { spriteIcon.Icon = blurredIcon.Icon = value; }
} }
public GlowIcon() public GlowIcon()

View File

@ -1,18 +1,16 @@
// 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.Graphics;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps.Timing; using OpenTK.Graphics;
namespace osu.Game.Screens.Play.BreaksOverlay namespace osu.Game.Screens.Play.Break
{ {
public class LetterboxOverlay : VisibilityContainer public class LetterboxOverlay : CompositeDrawable
{ {
private const double fade_duration = BreakPeriod.MIN_BREAK_DURATION / 2;
private const int height = 350; private const int height = 350;
private static readonly Color4 transparent_black = new Color4(0, 0, 0, 0); private static readonly Color4 transparent_black = new Color4(0, 0, 0, 0);
@ -20,7 +18,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay
public LetterboxOverlay() public LetterboxOverlay()
{ {
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.Both;
Children = new Drawable[] InternalChildren = new Drawable[]
{ {
new Container new Container
{ {
@ -48,8 +46,5 @@ namespace osu.Game.Screens.Play.BreaksOverlay
} }
}; };
} }
protected override void PopIn() => this.FadeIn(fade_duration);
protected override void PopOut() => this.FadeOut(fade_duration);
} }
} }

View File

@ -1,18 +1,15 @@
// 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.Game.Graphics.Sprites;
using osu.Framework.Graphics;
using System; using System;
using osu.Game.Beatmaps.Timing; using osu.Framework.Graphics;
using osu.Framework.Graphics.UserInterface; using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Screens.Play.BreaksOverlay namespace osu.Game.Screens.Play.Break
{ {
public class RemainingTimeCounter : Counter public class RemainingTimeCounter : Counter
{ {
private const double fade_duration = BreakPeriod.MIN_BREAK_DURATION / 2;
private readonly OsuSpriteText counter; private readonly OsuSpriteText counter;
public RemainingTimeCounter() public RemainingTimeCounter()
@ -25,13 +22,8 @@ namespace osu.Game.Screens.Play.BreaksOverlay
TextSize = 33, TextSize = 33,
Font = "Venera", Font = "Venera",
}; };
Alpha = 0;
} }
protected override void OnCountChanged(double count) => counter.Text = ((int)Math.Ceiling(count / 1000)).ToString(); protected override void OnCountChanged(double count) => counter.Text = ((int)Math.Ceiling(count / 1000)).ToString();
public override void Show() => this.FadeIn(fade_duration);
public override void Hide() => this.FadeOut(fade_duration);
} }
} }

View File

@ -1,15 +1,16 @@
// 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.Collections.Generic;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Beatmaps.Timing; using osu.Game.Beatmaps.Timing;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using System.Collections.Generic; using osu.Game.Screens.Play.Break;
using osu.Framework.Graphics.UserInterface;
namespace osu.Game.Screens.Play.BreaksOverlay namespace osu.Game.Screens.Play
{ {
public class BreakOverlay : Container public class BreakOverlay : Container
{ {
@ -18,28 +19,26 @@ namespace osu.Game.Screens.Play.BreaksOverlay
private const int vertical_margin = 25; private const int vertical_margin = 25;
private List<BreakPeriod> breaks; private List<BreakPeriod> breaks;
private readonly Container fadeContainer;
public List<BreakPeriod> Breaks public List<BreakPeriod> Breaks
{ {
get => breaks;
set set
{ {
breaks = value; breaks = value;
initializeBreaks(); initializeBreaks();
} }
get
{
return breaks;
}
} }
public override bool RemoveCompletedTransforms => false; public override bool RemoveCompletedTransforms => false;
private readonly bool letterboxing;
private readonly LetterboxOverlay letterboxOverlay;
private readonly Container remainingTimeAdjustmentBox; private readonly Container remainingTimeAdjustmentBox;
private readonly Container remainingTimeBox; private readonly Container remainingTimeBox;
private readonly RemainingTimeCounter remainingTimeCounter; private readonly RemainingTimeCounter remainingTimeCounter;
private readonly InfoContainer info; private readonly BreakInfo info;
private readonly ArrowsOverlay arrowsOverlay; private readonly BreakArrows breakArrows;
public BreakOverlay(bool letterboxing, ScoreProcessor scoreProcessor) public BreakOverlay(bool letterboxing, ScoreProcessor scoreProcessor)
: this(letterboxing) : this(letterboxing)
@ -49,13 +48,16 @@ namespace osu.Game.Screens.Play.BreaksOverlay
public BreakOverlay(bool letterboxing) public BreakOverlay(bool letterboxing)
{ {
this.letterboxing = letterboxing;
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.Both;
Child = fadeContainer = new Container
{
Alpha = 0,
RelativeSizeAxes = Axes.Both,
Children = new Drawable[] Children = new Drawable[]
{ {
letterboxOverlay = new LetterboxOverlay new LetterboxOverlay
{ {
Alpha = letterboxing ? 1 : 0,
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
}, },
@ -83,27 +85,35 @@ namespace osu.Game.Screens.Play.BreaksOverlay
Origin = Anchor.BottomCentre, Origin = Anchor.BottomCentre,
Margin = new MarginPadding { Bottom = vertical_margin }, Margin = new MarginPadding { Bottom = vertical_margin },
}, },
info = new InfoContainer info = new BreakInfo
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.TopCentre, Origin = Anchor.TopCentre,
Margin = new MarginPadding { Top = vertical_margin }, Margin = new MarginPadding { Top = vertical_margin },
}, },
arrowsOverlay = new ArrowsOverlay breakArrows = new BreakArrows
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
} }
}
}; };
} }
protected override void LoadComplete()
{
base.LoadComplete();
initializeBreaks();
}
private void initializeBreaks() private void initializeBreaks()
{ {
if (!IsLoaded) return; // we need a clock.
FinishTransforms(true); FinishTransforms(true);
Scheduler.CancelDelayedTasks(); Scheduler.CancelDelayedTasks();
if (breaks == null) if (breaks == null) return; //we need breaks.
return;
foreach (var b in breaks) foreach (var b in breaks)
{ {
@ -112,6 +122,9 @@ namespace osu.Game.Screens.Play.BreaksOverlay
using (BeginAbsoluteSequence(b.StartTime, true)) using (BeginAbsoluteSequence(b.StartTime, true))
{ {
fadeContainer.FadeIn(fade_duration);
breakArrows.Show(fade_duration);
remainingTimeAdjustmentBox remainingTimeAdjustmentBox
.ResizeWidthTo(remaining_time_container_max_size, fade_duration, Easing.OutQuint) .ResizeWidthTo(remaining_time_container_max_size, fade_duration, Easing.OutQuint)
.Delay(b.Duration - fade_duration) .Delay(b.Duration - fade_duration)
@ -123,35 +136,14 @@ namespace osu.Game.Screens.Play.BreaksOverlay
.ResizeWidthTo(1); .ResizeWidthTo(1);
remainingTimeCounter.CountTo(b.Duration).CountTo(0, b.Duration); remainingTimeCounter.CountTo(b.Duration).CountTo(0, b.Duration);
}
using (BeginAbsoluteSequence(b.StartTime)) using (BeginDelayedSequence(b.Duration - fade_duration, true))
{ {
Schedule(showBreak); fadeContainer.FadeOut(fade_duration);
using (BeginDelayedSequence(b.Duration - fade_duration)) breakArrows.Hide(fade_duration);
Schedule(hideBreak);
} }
} }
} }
private void showBreak()
{
if (letterboxing)
letterboxOverlay.Show();
remainingTimeCounter.Show();
info.Show();
arrowsOverlay.Show();
}
private void hideBreak()
{
if (letterboxing)
letterboxOverlay.Hide();
remainingTimeCounter.Hide();
info.Hide();
arrowsOverlay.Hide();
} }
private void bindProcessor(ScoreProcessor processor) private void bindProcessor(ScoreProcessor processor)

View File

@ -25,7 +25,6 @@ using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using osu.Game.Screens.Play.BreaksOverlay;
using osu.Game.Screens.Ranking; using osu.Game.Screens.Ranking;
using osu.Game.Storyboards.Drawables; using osu.Game.Storyboards.Drawables;

View File

@ -169,20 +169,43 @@ namespace osu.Game.Screens.Select
}); });
} }
public void SelectBeatmap(BeatmapInfo beatmap) /// <summary>
/// Selects a given beatmap on the carousel.
///
/// If bypassFilters is false, we will try to select another unfiltered beatmap in the same set. If the
/// entire set is filtered, no selection is made.
/// </summary>
/// <param name="beatmap">The beatmap to select.</param>
/// <param name="bypassFilters">Whether to select the beatmap even if it is filtered (i.e., not visible on carousel).</param>
/// <returns>True if a selection was made, False if it wasn't.</returns>
public bool SelectBeatmap(BeatmapInfo beatmap, bool bypassFilters = true)
{ {
if (beatmap?.Hidden != false) if (beatmap?.Hidden != false)
return; return false;
foreach (CarouselBeatmapSet group in beatmapSets) foreach (CarouselBeatmapSet set in beatmapSets)
{ {
var item = group.Beatmaps.FirstOrDefault(p => p.Beatmap.Equals(beatmap)); if (!bypassFilters && set.Filtered)
continue;
var item = set.Beatmaps.FirstOrDefault(p => p.Beatmap.Equals(beatmap));
if (item == null)
// The beatmap that needs to be selected doesn't exist in this set
continue;
if (!bypassFilters && item.Filtered)
// The beatmap exists in this set but is filtered, so look for the first unfiltered map in the set
item = set.Beatmaps.FirstOrDefault(b => !b.Filtered);
if (item != null) if (item != null)
{ {
select(item); select(item);
return; return true;
} }
} }
return false;
} }
/// <summary> /// <summary>

View File

@ -214,11 +214,7 @@ namespace osu.Game.Screens.Select
Beatmap.DisabledChanged += disabled => Carousel.AllowSelection = !disabled; Beatmap.DisabledChanged += disabled => Carousel.AllowSelection = !disabled;
Beatmap.TriggerChange(); Beatmap.TriggerChange();
Beatmap.ValueChanged += b => Beatmap.ValueChanged += workingBeatmapChanged;
{
if (IsCurrentScreen)
Carousel.SelectBeatmap(b?.BeatmapInfo);
};
} }
public void Edit(BeatmapInfo beatmap) public void Edit(BeatmapInfo beatmap)
@ -261,6 +257,17 @@ namespace osu.Game.Screens.Select
// We need to keep track of the last selected beatmap ignoring debounce to play the correct selection sounds. // We need to keep track of the last selected beatmap ignoring debounce to play the correct selection sounds.
private BeatmapInfo beatmapNoDebounce; private BeatmapInfo beatmapNoDebounce;
private void workingBeatmapChanged(WorkingBeatmap beatmap)
{
if (IsCurrentScreen && !Carousel.SelectBeatmap(beatmap?.BeatmapInfo, false))
// If selecting new beatmap without bypassing filters failed, there's possibly a ruleset mismatch
if (beatmap?.BeatmapInfo?.Ruleset != null && beatmap.BeatmapInfo.Ruleset != Ruleset.Value)
{
Ruleset.Value = beatmap.BeatmapInfo.Ruleset;
Carousel.SelectBeatmap(beatmap.BeatmapInfo);
}
}
/// <summary> /// <summary>
/// selection has been changed as the result of interaction with the carousel. /// selection has been changed as the result of interaction with the carousel.
/// </summary> /// </summary>
@ -450,13 +457,11 @@ namespace osu.Game.Screens.Select
private void carouselBeatmapsLoaded() private void carouselBeatmapsLoaded()
{ {
if (!Beatmap.IsDefault && Beatmap.Value.BeatmapSetInfo?.DeletePending == false && Beatmap.Value.BeatmapSetInfo?.Protected == false) if (!Beatmap.IsDefault && Beatmap.Value.BeatmapSetInfo?.DeletePending == false && Beatmap.Value.BeatmapSetInfo?.Protected == false && Carousel.SelectBeatmap(Beatmap.Value.BeatmapInfo, false))
return;
if (Carousel.SelectedBeatmapSet == null && !Carousel.SelectNextRandom())
{ {
Carousel.SelectBeatmap(Beatmap.Value.BeatmapInfo);
}
else if (Carousel.SelectedBeatmapSet == null)
{
if (!Carousel.SelectNextRandom())
// 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); carouselSelectionChanged(null);

View File

@ -128,7 +128,7 @@ namespace osu.Game.Tests.Visual
private void load(BeatmapManager beatmaps) private void load(BeatmapManager beatmaps)
{ {
var sets = beatmaps.GetAllUsableBeatmapSets(); var sets = beatmaps.GetAllUsableBeatmapSets();
var allBeatmaps = sets.SelectMany(s => s.Beatmaps).Where(b => ruleset.LegacyID < 0 || b.RulesetID == ruleset.LegacyID); var allBeatmaps = sets.SelectMany(s => s.Beatmaps).Where(b => ruleset.LegacyID == null || b.RulesetID == ruleset.LegacyID);
allBeatmaps.ForEach(b => beatmapDisplays.Add(new BeatmapDisplay(b))); allBeatmaps.ForEach(b => beatmapDisplays.Add(new BeatmapDisplay(b)));
} }

View File

@ -73,10 +73,10 @@ namespace osu.Game.Users
public struct UserRanks public struct UserRanks
{ {
[JsonProperty(@"global")] [JsonProperty(@"global")]
public int Global; public int? Global;
[JsonProperty(@"country")] [JsonProperty(@"country")]
public int Country; public int? Country;
} }
} }

View File

@ -287,6 +287,7 @@
<Compile Include="Database\MutableDatabaseBackedStore.cs" /> <Compile Include="Database\MutableDatabaseBackedStore.cs" />
<Compile Include="Database\SingletonContextFactory.cs" /> <Compile Include="Database\SingletonContextFactory.cs" />
<Compile Include="Graphics\Containers\LinkFlowContainer.cs" /> <Compile Include="Graphics\Containers\LinkFlowContainer.cs" />
<Compile Include="Graphics\DrawableDate.cs" />
<Compile Include="Graphics\Textures\LargeTextureStore.cs" /> <Compile Include="Graphics\Textures\LargeTextureStore.cs" />
<Compile Include="IO\Archives\ArchiveReader.cs" /> <Compile Include="IO\Archives\ArchiveReader.cs" />
<Compile Include="IO\Archives\LegacyFilesystemReader.cs" /> <Compile Include="IO\Archives\LegacyFilesystemReader.cs" />
@ -378,6 +379,7 @@
<Compile Include="Rulesets\Replays\ReplayFrame.cs" /> <Compile Include="Rulesets\Replays\ReplayFrame.cs" />
<Compile Include="Rulesets\Replays\Types\IConvertibleReplayFrame.cs" /> <Compile Include="Rulesets\Replays\Types\IConvertibleReplayFrame.cs" />
<Compile Include="Rulesets\Scoring\Legacy\LegacyScoreParser.cs" /> <Compile Include="Rulesets\Scoring\Legacy\LegacyScoreParser.cs" />
<Compile Include="Rulesets\UI\JudgementContainer.cs" />
<Compile Include="Screens\Play\ScreenWithBeatmapBackground.cs" /> <Compile Include="Screens\Play\ScreenWithBeatmapBackground.cs" />
<Compile Include="Screens\Play\PlayerSettings\VisualSettings.cs" /> <Compile Include="Screens\Play\PlayerSettings\VisualSettings.cs" />
<Compile Include="Rulesets\Objects\CatmullApproximator.cs" /> <Compile Include="Rulesets\Objects\CatmullApproximator.cs" />
@ -409,14 +411,14 @@
<Compile Include="Screens\Edit\Screens\Compose\RadioButtons\RadioButtonCollection.cs" /> <Compile Include="Screens\Edit\Screens\Compose\RadioButtons\RadioButtonCollection.cs" />
<Compile Include="Screens\Edit\Screens\Compose\Timeline\BeatmapWaveformGraph.cs" /> <Compile Include="Screens\Edit\Screens\Compose\Timeline\BeatmapWaveformGraph.cs" />
<Compile Include="Screens\Edit\Screens\Compose\Timeline\TimelineButton.cs" /> <Compile Include="Screens\Edit\Screens\Compose\Timeline\TimelineButton.cs" />
<Compile Include="Screens\Play\BreaksOverlay\ArrowsOverlay.cs" /> <Compile Include="Screens\Play\Break\BreakArrows.cs" />
<Compile Include="Screens\Play\BreaksOverlay\BlurredIcon.cs" /> <Compile Include="Screens\Play\Break\BlurredIcon.cs" />
<Compile Include="Screens\Play\BreaksOverlay\BreakOverlay.cs" /> <Compile Include="Screens\Play\BreakOverlay.cs" />
<Compile Include="Screens\Play\BreaksOverlay\GlowIcon.cs" /> <Compile Include="Screens\Play\Break\GlowIcon.cs" />
<Compile Include="Screens\Play\BreaksOverlay\InfoContainer.cs" /> <Compile Include="Screens\Play\Break\BreakInfo.cs" />
<Compile Include="Screens\Play\BreaksOverlay\InfoLine.cs" /> <Compile Include="Screens\Play\Break\BreakInfoLine.cs" />
<Compile Include="Screens\Play\BreaksOverlay\LetterboxOverlay.cs" /> <Compile Include="Screens\Play\Break\LetterboxOverlay.cs" />
<Compile Include="Screens\Play\BreaksOverlay\RemainingTimeCounter.cs" /> <Compile Include="Screens\Play\Break\RemainingTimeCounter.cs" />
<Compile Include="Beatmaps\Legacy\LegacyBeatmap.cs" /> <Compile Include="Beatmaps\Legacy\LegacyBeatmap.cs" />
<Compile Include="Beatmaps\RankStatus.cs" /> <Compile Include="Beatmaps\RankStatus.cs" />
<Compile Include="Beatmaps\Timing\BreakPeriod.cs" /> <Compile Include="Beatmaps\Timing\BreakPeriod.cs" />