1
0
mirror of https://github.com/ppy/osu.git synced 2026-05-19 02:29:53 +08:00

Compare commits

..

346 Commits

144 changed files with 3227 additions and 2041 deletions
+10 -4
View File
@@ -18,9 +18,12 @@ namespace osu.Desktop
{
internal class OsuGameDesktop : OsuGame
{
private readonly bool noVersionOverlay;
public OsuGameDesktop(string[] args = null)
: base(args)
{
noVersionOverlay = args?.Any(a => a == "--no-version-overlay") ?? false;
}
public override Storage GetStorageForStableInstall()
@@ -79,11 +82,14 @@ namespace osu.Desktop
{
base.LoadComplete();
LoadComponentAsync(new VersionManager { Depth = int.MinValue }, v =>
if (!noVersionOverlay)
{
Add(v);
v.State = Visibility.Visible;
});
LoadComponentAsync(new VersionManager { Depth = int.MinValue }, v =>
{
Add(v);
v.State = Visibility.Visible;
});
}
}
public override void SetHost(GameHost host)
+2 -1
View File
@@ -233,7 +233,8 @@ namespace osu.Desktop.Overlays
Text = @"Update ready to install. Click to restart!",
Activated = () =>
{
UpdateManager.RestartAppWhenExited();
// Squirrel returns execution to us after the update process is started, so it's safe to use Wait() here
UpdateManager.RestartAppWhenExited().Wait();
game.GracefullyExit();
return true;
}
@@ -14,11 +14,8 @@ namespace osu.Game.Rulesets.Catch
{
}
protected override double CalculateInternal(Dictionary<string, string> categoryDifficulty)
{
return 0;
}
public override double Calculate(Dictionary<string, string> categoryDifficulty = null) => 0;
protected override BeatmapConverter<CatchBaseHit> CreateBeatmapConverter() => new CatchBeatmapConverter();
protected override BeatmapConverter<CatchBaseHit> CreateBeatmapConverter(Beatmap beatmap) => new CatchBeatmapConverter();
}
}
}
+1 -1
View File
@@ -95,7 +95,7 @@ namespace osu.Game.Rulesets.Catch
public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_fruits_o };
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap) => new CatchDifficultyCalculator(beatmap);
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null) => new CatchDifficultyCalculator(beatmap);
public override int LegacyID => 2;
@@ -16,11 +16,8 @@ namespace osu.Game.Rulesets.Mania
{
}
protected override double CalculateInternal(Dictionary<string, string> categoryDifficulty)
{
return 0;
}
public override double Calculate(Dictionary<string, string> categoryDifficulty = null) => 0;
protected override BeatmapConverter<ManiaHitObject> CreateBeatmapConverter() => new ManiaBeatmapConverter(true, (int)Math.Max(1, Math.Round(Beatmap.BeatmapInfo.BaseDifficulty.CircleSize)));
protected override BeatmapConverter<ManiaHitObject> CreateBeatmapConverter(Beatmap beatmap) => new ManiaBeatmapConverter(true, (int)Math.Max(1, Math.Round(beatmap.BeatmapInfo.BaseDifficulty.CircleSize)));
}
}
+1 -1
View File
@@ -107,7 +107,7 @@ namespace osu.Game.Rulesets.Mania
public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_mania_o };
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap) => new ManiaDifficultyCalculator(beatmap);
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null) => new ManiaDifficultyCalculator(beatmap);
public override int LegacyID => 3;
+3 -3
View File
@@ -86,18 +86,17 @@ namespace osu.Game.Rulesets.Mania.Mods
public override Type[] IncompatibleMods => new[] { typeof(ModFlashlight) };
}
public class ManiaModRandom : Mod, IApplicableMod<ManiaHitObject>
public class ManiaModRandom : Mod, IApplicableToRulesetContainer<ManiaHitObject>
{
public override string Name => "Random";
public override string ShortenedName => "RD";
public override FontAwesome Icon => FontAwesome.fa_osu_dice;
public override FontAwesome Icon => FontAwesome.fa_osu_dice;
public override string Description => @"Shuffle around the notes!";
public override double ScoreMultiplier => 1;
public void ApplyToRulesetContainer(RulesetContainer<ManiaHitObject> rulesetContainer)
{
int availableColumns = ((ManiaRulesetContainer)rulesetContainer).AvailableColumns;
var shuffledColumns = Enumerable.Range(0, availableColumns).OrderBy(item => RNG.Next()).ToList();
rulesetContainer.Objects.OfType<ManiaHitObject>().ForEach(h => h.Column = shuffledColumns[h.Column]);
@@ -188,6 +187,7 @@ namespace osu.Game.Rulesets.Mania.Mods
base.ApplyToRulesetContainer(rulesetContainer);
}
protected override Score CreateReplayScore(Beatmap<ManiaHitObject> beatmap) => new Score
{
User = new User { Username = "osu!topus!" },
@@ -94,7 +94,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
protected override void UpdateState(ArmedState state)
{
switch (State)
switch (State.Value)
{
case ArmedState.Hit:
AccentColour = Color4.Green;
+3 -1
View File
@@ -57,8 +57,10 @@ namespace osu.Game.Rulesets.Mania.UI
{
base.LoadComplete();
this.ScaleTo(2f, 600, Easing.OutQuint).FadeOut(500).Expire();
this.ScaleTo(2f, 600, Easing.OutQuint).FadeOut(500);
inner.FadeOut(250);
Expire(true);
}
}
}
+17 -11
View File
@@ -9,7 +9,6 @@ using osu.Game.Rulesets.Osu.Objects;
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Game.Rulesets.Osu.UI;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
@@ -33,22 +32,29 @@ namespace osu.Game.Rulesets.Osu.Mods
public override double ScoreMultiplier => 1.06;
}
public class OsuModHardRock : ModHardRock, IApplicableMod<OsuHitObject>
public class OsuModHardRock : ModHardRock, IApplicableToHitObject<OsuHitObject>
{
public override double ScoreMultiplier => 1.06;
public override bool Ranked => true;
public void ApplyToRulesetContainer(RulesetContainer<OsuHitObject> rulesetContainer)
public void ApplyToHitObject(OsuHitObject hitObject)
{
hitObject.Position = new Vector2(hitObject.Position.X, OsuPlayfield.BASE_SIZE.Y - hitObject.Y);
var slider = hitObject as Slider;
if (slider == null)
return;
var newControlPoints = new List<Vector2>();
slider.ControlPoints.ForEach(c => newControlPoints.Add(new Vector2(c.X, OsuPlayfield.BASE_SIZE.Y - c.Y)));
slider.ControlPoints = newControlPoints;
slider.Curve?.Calculate(); // Recalculate the slider curve
}
public void ApplyToHitObjects(RulesetContainer<OsuHitObject> rulesetContainer)
{
rulesetContainer.Objects.OfType<OsuHitObject>().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Y));
rulesetContainer.Objects.OfType<Slider>().ForEach(s =>
{
var newControlPoints = new List<Vector2>();
s.ControlPoints.ForEach(c => newControlPoints.Add(new Vector2(c.X, OsuPlayfield.BASE_SIZE.Y - c.Y)));
s.ControlPoints = newControlPoints;
s.Curve?.Calculate(); // Recalculate the slider curve
});
}
}
@@ -14,6 +14,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
{
private const float width = 8;
public override bool RemoveWhenNotAlive => false;
public FollowPoint()
{
Origin = Anchor.Centre;
@@ -52,9 +52,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
}
}
public override bool RemoveCompletedTransforms => false;
private void update()
{
Clear();
if (hitObjects == null)
return;
@@ -58,6 +58,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
},
ApproachCircle = new ApproachCircle
{
Alpha = 0,
Scale = new Vector2(4),
Colour = AccentColour,
}
};
@@ -82,21 +84,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
});
}
protected override void UpdateInitialState()
{
base.UpdateInitialState();
// sane defaults
ring.Show();
circle.Show();
number.Show();
glow.Show();
ApproachCircle.Hide();
ApproachCircle.ScaleTo(new Vector2(4));
explode.Hide();
}
protected override void UpdatePreemptState()
{
base.UpdatePreemptState();
@@ -23,12 +23,13 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
protected sealed override void UpdateState(ArmedState state)
{
FinishTransforms();
double transformTime = HitObject.StartTime - TIME_PREEMPT;
using (BeginAbsoluteSequence(HitObject.StartTime - TIME_PREEMPT, true))
base.ApplyTransformsAt(transformTime, true);
base.ClearTransformsAfter(transformTime, true);
using (BeginAbsoluteSequence(transformTime, true))
{
UpdateInitialState();
UpdatePreemptState();
using (BeginDelayedSequence(TIME_PREEMPT + (Judgements.FirstOrDefault()?.TimeOffset ?? 0), true))
@@ -36,11 +37,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
}
}
protected virtual void UpdateInitialState()
{
Hide();
}
protected virtual void UpdatePreemptState()
{
this.FadeIn(TIME_FADEIN);
@@ -50,6 +46,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
}
// Todo: At some point we need to move these to DrawableHitObject after ensuring that all other Rulesets apply
// transforms in the same way and don't rely on them not being cleared
public override void ClearTransformsAfter(double time, bool propagateChildren = false, string targetMember = null) { }
public override void ApplyTransformsAt(double time, bool propagateChildren = false) { }
private OsuInputManager osuActionInputManager;
internal OsuInputManager OsuActionInputManager => osuActionInputManager ?? (osuActionInputManager = GetContainingInputManager() as OsuInputManager);
}
@@ -18,9 +18,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
public double FadeInTime;
public double FadeOutTime;
public override bool RemoveWhenNotAlive => false;
public DrawableRepeatPoint(RepeatPoint repeatPoint, DrawableSlider drawableSlider) : base(repeatPoint)
public DrawableRepeatPoint(RepeatPoint repeatPoint, DrawableSlider drawableSlider)
: base(repeatPoint)
{
this.repeatPoint = repeatPoint;
this.drawableSlider = drawableSlider;
@@ -28,6 +27,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
AutoSizeAxes = Axes.Both;
Blending = BlendingMode.Additive;
Origin = Anchor.Centre;
Scale = new Vector2(0.5f);
Children = new Drawable[]
{
@@ -51,12 +51,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
var animIn = Math.Min(150, repeatPoint.StartTime - FadeInTime);
this.Animate(
d => d.FadeIn(animIn),
d => d.ScaleTo(0.5f).ScaleTo(1.2f, animIn)
).Then(
d => d.ScaleTo(1, 150, Easing.Out)
);
this.FadeIn(animIn).ScaleTo(1.2f, animIn)
.Then()
.ScaleTo(1, 150, Easing.Out);
}
protected override void UpdateCurrentState(ArmedState state)
@@ -43,7 +43,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
ball = new SliderBall(s)
{
Scale = new Vector2(s.Scale),
AccentColour = AccentColour
AccentColour = AccentColour,
AlwaysPresent = true,
Alpha = 0
},
initialCircle = new DrawableHitCircle(new HitCircle
{
@@ -148,16 +150,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
}
}
protected override void UpdateInitialState()
{
base.UpdateInitialState();
body.Alpha = 1;
//we need to be present to handle input events. note that we still don't get enough events (we don't get a position if the mouse hasn't moved since the slider appeared).
ball.AlwaysPresent = true;
ball.Alpha = 0;
}
protected override void UpdateCurrentState(ArmedState state)
{
ball.FadeIn();
@@ -20,8 +20,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
public bool Tracking;
public override bool RemoveWhenNotAlive => false;
public override bool DisplayJudgement => false;
public DrawableSliderTick(SliderTick sliderTick) : base(sliderTick)
@@ -101,14 +101,21 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
// If the current time is between the start and end of the slider, we should track mouse input regardless of the cursor position.
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => canCurrentlyTrack || base.ReceiveMouseInputAt(screenSpacePos);
public override void ClearTransforms(bool propagateChildren = false, string targetMember = null)
{
// Consider the case of rewinding - children's transforms are handled internally, so propagating down
// any further will cause weirdness with the Tracking bool below. Let's not propagate further at this point.
base.ClearTransforms(false, targetMember);
}
private bool tracking;
public bool Tracking
{
get { return tracking; }
private set
{
if (value == tracking) return;
if (value == tracking)
return;
tracking = value;
follow.ScaleTo(tracking ? 2.8f : 1, 300, Easing.OutQuint);
@@ -123,8 +130,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
base.Update();
// Make sure to use the base version of ReceiveMouseInputAt so that we correctly check the position.
if (Time.Current < slider.EndTime)
Tracking = canCurrentlyTrack && lastState != null && base.ReceiveMouseInputAt(lastState.Mouse.NativeState.Position) && ((Parent as DrawableSlider)?.OsuActionInputManager?.PressedActions.Any(x => x == OsuAction.LeftButton || x == OsuAction.RightButton) ?? false);
Tracking = canCurrentlyTrack
&& lastState != null
&& base.ReceiveMouseInputAt(lastState.Mouse.NativeState.Position)
&& ((Parent as DrawableSlider)?.OsuActionInputManager?.PressedActions.Any(x => x == OsuAction.LeftButton || x == OsuAction.RightButton) ?? false);
}
public void UpdateProgress(double progress, int repeat)
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics.Sprites;
@@ -61,6 +62,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
public void SetRotation(float currentRotation)
{
// If we've gone back in time, it's fine to work with a fresh set of records for now
if (records.Count > 0 && Time.Current < records.Last().Time)
records.Clear();
if (records.Count > 0)
{
var record = records.Peek();
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Beatmaps;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing;
@@ -16,19 +17,25 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty
private const int section_length = 400;
private const double difficulty_multiplier = 0.0675;
public OsuDifficultyCalculator(Beatmap beatmap) : base(beatmap)
public OsuDifficultyCalculator(Beatmap beatmap)
: base(beatmap)
{
}
public OsuDifficultyCalculator(Beatmap beatmap, Mod[] mods)
: base(beatmap, mods)
{
}
protected override void PreprocessHitObjects()
{
foreach (OsuHitObject h in Objects)
foreach (OsuHitObject h in Beatmap.HitObjects)
(h as Slider)?.Curve?.Calculate();
}
protected override double CalculateInternal(Dictionary<string, string> categoryDifficulty)
public override double Calculate(Dictionary<string, string> categoryDifficulty = null)
{
OsuDifficultyBeatmap beatmap = new OsuDifficultyBeatmap(Objects);
OsuDifficultyBeatmap beatmap = new OsuDifficultyBeatmap(Beatmap.HitObjects);
Skill[] skills =
{
new Aim(),
@@ -67,6 +74,6 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty
return starRating;
}
protected override BeatmapConverter<OsuHitObject> CreateBeatmapConverter() => new OsuBeatmapConverter();
protected override BeatmapConverter<OsuHitObject> CreateBeatmapConverter(Beatmap beatmap) => new OsuBeatmapConverter();
}
}
+1 -1
View File
@@ -112,7 +112,7 @@ namespace osu.Game.Rulesets.Osu
public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_osu_o };
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap) => new OsuDifficultyCalculator(beatmap);
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null) => new OsuDifficultyCalculator(beatmap, mods);
public override string Description => "osu!";
@@ -111,7 +111,7 @@ namespace osu.Game.Rulesets.Osu.Tests
h.Depth = depth++;
if (auto)
h.State = ArmedState.Hit;
h.State.Value = ArmedState.Hit;
playfieldContainer.Add(h);
var proxyable = h as IDrawableHitObjectWithProxiedApproach;
@@ -1,8 +1,6 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Taiko.Judgements
{
public class TaikoStrongHitJudgement : TaikoJudgement
@@ -11,9 +9,7 @@ namespace osu.Game.Rulesets.Taiko.Judgements
public TaikoStrongHitJudgement()
{
base.Result = HitResult.Perfect;
Final = true;
}
public new HitResult Result => base.Result;
}
}
@@ -17,6 +17,11 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
/// </summary>
protected abstract TaikoAction[] HitActions { get; }
/// <summary>
/// Whether a second hit is allowed to be processed. This occurs once this hit object has been hit successfully.
/// </summary>
protected bool SecondHitAllowed { get; private set; }
/// <summary>
/// Whether the last key pressed is a valid hit key.
/// </summary>
@@ -45,7 +50,15 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
if (!validKeyPressed)
AddJudgement(new TaikoJudgement { Result = HitResult.Miss });
else if (hitOffset < HitObject.HitWindowGood)
AddJudgement(new TaikoJudgement { Result = hitOffset < HitObject.HitWindowGreat ? HitResult.Great : HitResult.Good });
{
AddJudgement(new TaikoJudgement
{
Result = hitOffset < HitObject.HitWindowGreat ? HitResult.Great : HitResult.Good,
Final = !HitObject.IsStrong
});
SecondHitAllowed = true;
}
else
AddJudgement(new TaikoJudgement { Result = HitResult.Miss });
}
@@ -72,7 +85,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
var offset = !AllJudged ? 0 : Time.Current - HitObject.StartTime;
using (BeginDelayedSequence(HitObject.StartTime - Time.Current + offset, true))
{
switch (State)
switch (State.Value)
{
case ArmedState.Idle:
this.Delay(HitObject.HitWindowMiss).Expire();
@@ -3,6 +3,7 @@
using System;
using System.Linq;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Taiko.Judgements;
namespace osu.Game.Rulesets.Taiko.Objects.Drawables
@@ -24,27 +25,25 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
{
}
private bool processedSecondHit;
public override bool AllJudged => processedSecondHit && base.AllJudged;
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
{
if (!base.AllJudged)
if (!SecondHitAllowed)
{
base.CheckForJudgements(userTriggered, timeOffset);
return;
}
if (!userTriggered)
{
if (timeOffset > second_hit_window)
AddJudgement(new TaikoStrongHitJudgement { Result = HitResult.Miss });
return;
}
// If we get here, we're assured that the key pressed is the correct secondary key
if (Math.Abs(firstHitTime - Time.Current) < second_hit_window)
{
AddJudgement(new TaikoStrongHitJudgement());
processedSecondHit = true;
}
AddJudgement(new TaikoStrongHitJudgement { Result = HitResult.Great });
}
public override bool OnReleased(TaikoAction action)
@@ -56,8 +55,11 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
public override bool OnPressed(TaikoAction action)
{
if (AllJudged)
return false;
// Check if we've handled the first key
if (!base.AllJudged)
if (!SecondHitAllowed)
{
// First key hasn't been handled yet, attempt to handle it
bool handled = base.OnPressed(action);
@@ -72,10 +74,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
return handled;
}
// If we've already hit the second key, don't handle this object any further
if (processedSecondHit)
return false;
// Don't handle represses of the first key
if (firstHitAction == action)
return false;
@@ -36,12 +36,12 @@ namespace osu.Game.Rulesets.Taiko
{
}
protected override double CalculateInternal(Dictionary<string, string> categoryDifficulty)
public override double Calculate(Dictionary<string, string> categoryDifficulty = null)
{
// Fill our custom DifficultyHitObject class, that carries additional information
difficultyHitObjects.Clear();
foreach (var hitObject in Objects)
foreach (var hitObject in Beatmap.HitObjects)
difficultyHitObjects.Add(new TaikoHitObjectDifficulty(hitObject));
// Sort DifficultyHitObjects by StartTime of the HitObjects - just to make sure.
@@ -134,6 +134,6 @@ namespace osu.Game.Rulesets.Taiko
return difficulty;
}
protected override BeatmapConverter<TaikoHitObject> CreateBeatmapConverter() => new TaikoBeatmapConverter(true);
protected override BeatmapConverter<TaikoHitObject> CreateBeatmapConverter(Beatmap beatmap) => new TaikoBeatmapConverter(true);
}
}
+1 -1
View File
@@ -97,7 +97,7 @@ namespace osu.Game.Rulesets.Taiko
public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_taiko_o };
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap) => new TaikoDifficultyCalculator(beatmap);
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null) => new TaikoDifficultyCalculator(beatmap);
public override int LegacyID => 1;
+6 -1
View File
@@ -244,7 +244,12 @@ namespace osu.Game.Rulesets.Taiko.UI
if (judgedObject.X >= -0.05f && judgedObject is DrawableHit)
{
// If we're far enough away from the left stage, we should bring outselves in front of it
topLevelHitContainer.Add(judgedObject.CreateProxy());
// Todo: The following try-catch is temporary for replay rewinding support
try
{
topLevelHitContainer.Add(judgedObject.CreateProxy());
}
catch { }
}
hitExplosionContainer.Add(new HitExplosion(judgedObject, isRim));
@@ -39,7 +39,7 @@ namespace osu.Game.Tests.Visual
StarDifficulty = 5.3f,
Metrics = new BeatmapMetrics
{
Ratings = Enumerable.Range(0, 10),
Ratings = Enumerable.Range(0, 11),
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
},
@@ -63,7 +63,7 @@ namespace osu.Game.Tests.Visual
StarDifficulty = 4.8f,
Metrics = new BeatmapMetrics
{
Ratings = Enumerable.Range(0, 10),
Ratings = Enumerable.Range(0, 11),
},
});
@@ -0,0 +1,314 @@
// Copyright (c) 2007-2017 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.Shapes;
using osu.Framework.MathUtils;
using osu.Game.Graphics;
using osu.Game.Online.API.Requests;
using osu.Game.Overlays.BeatmapSet.Scores;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Scoring;
using osu.Game.Users;
using System.Collections.Generic;
namespace osu.Game.Tests.Visual
{
public class TestCaseBeatmapScoresContainer : OsuTestCase
{
public override string Description => "BeatmapOverlay scores container";
private readonly IEnumerable<OnlineScore> scores;
private readonly IEnumerable<OnlineScore> anotherScores;
private readonly OnlineScore topScore;
private readonly Box background;
public TestCaseBeatmapScoresContainer()
{
Container container;
ScoresContainer scoresContainer;
Child = container = new Container
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
Width = 0.8f,
Children = new Drawable[]
{
background = new Box { RelativeSizeAxes = Axes.Both },
scoresContainer = new ScoresContainer(),
}
};
AddStep("scores pack 1", () => scoresContainer.Scores = scores);
AddStep("scores pack 2", () => scoresContainer.Scores = anotherScores);
AddStep("only top score", () => scoresContainer.Scores = new[] { topScore });
AddStep("remove scores", scoresContainer.CleanAllScores);
AddStep("turn on loading", () => scoresContainer.IsLoading = true);
AddStep("turn off loading", () => scoresContainer.IsLoading = false);
AddStep("resize to big", () => container.ResizeWidthTo(1, 300));
AddStep("resize to normal", () => container.ResizeWidthTo(0.8f, 300));
scores = new[]
{
new OnlineScore
{
User = new User
{
Id = 6602580,
Username = @"waaiiru",
Country = new Country
{
FullName = @"Spain",
FlagName = @"ES",
},
},
Mods = new Mod[]
{
new OsuModDoubleTime(),
new OsuModHidden(),
new OsuModFlashlight(),
new OsuModHardRock(),
},
Rank = ScoreRank.XH,
TotalScore = 1234567890,
Accuracy = 1,
},
new OnlineScore
{
User = new User
{
Id = 4608074,
Username = @"Skycries",
Country = new Country
{
FullName = @"Brazil",
FlagName = @"BR",
},
},
Mods = new Mod[]
{
new OsuModDoubleTime(),
new OsuModHidden(),
new OsuModFlashlight(),
},
Rank = ScoreRank.S,
TotalScore = 1234789,
Accuracy = 0.9997,
},
new OnlineScore
{
User = new User
{
Id = 1014222,
Username = @"eLy",
Country = new Country
{
FullName = @"Japan",
FlagName = @"JP",
},
},
Mods = new Mod[]
{
new OsuModDoubleTime(),
new OsuModHidden(),
},
Rank = ScoreRank.B,
TotalScore = 12345678,
Accuracy = 0.9854,
},
new OnlineScore
{
User = new User
{
Id = 1541390,
Username = @"Toukai",
Country = new Country
{
FullName = @"Canada",
FlagName = @"CA",
},
},
Mods = new Mod[]
{
new OsuModDoubleTime(),
},
Rank = ScoreRank.C,
TotalScore = 1234567,
Accuracy = 0.8765,
},
new OnlineScore
{
User = new User
{
Id = 7151382,
Username = @"Mayuri Hana",
Country = new Country
{
FullName = @"Thailand",
FlagName = @"TH",
},
},
Rank = ScoreRank.F,
TotalScore = 123456,
Accuracy = 0.6543,
},
};
foreach(var s in scores)
{
s.Statistics.Add("300", RNG.Next(2000));
s.Statistics.Add("100", RNG.Next(2000));
s.Statistics.Add("50", RNG.Next(2000));
}
anotherScores = new[]
{
new OnlineScore
{
User = new User
{
Id = 4608074,
Username = @"Skycries",
Country = new Country
{
FullName = @"Brazil",
FlagName = @"BR",
},
},
Mods = new Mod[]
{
new OsuModDoubleTime(),
new OsuModHidden(),
new OsuModFlashlight(),
},
Rank = ScoreRank.S,
TotalScore = 1234789,
Accuracy = 0.9997,
},
new OnlineScore
{
User = new User
{
Id = 6602580,
Username = @"waaiiru",
Country = new Country
{
FullName = @"Spain",
FlagName = @"ES",
},
},
Mods = new Mod[]
{
new OsuModDoubleTime(),
new OsuModHidden(),
new OsuModFlashlight(),
new OsuModHardRock(),
},
Rank = ScoreRank.XH,
TotalScore = 1234567890,
Accuracy = 1,
},
new OnlineScore
{
User = new User
{
Id = 7151382,
Username = @"Mayuri Hana",
Country = new Country
{
FullName = @"Thailand",
FlagName = @"TH",
},
},
Rank = ScoreRank.F,
TotalScore = 123456,
Accuracy = 0.6543,
},
new OnlineScore
{
User = new User
{
Id = 1014222,
Username = @"eLy",
Country = new Country
{
FullName = @"Japan",
FlagName = @"JP",
},
},
Mods = new Mod[]
{
new OsuModDoubleTime(),
new OsuModHidden(),
},
Rank = ScoreRank.B,
TotalScore = 12345678,
Accuracy = 0.9854,
},
new OnlineScore
{
User = new User
{
Id = 1541390,
Username = @"Toukai",
Country = new Country
{
FullName = @"Canada",
FlagName = @"CA",
},
},
Mods = new Mod[]
{
new OsuModDoubleTime(),
},
Rank = ScoreRank.C,
TotalScore = 1234567,
Accuracy = 0.8765,
},
};
foreach (var s in anotherScores)
{
s.Statistics.Add("300", RNG.Next(2000));
s.Statistics.Add("100", RNG.Next(2000));
s.Statistics.Add("50", RNG.Next(2000));
}
topScore = new OnlineScore
{
User = new User
{
Id = 2705430,
Username = @"Mooha",
Country = new Country
{
FullName = @"France",
FlagName = @"FR",
},
},
Mods = new Mod[]
{
new OsuModDoubleTime(),
new OsuModFlashlight(),
new OsuModHardRock(),
},
Rank = ScoreRank.B,
TotalScore = 987654321,
Accuracy = 0.8487,
};
topScore.Statistics.Add("300", RNG.Next(2000));
topScore.Statistics.Add("100", RNG.Next(2000));
topScore.Statistics.Add("50", RNG.Next(2000));
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
background.Colour = colours.Gray2;
}
}
}
@@ -53,6 +53,7 @@ namespace osu.Game.Tests.Visual
Submitted = new DateTime(2016, 2, 10),
Ranked = new DateTime(2016, 6, 19),
BPM = 236,
HasVideo = true,
Covers = new BeatmapSetOnlineCovers
{
Cover = @"https://assets.ppy.sh/beatmaps/415886/covers/cover.jpg?1465651778",
@@ -75,7 +76,6 @@ namespace osu.Game.Tests.Visual
OnlineInfo = new BeatmapOnlineInfo
{
Length = 115000,
HasVideo = false,
CircleCount = 265,
SliderCount = 71,
PlayCount = 47906,
@@ -83,7 +83,7 @@ namespace osu.Game.Tests.Visual
},
Metrics = new BeatmapMetrics
{
Ratings = Enumerable.Range(0, 10),
Ratings = Enumerable.Range(0, 11),
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
},
@@ -103,7 +103,6 @@ namespace osu.Game.Tests.Visual
OnlineInfo = new BeatmapOnlineInfo
{
Length = 118000,
HasVideo = true,
CircleCount = 592,
SliderCount = 62,
PlayCount = 162021,
@@ -111,7 +110,7 @@ namespace osu.Game.Tests.Visual
},
Metrics = new BeatmapMetrics
{
Ratings = Enumerable.Range(0, 10),
Ratings = Enumerable.Range(0, 11),
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
},
@@ -131,7 +130,6 @@ namespace osu.Game.Tests.Visual
OnlineInfo = new BeatmapOnlineInfo
{
Length = 118000,
HasVideo = false,
CircleCount = 1042,
SliderCount = 79,
PlayCount = 225178,
@@ -139,7 +137,7 @@ namespace osu.Game.Tests.Visual
},
Metrics = new BeatmapMetrics
{
Ratings = Enumerable.Range(0, 10),
Ratings = Enumerable.Range(0, 11),
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
},
@@ -159,7 +157,6 @@ namespace osu.Game.Tests.Visual
OnlineInfo = new BeatmapOnlineInfo
{
Length = 118000,
HasVideo = false,
CircleCount = 1352,
SliderCount = 69,
PlayCount = 131545,
@@ -167,7 +164,7 @@ namespace osu.Game.Tests.Visual
},
Metrics = new BeatmapMetrics
{
Ratings = Enumerable.Range(0, 10),
Ratings = Enumerable.Range(0, 11),
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
},
@@ -187,7 +184,6 @@ namespace osu.Game.Tests.Visual
OnlineInfo = new BeatmapOnlineInfo
{
Length = 118000,
HasVideo = false,
CircleCount = 1730,
SliderCount = 115,
PlayCount = 117673,
@@ -195,7 +191,7 @@ namespace osu.Game.Tests.Visual
},
Metrics = new BeatmapMetrics
{
Ratings = Enumerable.Range(0, 10),
Ratings = Enumerable.Range(0, 11),
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
},
@@ -227,6 +223,7 @@ namespace osu.Game.Tests.Visual
Submitted = new DateTime(2016, 6, 11),
Ranked = new DateTime(2016, 7, 12),
BPM = 160,
HasVideo = false,
Covers = new BeatmapSetOnlineCovers
{
Cover = @"https://assets.ppy.sh/beatmaps/625493/covers/cover.jpg?1499167472",
@@ -249,7 +246,6 @@ namespace osu.Game.Tests.Visual
OnlineInfo = new BeatmapOnlineInfo
{
Length = 193000,
HasVideo = false,
CircleCount = 262,
SliderCount = 0,
PlayCount = 3952,
@@ -257,7 +253,7 @@ namespace osu.Game.Tests.Visual
},
Metrics = new BeatmapMetrics
{
Ratings = Enumerable.Range(0, 10),
Ratings = Enumerable.Range(0, 11),
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
},
@@ -277,7 +273,6 @@ namespace osu.Game.Tests.Visual
OnlineInfo = new BeatmapOnlineInfo
{
Length = 193000,
HasVideo = false,
CircleCount = 464,
SliderCount = 0,
PlayCount = 4833,
@@ -285,7 +280,7 @@ namespace osu.Game.Tests.Visual
},
Metrics = new BeatmapMetrics
{
Ratings = Enumerable.Range(0, 10),
Ratings = Enumerable.Range(0, 11),
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
},
@@ -305,7 +300,6 @@ namespace osu.Game.Tests.Visual
OnlineInfo = new BeatmapOnlineInfo
{
Length = 193000,
HasVideo = false,
CircleCount = 712,
SliderCount = 0,
PlayCount = 4405,
@@ -313,7 +307,7 @@ namespace osu.Game.Tests.Visual
},
Metrics = new BeatmapMetrics
{
Ratings = Enumerable.Range(0, 10),
Ratings = Enumerable.Range(0, 11),
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
},
@@ -333,7 +327,6 @@ namespace osu.Game.Tests.Visual
OnlineInfo = new BeatmapOnlineInfo
{
Length = 193000,
HasVideo = false,
CircleCount = 943,
SliderCount = 0,
PlayCount = 3950,
@@ -341,7 +334,7 @@ namespace osu.Game.Tests.Visual
},
Metrics = new BeatmapMetrics
{
Ratings = Enumerable.Range(0, 10),
Ratings = Enumerable.Range(0, 11),
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
},
@@ -361,7 +354,6 @@ namespace osu.Game.Tests.Visual
OnlineInfo = new BeatmapOnlineInfo
{
Length = 193000,
HasVideo = false,
CircleCount = 1068,
SliderCount = 0,
PlayCount = 5856,
@@ -369,7 +361,7 @@ namespace osu.Game.Tests.Visual
},
Metrics = new BeatmapMetrics
{
Ratings = Enumerable.Range(0, 10),
Ratings = Enumerable.Range(0, 11),
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
},
@@ -0,0 +1,52 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using OpenTK.Graphics;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Timing;
using osu.Game.Screens.Menu;
namespace osu.Game.Tests.Visual
{
public class TestCaseIntroSequence : OsuTestCase
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(OsuLogo),
};
public TestCaseIntroSequence()
{
OsuLogo logo;
var rateAdjustClock = new StopwatchClock(true);
var framedClock = new FramedClock(rateAdjustClock);
framedClock.ProcessFrame();
Add(new Container
{
RelativeSizeAxes = Axes.Both,
Clock = framedClock,
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black,
},
logo = new OsuLogo
{
Anchor = Anchor.Centre,
}
}
});
AddStep(@"Restart", logo.PlayIntro);
AddSliderStep("Playback speed", 0.0, 2.0, 1, v => rateAdjustClock.Rate = v);
}
}
}
+39
View File
@@ -0,0 +1,39 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Timing;
using osu.Game.Screens;
using osu.Game.Screens.Menu;
using OpenTK.Graphics;
namespace osu.Game.Tests.Visual
{
public class TestCaseOsuGame : OsuTestCase
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(OsuLogo),
};
public TestCaseOsuGame()
{
var rateAdjustClock = new StopwatchClock(true);
var framedClock = new FramedClock(rateAdjustClock);
framedClock.ProcessFrame();
Add(new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black,
});
Add(new Loader());
AddSliderStep("Playback speed", 0.0, 2.0, 1, v => rateAdjustClock.Rate = v);
}
}
}
@@ -3,7 +3,7 @@
using osu.Framework.Graphics;
using osu.Game.Graphics.UserInterface;
using osu.Game.Screens.Play;
using osu.Game.Screens.Play.HUD;
using osu.Game.Screens.Play.ReplaySettings;
namespace osu.Game.Tests.Visual
+3
View File
@@ -93,6 +93,7 @@
<Compile Include="Visual\TestCaseBeatmapDetailArea.cs" />
<Compile Include="Visual\TestCaseBeatmapDetails.cs" />
<Compile Include="Visual\TestCaseBeatmapOptionsOverlay.cs" />
<Compile Include="Visual\TestCaseBeatmapScoresContainer.cs" />
<Compile Include="Visual\TestCaseBeatmapSetOverlay.cs" />
<Compile Include="Visual\TestCaseBeatSyncedContainer.cs" />
<Compile Include="Visual\TestCaseBreadcrumbs.cs" />
@@ -110,6 +111,7 @@
<Compile Include="Visual\TestCaseGamefield.cs" />
<Compile Include="Visual\TestCaseGraph.cs" />
<Compile Include="Visual\TestCaseIconButton.cs" />
<Compile Include="Visual\TestCaseIntroSequence.cs" />
<Compile Include="Visual\TestCaseKeyConfiguration.cs" />
<Compile Include="Visual\TestCaseKeyCounter.cs" />
<Compile Include="Visual\TestCaseLeaderboard.cs" />
@@ -121,6 +123,7 @@
<Compile Include="Visual\TestCaseNotificationOverlay.cs" />
<Compile Include="Visual\TestCaseOnScreenDisplay.cs" />
<Compile Include="Visual\TestCaseAllPlayers.cs" />
<Compile Include="Visual\TestCaseOsuGame.cs" />
<Compile Include="Visual\TestCasePlaySongSelect.cs" />
<Compile Include="Visual\TestCaseReplay.cs" />
<Compile Include="Visual\TestCaseReplaySettingsOverlay.cs" />
+4
View File
@@ -341,6 +341,8 @@ namespace osu.Game.Beatmaps
/// Returns a <see cref="BeatmapSetInfo"/> to a usable state if it has previously been deleted but not yet purged.
/// Is a no-op for already usable beatmaps.
/// </summary>
/// <param name="beatmaps">The store to restore beatmaps from.</param>
/// <param name="files">The store to restore beatmap files from.</param>
/// <param name="beatmapSet">The beatmap to restore.</param>
private void undelete(BeatmapStore beatmaps, FileStore files, BeatmapSetInfo beatmapSet)
{
@@ -426,6 +428,8 @@ namespace osu.Game.Beatmaps
/// Import a beamap into our local <see cref="FileStore"/> storage.
/// If the beatmap is already imported, the existing instance will be returned.
/// </summary>
/// <param name="files">The store to import beatmap files to.</param>
/// <param name="beatmaps">The store to import beatmaps to.</param>
/// <param name="reader">The beatmap archive to be read.</param>
/// <returns>The imported beatmap, or an existing instance if it is already present.</returns>
private BeatmapSetInfo importToStorage(FileStore files, BeatmapStore beatmaps, ArchiveReader reader)
-11
View File
@@ -1,8 +1,6 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using Newtonsoft.Json;
namespace osu.Game.Beatmaps
{
/// <summary>
@@ -15,33 +13,24 @@ namespace osu.Game.Beatmaps
/// </summary>
public double Length { get; set; }
/// <summary>
/// Whether or not this beatmap has a background video.
/// </summary>
public bool HasVideo { get; set; }
/// <summary>
/// The amount of circles in this beatmap.
/// </summary>
[JsonProperty(@"count_circles")]
public int CircleCount { get; set; }
/// <summary>
/// The amount of sliders in this beatmap.
/// </summary>
[JsonProperty(@"count_sliders")]
public int SliderCount { get; set; }
/// <summary>
/// The amount of plays this beatmap has.
/// </summary>
[JsonProperty(@"playcount")]
public int PlayCount { get; set; }
/// <summary>
/// The amount of passes this beatmap has.
/// </summary>
[JsonProperty(@"passcount")]
public int PassCount { get; set; }
}
}
+5 -4
View File
@@ -26,16 +26,19 @@ namespace osu.Game.Beatmaps
/// </summary>
public DateTimeOffset? LastUpdated { get; set; }
/// <summary>
/// Whether or not this beatmap set has a background video.
/// </summary>
public bool HasVideo { get; set; }
/// <summary>
/// The different sizes of cover art for this beatmap set.
/// </summary>
[JsonProperty(@"covers")]
public BeatmapSetOnlineCovers Covers { get; set; }
/// <summary>
/// A small sample clip of this beatmap set's song.
/// </summary>
[JsonProperty(@"previewUrl")]
public string Preview { get; set; }
/// <summary>
@@ -46,13 +49,11 @@ namespace osu.Game.Beatmaps
/// <summary>
/// The amount of plays this beatmap set has.
/// </summary>
[JsonProperty(@"play_count")]
public int PlayCount { get; set; }
/// <summary>
/// The amount of people who have favourited this beatmap set.
/// </summary>
[JsonProperty(@"favourite_count")]
public int FavouriteCount { get; set; }
}
@@ -1,6 +1,7 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Lists;
@@ -85,6 +86,9 @@ namespace osu.Game.Beatmaps.ControlPoints
private T binarySearch<T>(SortedList<T> list, double time, T prePoint = null)
where T : ControlPoint, new()
{
if (list == null)
throw new ArgumentNullException(nameof(list));
if (list.Count == 0)
return new T();
+29 -24
View File
@@ -3,6 +3,10 @@
using osu.Game.Rulesets.Objects;
using System.Collections.Generic;
using osu.Game.Rulesets.Mods;
using osu.Framework.Timing;
using System.Linq;
using osu.Framework.Extensions.IEnumerableExtensions;
namespace osu.Game.Beatmaps
{
@@ -10,45 +14,46 @@ namespace osu.Game.Beatmaps
{
protected double TimeRate = 1;
protected abstract double CalculateInternal(Dictionary<string, string> categoryDifficulty);
private void loadTiming()
{
// TODO: Handle mods
const int audio_rate = 100;
TimeRate = audio_rate / 100.0;
}
public double Calculate(Dictionary<string, string> categoryDifficulty = null)
{
loadTiming();
double difficulty = CalculateInternal(categoryDifficulty);
return difficulty;
}
public abstract double Calculate(Dictionary<string, string> categoryDifficulty = null);
}
public abstract class DifficultyCalculator<T> : DifficultyCalculator where T : HitObject
{
protected readonly Beatmap Beatmap;
protected readonly Beatmap<T> Beatmap;
protected readonly Mod[] Mods;
protected List<T> Objects;
protected DifficultyCalculator(Beatmap beatmap)
protected DifficultyCalculator(Beatmap beatmap, Mod[] mods = null)
{
Beatmap = beatmap;
Beatmap = CreateBeatmapConverter(beatmap).Convert(beatmap);
Mods = mods ?? new Mod[0];
Objects = CreateBeatmapConverter().Convert(beatmap).HitObjects;
foreach (var h in Objects)
h.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BaseDifficulty);
ApplyMods(Mods);
PreprocessHitObjects();
}
protected virtual void ApplyMods(Mod[] mods)
{
var clock = new StopwatchClock();
mods.OfType<IApplicableToClock>().ForEach(m => m.ApplyToClock(clock));
TimeRate = clock.Rate;
foreach (var mod in Mods.OfType<IApplicableToDifficulty>())
mod.ApplyToDifficulty(Beatmap.BeatmapInfo.BaseDifficulty);
foreach (var mod in mods.OfType<IApplicableToHitObject<T>>())
foreach (var obj in Beatmap.HitObjects)
mod.ApplyToHitObject(obj);
foreach (var h in Beatmap.HitObjects)
h.ApplyDefaults(Beatmap.ControlPointInfo, Beatmap.BeatmapInfo.BaseDifficulty);
}
protected virtual void PreprocessHitObjects()
{
}
protected abstract BeatmapConverter<T> CreateBeatmapConverter();
protected abstract BeatmapConverter<T> CreateBeatmapConverter(Beatmap beatmap);
}
}
@@ -1,6 +1,7 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Allocation;
using osu.Framework.Graphics.Sprites;
@@ -12,6 +13,9 @@ namespace osu.Game.Beatmaps.Drawables
public BeatmapBackgroundSprite(WorkingBeatmap working)
{
if (working == null)
throw new ArgumentNullException(nameof(working));
this.working = working;
}
@@ -72,6 +72,11 @@ namespace osu.Game.Beatmaps.Drawables
public BeatmapGroup(BeatmapSetInfo beatmapSet, BeatmapManager manager)
{
if (beatmapSet == null)
throw new ArgumentNullException(nameof(beatmapSet));
if (manager == null)
throw new ArgumentNullException(nameof(manager));
BeatmapSet = beatmapSet;
WorkingBeatmap beatmap = manager.GetWorkingBeatmap(BeatmapSet.Beatmaps.FirstOrDefault());
@@ -73,6 +73,9 @@ namespace osu.Game.Beatmaps.Drawables
public BeatmapPanel(BeatmapInfo beatmap)
{
if (beatmap == null)
throw new ArgumentNullException(nameof(beatmap));
Beatmap = beatmap;
Height *= 0.60f;
@@ -1,6 +1,7 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Allocation;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
@@ -12,6 +13,9 @@ namespace osu.Game.Beatmaps.Drawables
private readonly BeatmapSetInfo set;
public BeatmapSetCover(BeatmapSetInfo set)
{
if (set == null)
throw new ArgumentNullException(nameof(set));
this.set = set;
}
@@ -36,6 +36,9 @@ namespace osu.Game.Beatmaps.Drawables
public BeatmapSetHeader(WorkingBeatmap beatmap)
{
if (beatmap == null)
throw new ArgumentNullException(nameof(beatmap));
this.beatmap = beatmap;
Children = new Drawable[]
@@ -88,6 +91,9 @@ namespace osu.Game.Beatmaps.Drawables
[BackgroundDependencyLoader]
private void load(LocalisationEngine localisation)
{
if (localisation == null)
throw new ArgumentNullException(nameof(localisation));
title.Current = localisation.GetUnicodePreference(beatmap.Metadata.TitleUnicode, beatmap.Metadata.Title);
artist.Current = localisation.GetUnicodePreference(beatmap.Metadata.ArtistUnicode, beatmap.Metadata.Artist);
}
@@ -154,6 +160,9 @@ namespace osu.Game.Beatmaps.Drawables
public void AddDifficultyIcons(IEnumerable<BeatmapPanel> panels)
{
if (panels == null)
throw new ArgumentNullException(nameof(panels));
foreach (var p in panels)
difficultyIcons.Add(new DifficultyIcon(p.Beatmap));
}
@@ -1,6 +1,7 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Allocation;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics;
@@ -23,6 +24,9 @@ namespace osu.Game.Beatmaps.Drawables
[BackgroundDependencyLoader]
private void load(OsuColour palette)
{
if (palette == null)
throw new ArgumentNullException(nameof(palette));
this.palette = palette;
AccentColour = getColour(beatmap);
}
@@ -39,6 +43,9 @@ namespace osu.Game.Beatmaps.Drawables
private DifficultyRating getDifficultyRating(BeatmapInfo beatmap)
{
if (beatmap == null)
throw new ArgumentNullException(nameof(beatmap));
var rating = beatmap.StarDifficulty;
if (rating < 1.5) return DifficultyRating.Easy;
@@ -1,6 +1,7 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Graphics;
@@ -15,6 +16,9 @@ namespace osu.Game.Beatmaps.Drawables
public DifficultyIcon(BeatmapInfo beatmap) : base(beatmap)
{
if (beatmap == null)
throw new ArgumentNullException(nameof(beatmap));
this.beatmap = beatmap;
Size = new Vector2(20);
}
+1 -1
View File
@@ -59,7 +59,7 @@ namespace osu.Game.Beatmaps
throw new NotImplementedException();
}
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap) => null;
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null) => null;
public override string Description => "dummy";
@@ -18,6 +18,9 @@ namespace osu.Game.Beatmaps.Formats
public static BeatmapDecoder GetDecoder(StreamReader stream)
{
if (stream == null)
throw new ArgumentNullException(nameof(stream));
string line;
do { line = stream.ReadLine()?.Trim(); }
while (line != null && line.Length == 0);
@@ -70,6 +70,11 @@ namespace osu.Game.Beatmaps.Formats
private void handleGeneral(Beatmap beatmap, string line)
{
if (beatmap == null)
throw new ArgumentNullException(nameof(beatmap));
if (line == null)
throw new ArgumentNullException(nameof(line));
var pair = splitKeyVal(line, ':');
var metadata = beatmap.BeatmapInfo.Metadata;
@@ -129,6 +134,11 @@ namespace osu.Game.Beatmaps.Formats
private void handleEditor(Beatmap beatmap, string line)
{
if (beatmap == null)
throw new ArgumentNullException(nameof(beatmap));
if (line == null)
throw new ArgumentNullException(nameof(line));
var pair = splitKeyVal(line, ':');
switch (pair.Key)
@@ -153,6 +163,11 @@ namespace osu.Game.Beatmaps.Formats
private void handleMetadata(Beatmap beatmap, string line)
{
if (beatmap == null)
throw new ArgumentNullException(nameof(beatmap));
if (line == null)
throw new ArgumentNullException(nameof(line));
var pair = splitKeyVal(line, ':');
var metadata = beatmap.BeatmapInfo.Metadata;
@@ -194,6 +209,11 @@ namespace osu.Game.Beatmaps.Formats
private void handleDifficulty(Beatmap beatmap, string line)
{
if (beatmap == null)
throw new ArgumentNullException(nameof(beatmap));
if (line == null)
throw new ArgumentNullException(nameof(line));
var pair = splitKeyVal(line, ':');
var difficulty = beatmap.BeatmapInfo.BaseDifficulty;
@@ -226,6 +246,9 @@ namespace osu.Game.Beatmaps.Formats
/// <param name="line">The line which may contains variables.</param>
private void decodeVariables(ref string line)
{
if (line == null)
throw new ArgumentNullException(nameof(line));
while (line.IndexOf('$') >= 0)
{
string origLine = line;
@@ -244,6 +267,11 @@ namespace osu.Game.Beatmaps.Formats
private void handleEvents(Beatmap beatmap, string line, ref StoryboardSprite storyboardSprite, ref CommandTimelineGroup timelineGroup)
{
if (line == null)
throw new ArgumentNullException(nameof(line));
if (beatmap == null)
throw new ArgumentNullException(nameof(beatmap));
var depth = 0;
while (line.StartsWith(" ") || line.StartsWith("_"))
{
@@ -469,6 +497,11 @@ namespace osu.Game.Beatmaps.Formats
private void handleTimingPoints(Beatmap beatmap, string line)
{
if (beatmap == null)
throw new ArgumentNullException(nameof(beatmap));
if (line == null)
throw new ArgumentNullException(nameof(line));
string[] split = line.Split(',');
double time = double.Parse(split[0].Trim(), NumberFormatInfo.InvariantInfo);
@@ -555,6 +588,11 @@ namespace osu.Game.Beatmaps.Formats
private void handleColours(Beatmap beatmap, string line, ref bool hasCustomColours)
{
if (beatmap == null)
throw new ArgumentNullException(nameof(beatmap));
if (line == null)
throw new ArgumentNullException(nameof(line));
var pair = splitKeyVal(line, ':');
string[] split = pair.Value.Split(',');
@@ -587,6 +625,9 @@ namespace osu.Game.Beatmaps.Formats
private void handleVariables(string line)
{
if (line == null)
throw new ArgumentNullException(nameof(line));
var pair = splitKeyVal(line, '=');
variables[pair.Key] = pair.Value;
}
@@ -603,6 +644,11 @@ namespace osu.Game.Beatmaps.Formats
protected override void ParseFile(StreamReader stream, Beatmap beatmap)
{
if (beatmap == null)
throw new ArgumentNullException(nameof(beatmap));
if (stream == null)
throw new ArgumentNullException(nameof(stream));
beatmap.BeatmapInfo.BeatmapVersion = beatmapVersion;
Section section = Section.None;
@@ -679,6 +725,9 @@ namespace osu.Game.Beatmaps.Formats
private KeyValuePair<string, string> splitKeyVal(string line, char separator)
{
if (line == null)
throw new ArgumentNullException(nameof(line));
var split = line.Trim().Split(new[] { separator }, 2);
return new KeyValuePair<string, string>
+48 -79
View File
@@ -28,16 +28,11 @@ namespace osu.Game.Beatmaps
Metadata = beatmapInfo.Metadata ?? BeatmapSetInfo?.Metadata ?? new BeatmapMetadata();
Mods.ValueChanged += mods => applyRateAdjustments();
}
private void applyRateAdjustments()
{
var t = track;
if (t == null) return;
t.ResetSpeedAdjustments();
foreach (var mod in Mods.Value.OfType<IApplicableToClock>())
mod.ApplyToClock(t);
beatmap = new Lazy<Beatmap>(populateBeatmap);
background = new Lazy<Texture>(populateBackground);
track = new Lazy<Track>(populateTrack);
waveform = new Lazy<Waveform>(populateWaveform);
}
protected abstract Beatmap GetBeatmap();
@@ -45,98 +40,72 @@ namespace osu.Game.Beatmaps
protected abstract Track GetTrack();
protected virtual Waveform GetWaveform() => new Waveform();
private Beatmap beatmap;
private readonly object beatmapLock = new object();
public Beatmap Beatmap
public bool BeatmapLoaded => beatmap.IsValueCreated;
public Beatmap Beatmap => beatmap.Value;
private readonly Lazy<Beatmap> beatmap;
private Beatmap populateBeatmap()
{
get
{
lock (beatmapLock)
{
if (beatmap != null) return beatmap;
var b = GetBeatmap() ?? new Beatmap();
beatmap = GetBeatmap() ?? new Beatmap();
// use the database-backed info.
b.BeatmapInfo = BeatmapInfo;
// use the database-backed info.
beatmap.BeatmapInfo = BeatmapInfo;
return beatmap;
}
}
return b;
}
private readonly object backgroundLock = new object();
private Texture background;
public Texture Background
public bool BackgroundLoaded => background.IsValueCreated;
public Texture Background => background.Value;
private Lazy<Texture> background;
private Texture populateBackground() => GetBackground();
public bool TrackLoaded => track.IsValueCreated;
public Track Track => track.Value;
private Lazy<Track> track;
private Track populateTrack()
{
get
{
lock (backgroundLock)
{
return background ?? (background = GetBackground());
}
}
// we want to ensure that we always have a track, even if it's a fake one.
var t = GetTrack() ?? new TrackVirtual();
applyRateAdjustments(t);
return t;
}
private Track track;
private readonly object trackLock = new object();
public Track Track
{
get
{
lock (trackLock)
{
if (track != null) return track;
public bool WaveformLoaded => waveform.IsValueCreated;
public Waveform Waveform => waveform.Value;
private readonly Lazy<Waveform> waveform;
// we want to ensure that we always have a track, even if it's a fake one.
track = GetTrack() ?? new TrackVirtual();
applyRateAdjustments();
return track;
}
}
}
private Waveform waveform;
private readonly object waveformLock = new object();
public Waveform Waveform
{
get
{
lock (waveformLock)
return waveform ?? (waveform = GetWaveform());
}
}
public bool TrackLoaded => track != null;
private Waveform populateWaveform() => GetWaveform();
public void TransferTo(WorkingBeatmap other)
{
lock (trackLock)
{
if (track != null && BeatmapInfo.AudioEquals(other.BeatmapInfo))
other.track = track;
}
if (track.IsValueCreated && Track != null && BeatmapInfo.AudioEquals(other.BeatmapInfo))
other.track = track;
if (background != null && BeatmapInfo.BackgroundEquals(other.BeatmapInfo))
if (background.IsValueCreated && Background != null && BeatmapInfo.BackgroundEquals(other.BeatmapInfo))
other.background = background;
}
public virtual void Dispose()
{
background?.Dispose();
background = null;
waveform?.Dispose();
if (BackgroundLoaded) Background?.Dispose();
if (WaveformLoaded) Waveform?.Dispose();
}
public void DisposeTrack()
{
lock (trackLock)
{
track?.Dispose();
track = null;
}
if (TrackLoaded) Track?.Dispose();
}
private void applyRateAdjustments(Track t = null)
{
if (t == null && track.IsValueCreated) t = Track;
if (t == null) return;
t.ResetSpeedAdjustments();
foreach (var mod in Mods.Value.OfType<IApplicableToClock>())
mod.ApplyToClock(t);
}
}
}
+7 -9
View File
@@ -16,12 +16,12 @@ namespace osu.Game.Configuration
Set(OsuSetting.Ruleset, 0, 0, int.MaxValue);
Set(OsuSetting.BeatmapDetailTab, BeatmapDetailTab.Details);
Set(OsuSetting.DisplayStarsMinimum, 0.0, 0, 10);
Set(OsuSetting.DisplayStarsMaximum, 10.0, 0, 10);
Set(OsuSetting.DisplayStarsMinimum, 0.0, 0, 10, 0.1);
Set(OsuSetting.DisplayStarsMaximum, 10.0, 0, 10, 0.1);
Set(OsuSetting.SelectionRandomType, SelectionRandomType.RandomPermutation);
Set(OsuSetting.ChatDisplayHeight, ChatOverlay.DEFAULT_HEIGHT, 0.2, 1);
Set(OsuSetting.ChatDisplayHeight, ChatOverlay.DEFAULT_HEIGHT, 0.2, 1, 0.01);
// Online settings
Set(OsuSetting.Username, string.Empty);
@@ -41,11 +41,11 @@ namespace osu.Game.Configuration
Set(OsuSetting.MenuVoice, true);
Set(OsuSetting.MenuMusic, true);
Set(OsuSetting.AudioOffset, 0, -500.0, 500.0);
Set(OsuSetting.AudioOffset, 0, -500.0, 500.0, 1);
// Input
Set(OsuSetting.MenuCursorSize, 1.0, 0.5f, 2);
Set(OsuSetting.GameplayCursorSize, 1.0, 0.5f, 2);
Set(OsuSetting.MenuCursorSize, 1.0, 0.5f, 2, 0.01);
Set(OsuSetting.GameplayCursorSize, 1.0, 0.5f, 2, 0.01);
Set(OsuSetting.AutoCursorSize, false);
Set(OsuSetting.MouseDisableButtons, false);
@@ -63,13 +63,12 @@ namespace osu.Game.Configuration
Set(OsuSetting.SnakingOutSliders, true);
// Gameplay
Set(OsuSetting.DimLevel, 0.3, 0, 1);
Set(OsuSetting.DimLevel, 0.3, 0, 1, 0.01);
Set(OsuSetting.ShowInterface, true);
Set(OsuSetting.KeyOverlay, false);
Set(OsuSetting.FloatingComments, false);
Set(OsuSetting.PlaybackSpeed, 1.0, 0.5f, 2);
// Update
Set(OsuSetting.ReleaseStream, ReleaseStream.Lazer);
@@ -93,7 +92,6 @@ namespace osu.Game.Configuration
ShowStoryboard,
KeyOverlay,
FloatingComments,
PlaybackSpeed,
ShowInterface,
MouseDisableButtons,
MouseDisableWheel,
+2 -2
View File
@@ -102,7 +102,7 @@ namespace osu.Game.Database
return null;
}
public new int SaveChanges(IDbContextTransaction transaction = null)
public int SaveChanges(IDbContextTransaction transaction = null)
{
var ret = base.SaveChanges();
transaction?.Commit();
@@ -262,7 +262,7 @@ namespace osu.Game.Database
throw new MigrationFailedException(e);
}
}
catch (MigrationFailedException e)
catch (MigrationFailedException)
{
throw;
}
@@ -35,9 +35,12 @@ namespace osu.Game.Graphics.Containers
protected override void Update()
{
var track = Beatmap.Value.Track;
if (!Beatmap.Value.TrackLoaded || !Beatmap.Value.BeatmapLoaded) return;
if (track == null)
var track = Beatmap.Value.Track;
var beatmap = Beatmap.Value.Beatmap;
if (track == null || beatmap == null)
return;
double currentTrackTime = track.Length > 0 ? track.CurrentTime + EarlyActivationMilliseconds : Clock.CurrentTime;
@@ -7,7 +7,7 @@ using OpenTK.Input;
namespace osu.Game.Graphics.Containers
{
internal class OsuScrollContainer : ScrollContainer
public class OsuScrollContainer : ScrollContainer
{
/// <summary>
/// Allows controlling the scroll bar from any position in the container using the right mouse button.
@@ -11,7 +11,7 @@ using osu.Framework.Configuration;
namespace osu.Game.Graphics.Containers
{
internal class ParallaxContainer : Container, IRequireHighFrequencyMousePosition
public class ParallaxContainer : Container, IRequireHighFrequencyMousePosition
{
public float ParallaxAmount = 0.02f;
@@ -139,6 +139,8 @@ namespace osu.Game.Graphics.Containers
public void ScrollTo(Drawable section) => scrollContainer.ScrollTo(scrollContainer.GetChildPosInContent(section) - (FixedHeader?.BoundingBox.Height ?? 0));
public void ScrollToTop() => scrollContainer.ScrollTo(0);
private float lastKnownScroll;
protected override void UpdateAfterChildren()
{
-5
View File
@@ -57,11 +57,6 @@ namespace osu.Game.Graphics
private void load(FontStore store)
{
this.store = store;
}
protected override void LoadComplete()
{
base.LoadComplete();
updateTexture();
}
@@ -6,6 +6,7 @@ using osu.Framework.Graphics.Sprites;
using osu.Framework.MathUtils;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Graphics.Transforms;
namespace osu.Game.Graphics.Sprites
{
@@ -40,4 +41,23 @@ namespace osu.Game.Graphics.Sprites
return base.CreateFallbackCharacterDrawable();
}
}
public static class OsuSpriteTextTransformExtensions
{
/// <summary>
/// Sets <see cref="OsuSpriteText.Text"/> to a new value after a duration.
/// </summary>
/// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns>
public static TransformSequence<T> TransformTextTo<T>(this T spriteText, string newText, double duration = 0, Easing easing = Easing.None)
where T : OsuSpriteText
=> spriteText.TransformTo(nameof(OsuSpriteText.Text), newText, duration, easing);
/// <summary>
/// Sets <see cref="OsuSpriteText.Text"/> to a new value after a duration.
/// </summary>
/// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns>
public static TransformSequence<T> TransformTextTo<T>(this TransformSequence<T> t, string newText, double duration = 0, Easing easing = Easing.None)
where T : OsuSpriteText
=> t.Append(o => o.TransformTextTo(newText, duration, easing));
}
}
+1 -1
View File
@@ -19,7 +19,7 @@ namespace osu.Game.IO
{
public readonly IResourceStore<byte[]> Store;
public Storage Storage => base.Storage;
public new Storage Storage => base.Storage;
public FileStore(Func<OsuDbContext> createContext, Storage storage) : base(createContext, storage.GetStorageForDirectory(@"files"))
{
@@ -51,7 +51,9 @@ namespace osu.Game.Input.Bindings
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
store.KeyBindingChanged -= ReloadMappings;
if (store != null)
store.KeyBindingChanged -= ReloadMappings;
}
protected override void ReloadMappings() => KeyBindings = store.Query(ruleset?.ID, variant).ToList();
+1
View File
@@ -118,6 +118,7 @@ namespace osu.Game.Online.API
//NotificationOverlay.ShowMessage("Login failed!");
log.Add(@"Login failed!");
Password = null;
authentication.Clear();
continue;
}
+3
View File
@@ -27,6 +27,9 @@ namespace osu.Game.Online.API
internal bool AuthenticateWithLogin(string username, string password)
{
if (string.IsNullOrEmpty(username)) return false;
if (string.IsNullOrEmpty(password)) return false;
using (var req = new AccessTokenRequestPassword(username, password)
{
Url = $@"{endpoint}/oauth/token",
@@ -6,6 +6,7 @@ using System.Linq;
using Newtonsoft.Json;
using osu.Game.Beatmaps;
using osu.Game.Rulesets;
using System;
namespace osu.Game.Online.API.Requests
{
@@ -14,7 +15,7 @@ namespace osu.Game.Online.API.Requests
[JsonProperty(@"covers")]
private BeatmapSetOnlineCovers covers { get; set; }
[JsonProperty(@"previewUrl")]
[JsonProperty(@"preview_url")]
private string preview { get; set; }
[JsonProperty(@"play_count")]
@@ -23,6 +24,21 @@ namespace osu.Game.Online.API.Requests
[JsonProperty(@"favourite_count")]
private int favouriteCount { get; set; }
[JsonProperty(@"bpm")]
private double bpm { get; set; }
[JsonProperty(@"video")]
private bool hasVideo { get; set; }
[JsonProperty(@"submitted_date")]
private DateTimeOffset submitted { get; set; }
[JsonProperty(@"ranked_date")]
private DateTimeOffset ranked { get; set; }
[JsonProperty(@"last_updated")]
private DateTimeOffset lastUpdated { get; set; }
[JsonProperty(@"user_id")]
private long creatorId {
set { Author.Id = value; }
@@ -43,6 +59,11 @@ namespace osu.Game.Online.API.Requests
Preview = preview,
PlayCount = playCount,
FavouriteCount = favouriteCount,
BPM = bpm,
HasVideo = hasVideo,
Submitted = submitted,
Ranked = ranked,
LastUpdated = lastUpdated,
},
Beatmaps = beatmaps.Select(b => b.ToBeatmap(rulesets)).ToList(),
};
@@ -50,6 +71,9 @@ namespace osu.Game.Online.API.Requests
private class GetBeatmapSetsBeatmapResponse : BeatmapMetadata
{
[JsonProperty(@"id")]
private int onlineBeatmapID { get; set; }
[JsonProperty(@"playcount")]
private int playCount { get; set; }
@@ -62,6 +86,30 @@ namespace osu.Game.Online.API.Requests
[JsonProperty(@"difficulty_rating")]
private double starDifficulty { get; set; }
[JsonProperty(@"drain")]
private float drainRate { get; set; }
[JsonProperty(@"cs")]
private float circleSize { get; set; }
[JsonProperty(@"ar")]
private float approachRate { get; set; }
[JsonProperty(@"accuracy")]
private float overallDifficulty { get; set; }
[JsonProperty(@"total_length")]
private double length { get; set; }
[JsonProperty(@"count_circles")]
private int circleCount { get; set; }
[JsonProperty(@"count_sliders")]
private int sliderCount { get; set; }
[JsonProperty(@"version")]
private string version { get; set; }
public BeatmapInfo ToBeatmap(RulesetStore rulesets)
{
return new BeatmapInfo
@@ -69,10 +117,22 @@ namespace osu.Game.Online.API.Requests
Metadata = this,
Ruleset = rulesets.GetRuleset(ruleset),
StarDifficulty = starDifficulty,
OnlineBeatmapID = onlineBeatmapID,
Version = version,
BaseDifficulty = new BeatmapDifficulty
{
DrainRate = drainRate,
CircleSize = circleSize,
ApproachRate = approachRate,
OverallDifficulty = overallDifficulty,
},
OnlineInfo = new BeatmapOnlineInfo
{
PlayCount = playCount,
PassCount = passCount,
Length = length,
CircleCount = circleCount,
SliderCount = sliderCount,
},
};
}
@@ -0,0 +1,33 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using Humanizer;
using System.Collections.Generic;
namespace osu.Game.Online.API.Requests
{
public class GetUserBeatmapsRequest : APIRequest<List<GetBeatmapSetsResponse>>
{
private readonly long userId;
private readonly int offset;
private readonly BeatmapSetType type;
public GetUserBeatmapsRequest(long userId, BeatmapSetType type, int offset = 0)
{
this.userId = userId;
this.offset = offset;
this.type = type;
}
protected override string Target => $@"users/{userId}/beatmapsets/{type.ToString().Underscore()}?offset={offset}";
}
public enum BeatmapSetType
{
MostPlayed,
Favourite,
RankedAndApproved,
Unranked,
Graveyard
}
}
+16
View File
@@ -255,6 +255,22 @@ namespace osu.Game
};
}
// eventually informational overlays should be displayed in a stack, but for now let's only allow one to stay open at a time.
var informationalOverlays = new OverlayContainer[] { beatmapSetOverlay, userProfile };
foreach (var overlay in informationalOverlays)
{
overlay.StateChanged += state =>
{
if (state == Visibility.Hidden) return;
foreach (var c in informationalOverlays)
{
if (c == overlay) continue;
c.State = Visibility.Hidden;
}
};
}
settings.StateChanged += delegate
{
switch (settings.State)
+3 -3
View File
@@ -39,9 +39,9 @@ namespace osu.Game.Overlays.BeatmapSet
if (value == beatmap) return;
beatmap = value;
length.Value = TimeSpan.FromMilliseconds(beatmap.OnlineInfo.Length).ToString(@"m\:ss");
circleCount.Value = beatmap.OnlineInfo.CircleCount.ToString("N0");
sliderCount.Value = beatmap.OnlineInfo.SliderCount.ToString("N0");
length.Value = TimeSpan.FromSeconds(beatmap.OnlineInfo.Length).ToString(@"m\:ss");
circleCount.Value = beatmap.OnlineInfo.CircleCount.ToString();
sliderCount.Value = beatmap.OnlineInfo.SliderCount.ToString();
}
}
+6 -18
View File
@@ -26,6 +26,8 @@ namespace osu.Game.Overlays.BeatmapSet
private readonly Box tabsBg;
private readonly Container coverContainer;
private readonly OsuSpriteText title, artist;
private readonly Container noVideoButtons;
private readonly FillFlowContainer videoButtons;
private readonly AuthorInfo author;
public Details Details;
@@ -46,6 +48,9 @@ namespace osu.Game.Overlays.BeatmapSet
title.Text = BeatmapSet.Metadata.Title;
artist.Text = BeatmapSet.Metadata.Artist;
noVideoButtons.FadeTo(BeatmapSet.OnlineInfo.HasVideo ? 0 : 1, transition_duration);
videoButtons.FadeTo(BeatmapSet.OnlineInfo.HasVideo ? 1 : 0, transition_duration);
cover?.FadeOut(400, Easing.Out);
coverContainer.Add(cover = new DelayedLoadWrapper(new BeatmapSetCover(BeatmapSet)
{
@@ -77,9 +82,6 @@ namespace osu.Game.Overlays.BeatmapSet
Radius = 3,
Offset = new Vector2(0f, 1f),
};
Container noVideoButtons;
FillFlowContainer videoButtons;
Children = new Drawable[]
{
new Container
@@ -202,21 +204,7 @@ namespace osu.Game.Overlays.BeatmapSet
},
};
Picker.Beatmap.ValueChanged += b =>
{
Details.Beatmap = b;
if (b.OnlineInfo.HasVideo)
{
noVideoButtons.FadeOut(transition_duration);
videoButtons.FadeIn(transition_duration);
}
else
{
noVideoButtons.FadeIn(transition_duration);
videoButtons.FadeOut(transition_duration);
}
};
Picker.Beatmap.ValueChanged += b => Details.Beatmap = b;
}
[BackgroundDependencyLoader]
+2 -4
View File
@@ -74,20 +74,18 @@ namespace osu.Game.Overlays.BeatmapSet
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Right = metadata_width + BeatmapSetOverlay.RIGHT_WIDTH + spacing * 2 },
Child = new ScrollContainer
Child = new Container
{
RelativeSizeAxes = Axes.Both,
ScrollbarVisible = false,
Child = description = new MetadataSection("Description"),
},
},
new ScrollContainer
new Container
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
RelativeSizeAxes = Axes.Y,
Width = metadata_width,
ScrollbarVisible = false,
Padding = new MarginPadding { Horizontal = 10 },
Margin = new MarginPadding { Right = BeatmapSetOverlay.RIGHT_WIDTH + spacing },
Child = new FillFlowContainer
@@ -0,0 +1,62 @@
// Copyright (c) 2007-2017 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.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Users;
using osu.Framework.Input;
namespace osu.Game.Overlays.BeatmapSet.Scores
{
public class ClickableUsername : OsuHoverContainer
{
private readonly OsuSpriteText text;
private UserProfileOverlay profile;
private User user;
public User User
{
get { return user; }
set
{
if (user == value) return;
user = value;
text.Text = user.Username;
}
}
public float TextSize
{
set
{
if (text.TextSize == value) return;
text.TextSize = value;
}
get { return text.TextSize; }
}
public ClickableUsername()
{
AutoSizeAxes = Axes.Both;
Child = text = new OsuSpriteText
{
Font = @"Exo2.0-BoldItalic",
};
}
[BackgroundDependencyLoader(true)]
private void load(UserProfileOverlay profile)
{
this.profile = profile;
}
protected override bool OnClick(InputState state)
{
profile?.ShowUser(user);
return true;
}
}
}
@@ -0,0 +1,141 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Online.API.Requests;
using osu.Game.Overlays.Profile.Sections.Ranks;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI;
using osu.Game.Screens.Select.Leaderboards;
using osu.Game.Users;
namespace osu.Game.Overlays.BeatmapSet.Scores
{
public class DrawableScore : Container
{
private const int fade_duration = 100;
private const float side_margin = 20;
private readonly Box background;
public DrawableScore(int index, OnlineScore score)
{
ScoreModsContainer modsContainer;
RelativeSizeAxes = Axes.X;
Height = 30;
CornerRadius = 3;
Masking = true;
Children = new Drawable[]
{
background = new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = 0,
},
new OsuSpriteText
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Text = $"#{index + 1}",
Font = @"Exo2.0-RegularItalic",
Margin = new MarginPadding { Left = side_margin }
},
new DrawableFlag(score.User.Country?.FlagName)
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Size = new Vector2(30, 20),
Margin = new MarginPadding { Left = 60 }
},
new ClickableUsername
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
User = score.User,
Margin = new MarginPadding { Left = 100 }
},
modsContainer = new ScoreModsContainer
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
Width = 0.06f,
RelativePositionAxes = Axes.X,
X = 0.42f
},
new DrawableRank(score.Rank)
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Size = new Vector2(30, 20),
FillMode = FillMode.Fit,
RelativePositionAxes = Axes.X,
X = 0.55f
},
new OsuSpriteText
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreRight,
Text = $@"{score.TotalScore:N0}",
Font = @"Venera",
RelativePositionAxes = Axes.X,
X = 0.75f,
FixedWidth = true,
},
new OsuSpriteText
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreRight,
Text = $@"{score.Accuracy:P2}",
Font = @"Exo2.0-RegularItalic",
RelativePositionAxes = Axes.X,
X = 0.85f
},
new OsuSpriteText
{
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
Text = $"{score.Statistics["300"]}/{score.Statistics["100"]}/{score.Statistics["50"]}",
Font = @"Exo2.0-RegularItalic",
Margin = new MarginPadding { Right = side_margin }
},
};
foreach (Mod mod in score.Mods)
modsContainer.Add(new ModIcon(mod)
{
AutoSizeAxes = Axes.Both,
Scale = new Vector2(0.35f),
});
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
background.Colour = colours.Gray4;
}
protected override bool OnHover(InputState state)
{
background.FadeIn(fade_duration, Easing.OutQuint);
return base.OnHover(state);
}
protected override void OnHoverLost(InputState state)
{
background.FadeOut(fade_duration, Easing.OutQuint);
base.OnHoverLost(state);
}
protected override bool OnClick(InputState state) => true;
}
}
@@ -0,0 +1,243 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Online.API.Requests;
using osu.Game.Overlays.Profile.Sections.Ranks;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
using osu.Game.Screens.Select.Leaderboards;
using osu.Game.Users;
namespace osu.Game.Overlays.BeatmapSet.Scores
{
public class DrawableTopScore : Container
{
private const float fade_duration = 100;
private const float height = 200;
private const float avatar_size = 80;
private const float margin = 10;
private readonly Box background;
private readonly Box bottomBackground;
private readonly Box middleLine;
private readonly UpdateableAvatar avatar;
private readonly DrawableFlag flag;
private readonly ClickableUsername username;
private readonly OsuSpriteText rankText;
private readonly OsuSpriteText date;
private readonly DrawableRank rank;
private readonly InfoColumn totalScore;
private readonly InfoColumn accuracy;
private readonly InfoColumn statistics;
private readonly ScoreModsContainer modsContainer;
private OnlineScore score;
public OnlineScore Score
{
get { return score; }
set
{
if (score == value) return;
score = value;
avatar.User = username.User = score.User;
flag.FlagName = score.User.Country?.FlagName;
date.Text = $@"achieved {score.Date:MMM d, yyyy}";
rank.UpdateRank(score.Rank);
totalScore.Value = $@"{score.TotalScore:N0}";
accuracy.Value = $@"{score.Accuracy:P2}";
statistics.Value = $"{score.Statistics["300"]}/{score.Statistics["100"]}/{score.Statistics["50"]}";
modsContainer.Clear();
foreach (Mod mod in score.Mods)
modsContainer.Add(new ModIcon(mod)
{
AutoSizeAxes = Axes.Both,
Scale = new Vector2(0.45f),
});
}
}
public DrawableTopScore()
{
RelativeSizeAxes = Axes.X;
Height = height;
CornerRadius = 5;
BorderThickness = 4;
Masking = true;
Children = new Drawable[]
{
background = new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = 0,
AlwaysPresent = true, //used for correct border representation
},
avatar = new UpdateableAvatar
{
Size = new Vector2(avatar_size),
Masking = true,
CornerRadius = 5,
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Shadow,
Colour = Color4.Black.Opacity(0.25f),
Offset = new Vector2(0, 2),
Radius = 1,
},
Margin = new MarginPadding { Top = margin, Left = margin }
},
flag = new DrawableFlag
{
Size = new Vector2(30, 20),
Position = new Vector2(margin * 2 + avatar_size, height / 4),
},
username = new ClickableUsername
{
Origin = Anchor.BottomLeft,
TextSize = 30,
Position = new Vector2(margin * 2 + avatar_size, height / 4),
Margin = new MarginPadding { Bottom = 4 }
},
rankText = new OsuSpriteText
{
Anchor = Anchor.TopRight,
Origin = Anchor.BottomRight,
Text = "#1",
TextSize = 40,
Font = @"Exo2.0-BoldItalic",
Y = height / 4,
Margin = new MarginPadding { Right = margin }
},
date = new OsuSpriteText
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
Y = height / 4,
Margin = new MarginPadding { Right = margin }
},
new Container
{
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
RelativeSizeAxes = Axes.Both,
Height = 0.5f,
Children = new Drawable[]
{
bottomBackground = new Box { RelativeSizeAxes = Axes.Both },
middleLine = new Box
{
RelativeSizeAxes = Axes.X,
Height = 1,
},
rank = new DrawableRank(ScoreRank.F)
{
Origin = Anchor.BottomLeft,
Size = new Vector2(avatar_size, 40),
FillMode = FillMode.Fit,
Y = height / 4,
Margin = new MarginPadding { Left = margin }
},
new FillFlowContainer<InfoColumn>
{
Origin = Anchor.BottomLeft,
AutoSizeAxes = Axes.Both,
Position = new Vector2(height / 2, height / 4),
Direction = FillDirection.Horizontal,
Spacing = new Vector2(15, 0),
Children = new[]
{
totalScore = new InfoColumn("Score"),
accuracy = new InfoColumn("Accuracy"),
statistics = new InfoColumn("300/100/50"),
},
},
modsContainer = new ScoreModsContainer
{
AutoSizeAxes = Axes.Y,
Width = 80,
Position = new Vector2(height / 2, height / 4),
}
}
},
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
background.Colour = bottomBackground.Colour = colours.Gray4;
middleLine.Colour = colours.Gray2;
date.Colour = colours.Gray9;
BorderColour = rankText.Colour = colours.Yellow;
}
protected override bool OnHover(InputState state)
{
background.FadeIn(fade_duration, Easing.OutQuint);
return base.OnHover(state);
}
protected override void OnHoverLost(InputState state)
{
background.FadeOut(fade_duration, Easing.OutQuint);
base.OnHoverLost(state);
}
private class InfoColumn : FillFlowContainer
{
private readonly OsuSpriteText headerText;
private readonly OsuSpriteText valueText;
public string Value
{
set
{
if (valueText.Text == value)
return;
valueText.Text = value;
}
get { return valueText.Text; }
}
public InfoColumn(string header)
{
AutoSizeAxes = Axes.Both;
Direction = FillDirection.Vertical;
Spacing = new Vector2(0, 3);
Children = new Drawable[]
{
headerText = new OsuSpriteText
{
TextSize = 14,
Text = header,
Font = @"Exo2.0-Bold",
},
valueText = new OsuSpriteText
{
TextSize = 25,
Font = @"Exo2.0-RegularItalic",
}
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
headerText.Colour = colours.Gray9;
}
}
}
}
@@ -0,0 +1,115 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API.Requests;
using System.Collections.Generic;
using System.Linq;
namespace osu.Game.Overlays.BeatmapSet.Scores
{
public class ScoresContainer : Container
{
private const int spacing = 15;
private const int fade_duration = 200;
private readonly FillFlowContainer flow;
private readonly DrawableTopScore topScore;
private readonly LoadingAnimation loadingAnimation;
private readonly Box foreground;
private bool isLoading;
public bool IsLoading
{
get { return isLoading; }
set
{
if (isLoading == value) return;
isLoading = value;
foreground.FadeTo(isLoading ? 1 : 0, fade_duration);
loadingAnimation.FadeTo(isLoading ? 1 : 0, fade_duration);
}
}
private IEnumerable<OnlineScore> scores;
public IEnumerable<OnlineScore> Scores
{
get { return scores; }
set
{
scores = value;
var scoresAmount = scores.Count();
if (scoresAmount == 0)
{
CleanAllScores();
return;
}
topScore.Score = scores.FirstOrDefault();
topScore.Show();
flow.Clear();
if (scoresAmount < 2)
return;
for (int i = 1; i < scoresAmount; i++)
flow.Add(new DrawableScore(i, scores.ElementAt(i)));
}
}
public ScoresContainer()
{
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
Children = new Drawable[]
{
new FillFlowContainer
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Width = 0.95f,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, spacing),
Margin = new MarginPadding { Vertical = spacing },
Children = new Drawable[]
{
topScore = new DrawableTopScore(),
flow = new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 1),
},
}
},
foreground = new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black.Opacity(0.7f),
Alpha = 0,
},
loadingAnimation = new LoadingAnimation
{
Alpha = 0,
},
};
}
public void CleanAllScores()
{
topScore.Hide();
flow.Clear();
}
}
}
+4 -1
View File
@@ -29,7 +29,10 @@ namespace osu.Game.Overlays.BeatmapSet
if (value == beatmap) return;
beatmap = value;
var rate = (float)beatmap.OnlineInfo.PassCount / beatmap.OnlineInfo.PlayCount;
int passCount = beatmap.OnlineInfo.PassCount;
int playCount = beatmap.OnlineInfo.PlayCount;
var rate = playCount != 0 ? (float)passCount / playCount : 0;
successPercent.Text = rate.ToString("P0");
successRate.Length = rate;
percentContainer.ResizeWidthTo(successRate.Length, 250, Easing.InOutCubic);
+34 -2
View File
@@ -16,6 +16,7 @@ using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Overlays.BeatmapSet;
using osu.Game.Rulesets;
using osu.Game.Overlays.BeatmapSet.Scores;
namespace osu.Game.Overlays
{
@@ -26,9 +27,13 @@ namespace osu.Game.Overlays
private readonly Header header;
private readonly Info info;
private readonly ScoresContainer scores;
private APIAccess api;
private RulesetStore rulesets;
private GetScoresRequest getScoresRequest;
private readonly ScrollContainer scroll;
// receive input outside our bounds so we can trigger a close event on ourselves.
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => true;
@@ -61,7 +66,7 @@ namespace osu.Game.Overlays
RelativeSizeAxes = Axes.Both,
Colour = OsuColour.Gray(0.2f)
},
new ScrollContainer
scroll = new ScrollContainer
{
RelativeSizeAxes = Axes.Both,
ScrollbarVisible = false,
@@ -74,12 +79,38 @@ namespace osu.Game.Overlays
{
header = new Header(),
info = new Info(),
scores = new ScoresContainer(),
},
},
},
};
header.Picker.Beatmap.ValueChanged += b => info.Beatmap = b;
header.Picker.Beatmap.ValueChanged += b =>
{
info.Beatmap = b;
updateScores(b);
};
}
private void updateScores(BeatmapInfo beatmap)
{
getScoresRequest?.Cancel();
if (!beatmap.OnlineBeatmapID.HasValue)
{
scores.CleanAllScores();
return;
}
scores.IsLoading = true;
getScoresRequest = new GetScoresRequest(beatmap);
getScoresRequest.Success += r =>
{
scores.Scores = r.Scores;
scores.IsLoading = false;
};
api.Queue(getScoresRequest);
}
[BackgroundDependencyLoader]
@@ -120,6 +151,7 @@ namespace osu.Game.Overlays
{
header.BeatmapSet = info.BeatmapSet = set;
Show();
scroll.ScrollTo(0);
}
}
}
@@ -29,6 +29,7 @@ namespace osu.Game.Overlays.Direct
public DirectGridPanel(BeatmapSetInfo beatmap) : base(beatmap)
{
Width = 400;
Height = 140 + vertical_padding; //full height of all the elements plus vertical padding (autosize uses the image)
}
+1 -1
View File
@@ -222,7 +222,7 @@ namespace osu.Game.Overlays
switch (displayStyle)
{
case PanelDisplayStyle.Grid:
return new DirectGridPanel(b) { Width = 400 };
return new DirectGridPanel(b);
default:
return new DirectListPanel(b);
}
-3
View File
@@ -207,14 +207,12 @@ namespace osu.Game.Overlays.Mods
{
Origin = Anchor.BottomRight,
Anchor = Anchor.BottomRight,
AutoSizeAxes = Axes.Both,
Position = new Vector2(1.5f),
},
foregroundIcon = new ModIcon(Mods[0])
{
Origin = Anchor.BottomRight,
Anchor = Anchor.BottomRight,
AutoSizeAxes = Axes.Both,
Position = new Vector2(-1.5f),
},
});
@@ -225,7 +223,6 @@ namespace osu.Game.Overlays.Mods
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
AutoSizeAxes = Axes.Both,
});
}
}
+72 -55
View File
@@ -2,7 +2,6 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using System.Linq;
using OpenTK;
using osu.Framework.Allocation;
@@ -33,6 +32,9 @@ namespace osu.Game.Overlays.Profile
{
this.user = user;
int[] userRanks = user.RankHistory?.Data ?? new[] { user.Statistics.Rank };
ranks = userRanks.SkipWhile(x => x == 0).ToArray();
Padding = new MarginPadding { Vertical = padding };
Children = new Drawable[]
{
@@ -58,19 +60,21 @@ namespace osu.Game.Overlays.Profile
Font = @"Exo2.0-RegularItalic",
TextSize = secondary_textsize
},
graph = new RankChartLineGraph
};
if (ranks.Length > 0)
{
Add(graph = new RankChartLineGraph
{
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
RelativeSizeAxes = Axes.X,
Y = -secondary_textsize,
DefaultValueCount = 90,
BallRelease = updateRankTexts,
BallMove = showHistoryRankTexts
}
};
DefaultValueCount = ranks.Length,
});
ranks = user.RankHistory?.Data ?? new[] { user.Statistics.Rank };
graph.OnBallMove += showHistoryRankTexts;
}
}
private void updateRankTexts()
@@ -82,7 +86,8 @@ namespace osu.Game.Overlays.Profile
private void showHistoryRankTexts(int dayIndex)
{
rankText.Text = ranks[dayIndex] > 0 ? $"#{ranks[dayIndex]:#,0}" : "no rank";
rankText.Text = $"#{ranks[dayIndex]:#,0}";
dayIndex++;
relativeText.Text = dayIndex == ranks.Length ? "Now" : $"{ranks.Length - dayIndex} days ago";
//plural should be handled in a general way
}
@@ -90,14 +95,15 @@ namespace osu.Game.Overlays.Profile
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
graph.Colour = colours.Yellow;
if (user.Statistics.Rank > 0)
if (graph != null)
{
graph.Colour = colours.Yellow;
// use logarithmic coordinates
graph.Values = ranks.Select(x => -(float)Math.Log(x));
graph.ResetBall();
graph.SetStaticBallPosition();
}
updateRankTexts();
}
public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true)
@@ -110,67 +116,78 @@ namespace osu.Game.Overlays.Profile
return base.Invalidate(invalidation, source, shallPropagate);
}
protected override bool OnHover(InputState state)
{
graph?.UpdateBallPosition(state.Mouse.Position.X);
graph?.ShowBall();
return base.OnHover(state);
}
protected override bool OnMouseMove(InputState state)
{
graph?.UpdateBallPosition(state.Mouse.Position.X);
return base.OnMouseMove(state);
}
protected override void OnHoverLost(InputState state)
{
if (graph != null)
{
graph.HideBall();
updateRankTexts();
}
base.OnHoverLost(state);
}
private class RankChartLineGraph : LineGraph
{
private readonly CircularContainer ball;
private bool ballShown;
private const double fade_duration = 200;
private const double transform_duration = 100;
private readonly CircularContainer staticBall;
private readonly CircularContainer movingBall;
public Action<int> BallMove;
public Action BallRelease;
public Action<int> OnBallMove;
public RankChartLineGraph()
{
Add(ball = new CircularContainer
Add(staticBall = new CircularContainer
{
Origin = Anchor.Centre,
Size = new Vector2(8),
Masking = true,
Origin = Anchor.Centre,
Alpha = 0,
RelativePositionAxes = Axes.Both,
Children = new Drawable[]
{
new Box { RelativeSizeAxes = Axes.Both }
}
Child = new Box { RelativeSizeAxes = Axes.Both }
});
Add(movingBall = new CircularContainer
{
Origin = Anchor.Centre,
Size = new Vector2(8),
Alpha = 0,
Masking = true,
RelativePositionAxes = Axes.Both,
Child = new Box { RelativeSizeAxes = Axes.Both }
});
}
public void ResetBall()
public void SetStaticBallPosition() => staticBall.Position = new Vector2(1, GetYPosition(Values.Last()));
public void UpdateBallPosition(float mouseXPosition)
{
ball.MoveTo(new Vector2(1, GetYPosition(Values.Last())), ballShown ? transform_duration : 0, Easing.OutQuint);
ball.Show();
BallRelease();
ballShown = true;
int index = calculateIndex(mouseXPosition);
movingBall.Position = calculateBallPosition(index);
OnBallMove.Invoke(index);
}
protected override bool OnMouseMove(InputState state)
{
if (ballShown)
{
var values = (IList<float>)Values;
var position = ToLocalSpace(state.Mouse.NativeState.Position);
int count = Math.Max(values.Count, DefaultValueCount);
int index = (int)Math.Round(position.X / DrawWidth * (count - 1));
if (index >= count - values.Count)
{
int i = index + values.Count - count;
float y = GetYPosition(values[i]);
if (Math.Abs(y * DrawHeight - position.Y) <= 8f)
{
ball.MoveTo(new Vector2(index / (float)(count - 1), y), transform_duration, Easing.OutQuint);
BallMove(i);
}
}
}
return base.OnMouseMove(state);
}
public void ShowBall() => movingBall.FadeIn(fade_duration);
protected override void OnHoverLost(InputState state)
public void HideBall() => movingBall.FadeOut(fade_duration);
private int calculateIndex(float mouseXPosition) => (int)Math.Round(mouseXPosition / DrawWidth * (DefaultValueCount - 1));
private Vector2 calculateBallPosition(int index)
{
if (ballShown)
ResetBall();
base.OnHoverLost(state);
float y = GetYPosition(Values.ElementAt(index));
return new Vector2(index / (float)(DefaultValueCount - 1), y);
}
}
}
@@ -0,0 +1,72 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Game.Online.API.Requests;
using osu.Game.Overlays.Direct;
using osu.Game.Users;
using System.Linq;
namespace osu.Game.Overlays.Profile.Sections.Beatmaps
{
public class PaginatedBeatmapContainer : PaginatedContainer
{
private const float panel_padding = 10f;
private readonly BeatmapSetType type;
private DirectPanel currentlyPlaying;
public PaginatedBeatmapContainer(BeatmapSetType type, Bindable<User> user, string header, string missing = "None... yet.")
: base(user, header, missing)
{
this.type = type;
ItemsPerPage = 6;
ItemsContainer.Spacing = new Vector2(panel_padding);
}
protected override void ShowMore()
{
base.ShowMore();
var req = new GetUserBeatmapsRequest(User.Value.Id, type, VisiblePages++ * ItemsPerPage);
req.Success += sets =>
{
ShowMoreButton.FadeTo(sets.Count == ItemsPerPage ? 1 : 0);
ShowMoreLoading.Hide();
if (!sets.Any())
{
MissingText.Show();
return;
}
foreach (var s in sets)
{
if (!s.OnlineBeatmapSetID.HasValue)
continue;
var panel = new DirectGridPanel(s.ToBeatmapSet(Rulesets));
ItemsContainer.Add(panel);
panel.PreviewPlaying.ValueChanged += isPlaying =>
{
if (!isPlaying) return;
if (currentlyPlaying != null && currentlyPlaying != panel)
currentlyPlaying.PreviewPlaying.Value = false;
currentlyPlaying = panel;
};
}
};
Api.Queue(req);
}
}
}
@@ -1,6 +1,9 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Online.API.Requests;
using osu.Game.Overlays.Profile.Sections.Beatmaps;
namespace osu.Game.Overlays.Profile.Sections
{
public class BeatmapsSection : ProfileSection
@@ -8,5 +11,16 @@ namespace osu.Game.Overlays.Profile.Sections
public override string Title => "Beatmaps";
public override string Identifier => "beatmaps";
public BeatmapsSection()
{
Children = new[]
{
new PaginatedBeatmapContainer(BeatmapSetType.Favourite, User, "Favourite Beatmaps"),
new PaginatedBeatmapContainer(BeatmapSetType.RankedAndApproved, User, "Ranked & Approved Beatmaps"),
new PaginatedBeatmapContainer(BeatmapSetType.Unranked, User, "Pending Beatmaps"),
new PaginatedBeatmapContainer(BeatmapSetType.Graveyard, User, "Graveyarded Beatmaps"),
};
}
}
}
@@ -14,7 +14,7 @@ namespace osu.Game.Overlays.Profile.Sections
public HistoricalSection()
{
Child = new PaginatedScoreContainer(ScoreType.Recent, User, "Recent Plays (24h)");
Child = new PaginatedScoreContainer(ScoreType.Recent, User, "Recent Plays (24h)", "No performance records. :(");
}
}
}
@@ -0,0 +1,110 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API;
using osu.Game.Rulesets;
using osu.Game.Users;
namespace osu.Game.Overlays.Profile.Sections
{
public class PaginatedContainer : FillFlowContainer
{
protected readonly FillFlowContainer ItemsContainer;
protected readonly OsuHoverContainer ShowMoreButton;
protected readonly LoadingAnimation ShowMoreLoading;
protected readonly OsuSpriteText MissingText;
protected int VisiblePages;
protected int ItemsPerPage;
protected readonly Bindable<User> User = new Bindable<User>();
protected APIAccess Api;
protected RulesetStore Rulesets;
public PaginatedContainer(Bindable<User> user, string header, string missing)
{
User.BindTo(user);
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
Direction = FillDirection.Vertical;
Children = new Drawable[]
{
new OsuSpriteText
{
TextSize = 15,
Text = header,
Font = "Exo2.0-RegularItalic",
Margin = new MarginPadding { Top = 10, Bottom = 10 },
},
ItemsContainer = new FillFlowContainer
{
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
Margin = new MarginPadding { Bottom = 10 }
},
ShowMoreButton = new OsuHoverContainer
{
Alpha = 0,
Action = ShowMore,
AutoSizeAxes = Axes.Both,
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Child = new OsuSpriteText
{
TextSize = 14,
Text = "show more",
}
},
ShowMoreLoading = new LoadingAnimation
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Size = new Vector2(14),
},
MissingText = new OsuSpriteText
{
TextSize = 14,
Text = missing,
Alpha = 0,
},
};
}
[BackgroundDependencyLoader]
private void load(APIAccess api, RulesetStore rulesets)
{
Api = api;
Rulesets = rulesets;
User.ValueChanged += onUserChanged;
User.TriggerChange();
}
private void onUserChanged(User newUser)
{
VisiblePages = 0;
ItemsContainer.Clear();
ShowMoreButton.Hide();
if (newUser != null)
ShowMore();
}
protected virtual void ShowMore()
{
ShowMoreLoading.Show();
ShowMoreButton.Hide();
}
}
}
@@ -20,7 +20,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
}
[BackgroundDependencyLoader]
private new void load(OsuColour colour)
private void load(OsuColour colour)
{
double pp = Score.PP ?? 0;
Stats.Add(new OsuSpriteText
@@ -1,80 +1,124 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
using OpenTK;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Mods;
using osu.Game.Screens.Select.Leaderboards;
using System.Linq;
using osu.Framework.Localisation;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
using OpenTK.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Input;
using osu.Framework.Extensions.Color4Extensions;
using osu.Game.Graphics.Containers;
namespace osu.Game.Overlays.Profile.Sections.Ranks
{
public abstract class DrawableScore : Container
{
private const int fade_duration = 200;
protected readonly FillFlowContainer<OsuSpriteText> Stats;
private readonly FillFlowContainer metadata;
private readonly ModContainer modContainer;
private readonly ScoreModsContainer modsContainer;
protected readonly Score Score;
private readonly Box underscoreLine;
private readonly Box coloredBackground;
private readonly Container background;
protected DrawableScore(Score score)
{
Score = score;
RelativeSizeAxes = Axes.X;
Height = 60;
Children = new Drawable[]
{
new DrawableRank(score.Rank)
background = new Container
{
RelativeSizeAxes = Axes.Y,
Width = 60,
FillMode = FillMode.Fit,
},
Stats = new FillFlowContainer<OsuSpriteText>
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
Direction = FillDirection.Vertical,
},
metadata = new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Margin = new MarginPadding { Left = 70 },
Direction = FillDirection.Vertical,
Child = new OsuSpriteText
RelativeSizeAxes = Axes.Both,
Masking = true,
CornerRadius = 3,
Alpha = 0,
EdgeEffect = new EdgeEffectParameters
{
Text = score.Date.LocalDateTime.ToShortDateString(),
TextSize = 11,
Colour = OsuColour.Gray(0xAA),
Depth = -1,
Type = EdgeEffectType.Shadow,
Offset = new Vector2(0f, 1f),
Radius = 1f,
Colour = Color4.Black.Opacity(0.2f),
},
Child = coloredBackground = new Box { RelativeSizeAxes = Axes.Both }
},
modContainer = new ModContainer
new Container
{
AutoSizeAxes = Axes.Y,
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
Width = 60,
Margin = new MarginPadding { Right = 150 }
}
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Width = 0.97f,
Children = new Drawable[]
{
underscoreLine = new Box
{
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
RelativeSizeAxes = Axes.X,
Height = 1,
},
new DrawableRank(score.Rank)
{
RelativeSizeAxes = Axes.Y,
Width = 60,
FillMode = FillMode.Fit,
},
Stats = new FillFlowContainer<OsuSpriteText>
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
Direction = FillDirection.Vertical,
},
metadata = new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Margin = new MarginPadding { Left = 70 },
Direction = FillDirection.Vertical,
Child = new OsuSpriteText
{
Text = score.Date.LocalDateTime.ToShortDateString(),
TextSize = 11,
Colour = OsuColour.Gray(0xAA),
Depth = -1,
},
},
modsContainer = new ScoreModsContainer
{
AutoSizeAxes = Axes.Y,
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
Width = 60,
Margin = new MarginPadding { Right = 160 }
}
}
},
};
}
[BackgroundDependencyLoader(true)]
private void load(OsuColour colour, LocalisationEngine locale, BeatmapSetOverlay beatmapSetOverlay)
{
coloredBackground.Colour = underscoreLine.Colour = colour.Gray4;
Stats.Add(new OsuSpriteText
{
Text = $"accuracy: {Score.Accuracy:P2}",
@@ -86,7 +130,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
Depth = -1,
});
metadata.Add(new OsuHoverContainer
metadata.Add(new MetadataContainer(Score.Beatmap.Metadata.Title, Score.Beatmap.Metadata.Artist)
{
AutoSizeAxes = Axes.Both,
Action = () =>
@@ -119,20 +163,32 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
});
foreach (Mod mod in Score.Mods)
modContainer.Add(new ModIcon(mod)
{
AutoSizeAxes = Axes.Both,
Scale = new Vector2(0.5f),
});
modsContainer.Add(new ModIcon(mod) { Scale = new Vector2(0.5f) });
}
private class ModContainer : FlowContainer<ModIcon>
protected override bool OnClick(InputState state) => true;
protected override bool OnHover(InputState state)
{
protected override IEnumerable<Vector2> ComputeLayoutPositions()
background.FadeIn(fade_duration, Easing.OutQuint);
underscoreLine.FadeOut(fade_duration, Easing.OutQuint);
return true;
}
protected override void OnHoverLost(InputState state)
{
background.FadeOut(fade_duration, Easing.OutQuint);
underscoreLine.FadeIn(fade_duration, Easing.OutQuint);
base.OnHoverLost(state);
}
private class MetadataContainer : OsuHoverContainer, IHasTooltip
{
public string TooltipText { get; set; }
public MetadataContainer(string title, string artist)
{
int count = FlowingChildren.Count();
for (int i = 0; i < count; i++)
yield return new Vector2(DrawWidth * i * (count == 1 ? 0 : 1f / (count - 1)), 0);
TooltipText = $"{artist} - {title}";
}
}
}
@@ -16,7 +16,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
}
[BackgroundDependencyLoader]
private new void load()
private void load()
{
Stats.Add(new OsuSpriteText
{
@@ -1,130 +1,53 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Rulesets;
using osu.Game.Users;
using System;
using System.Linq;
namespace osu.Game.Overlays.Profile.Sections.Ranks
{
public class PaginatedScoreContainer : FillFlowContainer
public class PaginatedScoreContainer : PaginatedContainer
{
private readonly FillFlowContainer<DrawableScore> scoreContainer;
private readonly OsuSpriteText missing;
private readonly OsuHoverContainer showMoreButton;
private readonly LoadingAnimation showMoreLoading;
private readonly bool includeWeight;
private readonly ScoreType type;
private int visiblePages;
private readonly Bindable<User> user = new Bindable<User>();
private RulesetStore rulesets;
private APIAccess api;
public PaginatedScoreContainer(ScoreType type, Bindable<User> user, string header, bool includeWeight = false)
public PaginatedScoreContainer(ScoreType type, Bindable<User> user, string header, string missing, bool includeWeight = false)
: base(user, header, missing)
{
this.type = type;
this.includeWeight = includeWeight;
this.user.BindTo(user);
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
Direction = FillDirection.Vertical;
ItemsPerPage = 5;
Children = new Drawable[]
{
new OsuSpriteText
{
TextSize = 15,
Text = header,
Font = "Exo2.0-RegularItalic",
Margin = new MarginPadding { Top = 10, Bottom = 10 },
},
scoreContainer = new FillFlowContainer<DrawableScore>
{
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
Direction = FillDirection.Vertical,
},
showMoreButton = new OsuHoverContainer
{
Alpha = 0,
Action = showMore,
AutoSizeAxes = Axes.Both,
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Child = new OsuSpriteText
{
TextSize = 14,
Text = "show more",
}
},
showMoreLoading = new LoadingAnimation
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Size = new Vector2(14),
},
missing = new OsuSpriteText
{
TextSize = 14,
Text = type == ScoreType.Recent ? "No performance records. :(" : "No awesome performance records yet. :(",
},
};
ItemsContainer.Direction = FillDirection.Vertical;
}
[BackgroundDependencyLoader]
private void load(APIAccess api, RulesetStore rulesets)
protected override void ShowMore()
{
this.api = api;
this.rulesets = rulesets;
base.ShowMore();
user.ValueChanged += user_ValueChanged;
user.TriggerChange();
}
private void user_ValueChanged(User newUser)
{
visiblePages = 0;
scoreContainer.Clear();
showMoreButton.Hide();
missing.Show();
if (newUser != null)
showMore();
}
private void showMore()
{
var req = new GetUserScoresRequest(user.Value.Id, type, visiblePages++ * 5);
showMoreLoading.Show();
showMoreButton.Hide();
var req = new GetUserScoresRequest(User.Value.Id, type, VisiblePages++ * ItemsPerPage);
req.Success += scores =>
{
foreach (var s in scores)
s.ApplyRuleset(rulesets.GetRuleset(s.OnlineRulesetID));
s.ApplyRuleset(Rulesets.GetRuleset(s.OnlineRulesetID));
showMoreButton.FadeTo(scores.Count == 5 ? 1 : 0);
showMoreLoading.Hide();
ShowMoreButton.FadeTo(scores.Count == ItemsPerPage ? 1 : 0);
ShowMoreLoading.Hide();
if (!scores.Any()) return;
if (!scores.Any())
{
MissingText.Show();
return;
}
missing.Hide();
MissingText.Hide();
foreach (OnlineScore score in scores)
{
@@ -133,21 +56,18 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
switch (type)
{
default:
drawableScore = new DrawablePerformanceScore(score, includeWeight ? Math.Pow(0.95, scoreContainer.Count) : (double?)null);
drawableScore = new DrawablePerformanceScore(score, includeWeight ? Math.Pow(0.95, ItemsContainer.Count) : (double?)null);
break;
case ScoreType.Recent:
drawableScore = new DrawableTotalScore(score);
break;
}
drawableScore.RelativeSizeAxes = Axes.X;
drawableScore.Height = 60;
scoreContainer.Add(drawableScore);
ItemsContainer.Add(drawableScore);
}
};
api.Queue(req);
Api.Queue(req);
}
}
}
@@ -0,0 +1,21 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.UI;
using System.Collections.Generic;
using System.Linq;
namespace osu.Game.Overlays.Profile.Sections.Ranks
{
public class ScoreModsContainer : FlowContainer<ModIcon>
{
protected override IEnumerable<Vector2> ComputeLayoutPositions()
{
int count = FlowingChildren.Count();
for (int i = 0; i < count; i++)
yield return new Vector2(DrawWidth * i * (count == 1 ? 0 : 1f / (count - 1)), 0);
}
}
}
@@ -16,8 +16,8 @@ namespace osu.Game.Overlays.Profile.Sections
{
Children = new[]
{
new PaginatedScoreContainer(ScoreType.Best, User, "Best Performance", true),
new PaginatedScoreContainer(ScoreType.Firsts, User, "First Place Ranks"),
new PaginatedScoreContainer(ScoreType.Best, User, "Best Performance", "No performance records. :(", true),
new PaginatedScoreContainer(ScoreType.Firsts, User, "First Place Ranks", "No awesome performance records yet. :("),
};
}
}
+20 -11
View File
@@ -33,7 +33,7 @@ namespace osu.Game.Overlays.Settings
private SpriteText text;
private readonly RestoreDefaultValueButton<T> restoreDefaultValueButton = new RestoreDefaultValueButton<T>();
private readonly RestoreDefaultValueButton restoreDefaultValueButton = new RestoreDefaultValueButton();
public bool ShowsDefaultIndicator = true;
@@ -80,7 +80,7 @@ namespace osu.Game.Overlays.Settings
controlWithCurrent?.Current.BindTo(bindable);
if (ShowsDefaultIndicator)
{
restoreDefaultValueButton.Bindable.BindTo(bindable);
restoreDefaultValueButton.Bindable = bindable.GetBoundCopy();
restoreDefaultValueButton.Bindable.TriggerChange();
}
}
@@ -132,9 +132,19 @@ namespace osu.Game.Overlays.Settings
}
}
private class RestoreDefaultValueButton<T> : Box, IHasTooltip
private class RestoreDefaultValueButton : Box, IHasTooltip
{
internal readonly Bindable<T> Bindable = new Bindable<T>();
private Bindable<T> bindable;
internal Bindable<T> Bindable
{
get { return bindable; }
set
{
bindable = value;
bindable.ValueChanged += newValue => UpdateState();
bindable.DisabledChanged += disabled => UpdateState();
}
}
private Color4 buttonColour;
@@ -142,9 +152,6 @@ namespace osu.Game.Overlays.Settings
public RestoreDefaultValueButton()
{
Bindable.ValueChanged += value => UpdateState();
Bindable.DisabledChanged += disabled => UpdateState();
RelativeSizeAxes = Axes.Y;
Width = SettingsOverlay.CONTENT_MARGINS;
Alpha = 0f;
@@ -160,8 +167,8 @@ namespace osu.Game.Overlays.Settings
protected override bool OnClick(InputState state)
{
if (!Bindable.Disabled)
Bindable.SetDefault();
if (bindable != null && !bindable.Disabled)
bindable.SetDefault();
return true;
}
@@ -186,8 +193,10 @@ namespace osu.Game.Overlays.Settings
internal void UpdateState()
{
var colour = Bindable.Disabled ? Color4.Gray : buttonColour;
this.FadeTo(Bindable.IsDefault ? 0f : hovering && !Bindable.Disabled ? 1f : 0.5f, 200, Easing.OutQuint);
if (bindable == null)
return;
var colour = bindable.Disabled ? Color4.Gray : buttonColour;
this.FadeTo(bindable.IsDefault ? 0f : hovering && !bindable.Disabled ? 1f : 0.5f, 200, Easing.OutQuint);
this.FadeColour(ColourInfo.GradientHorizontal(colour.Opacity(0.8f), colour.Opacity(0)), 200, Easing.OutQuint);
}
}
+3 -2
View File
@@ -91,12 +91,12 @@ namespace osu.Game.Overlays
sections = new ProfileSection[]
{
new AboutSection(),
//new AboutSection(),
//new RecentSection(),
new RanksSection(),
//new MedalsSection(),
new HistoricalSection(),
//new BeatmapsSection(),
new BeatmapsSection(),
//new KudosuSection()
};
tabs = new ProfileTabControl
@@ -164,6 +164,7 @@ namespace osu.Game.Overlays
}
Show();
sectionsContainer.ScrollToTop();
}
private void userLoadComplete(User user)
-20
View File
@@ -1,20 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.IO;
using System.Reflection;
namespace osu.Game.Tests.Resources
{
public static class Resource
{
public static Stream OpenResource(string name)
{
var localPath = Path.GetDirectoryName(Uri.UnescapeDataString(new UriBuilder(Assembly.GetExecutingAssembly().CodeBase).Path));
return Assembly.GetExecutingAssembly().GetManifestResourceStream($@"osu.Game.Tests.Resources.{name}") ??
Assembly.LoadFrom(Path.Combine(localPath, @"osu.Game.Resources.dll")).GetManifestResourceStream($@"osu.Game.Resources.{name}");
}
}
}
File diff suppressed because it is too large Load Diff
@@ -83,7 +83,7 @@ namespace osu.Game.Rulesets.Judgements
break;
}
Expire();
Expire(true);
}
}
}
+18
View File
@@ -17,8 +17,26 @@ namespace osu.Game.Rulesets.Judgements
/// </summary>
public virtual HitResult MaxResult => HitResult.Perfect;
/// <summary>
/// The combo prior to this judgement occurring.
/// </summary>
internal int ComboAtJudgement;
/// <summary>
/// The highest combo achieved prior to this judgement occurring.
/// </summary>
internal int HighestComboAtJudgement;
/// <summary>
/// Whether a successful hit occurred.
/// </summary>
public bool IsHit => Result > HitResult.Miss;
/// <summary>
/// Whether this judgement is the final judgement for the hit object.
/// </summary>
public bool Final = true;
/// <summary>
/// The offset from a perfect hit at which this judgement occurred.
/// Populated when added via <see cref="DrawableHitObject{TObject}.AddJudgement"/>.
-22
View File
@@ -1,22 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets.Mods
{
/// <summary>
/// An interface for mods that are applied to a RulesetContainer.
/// </summary>
/// <typeparam name="TObject">The type of HitObject the RulesetContainer contains.</typeparam>
public interface IApplicableMod<TObject>
where TObject : HitObject
{
/// <summary>
/// Applies the mod to a RulesetContainer.
/// </summary>
/// <param name="rulesetContainer">The RulesetContainer to apply the mod to.</param>
void ApplyToRulesetContainer(RulesetContainer<TObject> rulesetContainer);
}
}
@@ -0,0 +1,20 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Objects;
namespace osu.Game.Rulesets.Mods
{
/// <summary>
/// An interface for <see cref="Mod"/>s that can be applied to <see cref="HitObject"/>s.
/// </summary>
public interface IApplicableToHitObject<in TObject>
where TObject : HitObject
{
/// <summary>
/// Applies this <see cref="IApplicableToHitObject{TObject}"/> to a <see cref="HitObject"/>.
/// </summary>
/// <param name="hitObject">The <see cref="HitObject"/> to apply to.</param>
void ApplyToHitObject(TObject hitObject);
}
}
@@ -0,0 +1,21 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets.Mods
{
/// <summary>
/// An interface for <see cref="Mod"/>s that can be applied to <see cref="RulesetContainer"/>s.
/// </summary>
public interface IApplicableToRulesetContainer<TObject>
where TObject : HitObject
{
/// <summary>
/// Applies this <see cref="IApplicableToRulesetContainer{TObject}"/> to a <see cref="RulesetContainer{TObject}"/>.
/// </summary>
/// <param name="rulesetContainer">The <see cref="RulesetContainer{TObject}"/> to apply to.</param>
void ApplyToRulesetContainer(RulesetContainer<TObject> rulesetContainer);
}
}

Some files were not shown because too many files have changed in this diff Show More