1
0
mirror of https://github.com/ppy/osu.git synced 2026-05-18 08:30:00 +08:00

Compare commits

..

95 Commits

67 changed files with 1447 additions and 1491 deletions
+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!" },
+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
});
}
}
@@ -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!";
@@ -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;
@@ -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),
},
+1
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" />
+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; }
}
+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 -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";
+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);
}
}
}
+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.
@@ -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()
{
+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"))
{
@@ -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,
},
};
}
@@ -26,6 +26,8 @@ namespace osu.Game.Online.API.Requests
{
MostPlayed,
Favourite,
RankedAndApproved
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();
}
}
}
+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,
});
}
}
@@ -17,9 +17,9 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps
private readonly BeatmapSetType type;
private DirectPanel playing;
private DirectPanel currentlyPlaying;
public PaginatedBeatmapContainer(BeatmapSetType type, Bindable<User> user, string header, string missing)
public PaginatedBeatmapContainer(BeatmapSetType type, Bindable<User> user, string header, string missing = "None... yet.")
: base(user, header, missing)
{
this.type = type;
@@ -27,7 +27,6 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps
ItemsPerPage = 6;
ItemsContainer.Spacing = new Vector2(panel_padding);
ItemsContainer.Margin = new MarginPadding { Bottom = panel_padding };
}
protected override void ShowMore()
@@ -52,24 +51,18 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps
if (!s.OnlineBeatmapSetID.HasValue)
continue;
var subReq = new GetBeatmapSetRequest(s.OnlineBeatmapSetID.Value);
subReq.Success += b =>
var panel = new DirectGridPanel(s.ToBeatmapSet(Rulesets));
ItemsContainer.Add(panel);
panel.PreviewPlaying.ValueChanged += isPlaying =>
{
var panel = new DirectGridPanel(b.ToBeatmapSet(Rulesets)) { Width = 400 };
ItemsContainer.Add(panel);
if (!isPlaying) return;
panel.PreviewPlaying.ValueChanged += newValue =>
{
if (newValue)
{
if (playing != null && playing != panel)
playing.PreviewPlaying.Value = false;
playing = panel;
}
};
if (currentlyPlaying != null && currentlyPlaying != panel)
currentlyPlaying.PreviewPlaying.Value = false;
currentlyPlaying = panel;
};
Api.Queue(subReq);
}
};
@@ -16,8 +16,10 @@ namespace osu.Game.Overlays.Profile.Sections
{
Children = new[]
{
new PaginatedBeatmapContainer(BeatmapSetType.Favourite, User, "Favourite Beatmaps", "None... yet."),
new PaginatedBeatmapContainer(BeatmapSetType.RankedAndApproved, User, "Ranked & Approved Beatmaps", "None... yet."),
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"),
};
}
}
@@ -51,6 +51,7 @@ namespace osu.Game.Overlays.Profile.Sections
{
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
Margin = new MarginPadding { Bottom = 10 }
},
ShowMoreButton = new OsuHoverContainer
{
@@ -1,7 +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 System.Collections.Generic;
using OpenTK;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
@@ -10,7 +9,6 @@ using osu.Game.Graphics;
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;
@@ -29,7 +27,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
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;
@@ -103,7 +101,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
Depth = -1,
},
},
modContainer = new ModContainer
modsContainer = new ScoreModsContainer
{
AutoSizeAxes = Axes.Y,
Anchor = Anchor.CentreRight,
@@ -165,11 +163,7 @@ 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) });
}
protected override bool OnClick(InputState state) => true;
@@ -188,16 +182,6 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
base.OnHoverLost(state);
}
private class ModContainer : 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);
}
}
private class MetadataContainer : OsuHoverContainer, IHasTooltip
{
public string TooltipText { get; set; }
@@ -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);
}
}
}
+2 -2
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;
@@ -132,7 +132,7 @@ namespace osu.Game.Overlays.Settings
}
}
private class RestoreDefaultValueButton<T> : Box, IHasTooltip
private class RestoreDefaultValueButton : Box, IHasTooltip
{
private Bindable<T> bindable;
internal Bindable<T> Bindable
+1
View File
@@ -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
-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);
}
}
+2 -2
View File
@@ -10,7 +10,7 @@ using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets.Mods
{
public abstract class ModAutoplay<T> : ModAutoplay, IApplicableMod<T>
public abstract class ModAutoplay<T> : ModAutoplay, IApplicableToRulesetContainer<T>
where T : HitObject
{
protected abstract Score CreateReplayScore(Beatmap<T> beatmap);
@@ -30,4 +30,4 @@ namespace osu.Game.Rulesets.Mods
public override double ScoreMultiplier => 0;
public override Type[] IncompatibleMods => new[] { typeof(ModRelax), typeof(ModSuddenDeath), typeof(ModNoFail) };
}
}
}
+1 -1
View File
@@ -47,7 +47,7 @@ namespace osu.Game.Rulesets
/// <returns></returns>
public abstract RulesetContainer CreateRulesetContainerWith(WorkingBeatmap beatmap, bool isForCurrentRuleset);
public abstract DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap);
public abstract DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null);
public virtual Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_question_circle };
+8 -6
View File
@@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.UI
private readonly SpriteIcon modIcon;
private readonly SpriteIcon background;
private const float background_size = 80;
private const float size = 80;
public FontAwesome Icon
{
@@ -38,23 +38,25 @@ namespace osu.Game.Rulesets.UI
TooltipText = mod.Name;
Size = new Vector2(size);
Children = new Drawable[]
{
background = new SpriteIcon
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Size = new Vector2(background_size),
Size = new Vector2(size),
Icon = FontAwesome.fa_osu_mod_bg,
Y = -6.5f,
Shadow = true,
},
modIcon = new SpriteIcon
{
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Colour = OsuColour.Gray(84),
Size = new Vector2(background_size - 35),
Y = 25,
Size = new Vector2(size - 35),
Icon = mod.Icon
},
};
+5 -1
View File
@@ -212,7 +212,11 @@ namespace osu.Game.Rulesets.UI
if (mods == null)
return;
foreach (var mod in mods.OfType<IApplicableMod<TObject>>())
foreach (var mod in mods.OfType<IApplicableToHitObject<TObject>>())
foreach (var obj in Beatmap.HitObjects)
mod.ApplyToHitObject(obj);
foreach (var mod in mods.OfType<IApplicableToRulesetContainer<TObject>>())
mod.ApplyToRulesetContainer(this);
}
@@ -114,7 +114,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline
}
/// <summary>
/// Zoom target as a relative position in the <see cref="Content"/> space.
/// Zoom target as a relative position in the <see cref="ScrollingTimelineContainer.Content"/> space.
/// </summary>
private float? relativeContentZoomTarget;
+69 -47
View File
@@ -17,6 +17,7 @@ using OpenTK.Graphics;
using OpenTK.Input;
using osu.Framework.Audio.Sample;
using osu.Framework.Audio;
using osu.Framework.Threading;
namespace osu.Game.Screens.Menu
{
@@ -55,6 +56,8 @@ namespace osu.Game.Screens.Menu
// osuLogo.SizeForFlow relies on loading to be complete.
buttonFlow.Position = new Vector2(WEDGE_WIDTH * 2 - (BUTTON_WIDTH + this.logo.SizeForFlow / 4), 0);
updateLogoState();
}
}
@@ -217,29 +220,17 @@ namespace osu.Game.Screens.Menu
if (state == MenuState.TopLevel)
buttonArea.FinishTransforms(true);
updateLogoState(lastState);
using (buttonArea.BeginDelayedSequence(lastState == MenuState.Initial ? 150 : 0, true))
{
switch (state)
{
case MenuState.Exit:
case MenuState.Initial:
trackingPosition = false;
buttonAreaBackground.ScaleTo(Vector2.One, 500, Easing.Out);
buttonArea.FadeOut(300);
logo?.Delay(150)
.Schedule(() =>
{
toolbar?.Hide();
logo.ClearTransforms(targetMember: nameof(Position));
logo.RelativePositionAxes = Axes.Both;
logo.MoveTo(new Vector2(0.5f), 800, Easing.OutExpo);
logo.ScaleTo(1, 800, Easing.OutExpo);
});
foreach (Button b in buttonsTopLevel)
b.State = ButtonState.Contracted;
@@ -252,33 +243,6 @@ namespace osu.Game.Screens.Menu
case MenuState.TopLevel:
buttonAreaBackground.ScaleTo(Vector2.One, 200, Easing.Out);
logo.ClearTransforms(targetMember: nameof(Position));
logo.RelativePositionAxes = Axes.None;
trackingPosition = true;
switch (lastState)
{
case MenuState.Initial:
logo.ScaleTo(0.5f, 200, Easing.In);
trackingPosition = false;
logo
.MoveTo(iconTrackingPosition, lastState == MenuState.EnteringMode ? 0 : 200, Easing.In)
.OnComplete(o =>
{
trackingPosition = true;
o.Impact();
toolbar?.Show();
});
break;
default:
logo.ScaleTo(0.5f, 200, Easing.OutQuint);
break;
}
buttonArea.FadeIn(300);
foreach (Button b in buttonsTopLevel)
@@ -297,8 +261,6 @@ namespace osu.Game.Screens.Menu
case MenuState.EnteringMode:
buttonAreaBackground.ScaleTo(new Vector2(2, 0), 300, Easing.InSine);
trackingPosition = true;
buttonsTopLevel.ForEach(b => b.ContractStyle = 1);
buttonsPlay.ForEach(b => b.ContractStyle = 1);
backButton.ContractStyle = 1;
@@ -320,9 +282,69 @@ namespace osu.Game.Screens.Menu
}
}
private Vector2 iconTrackingPosition => logo.Parent.ToLocalSpace(iconFacade.ScreenSpaceDrawQuad.Centre);
private ScheduledDelegate logoDelayedAction;
private bool trackingPosition;
private void updateLogoState(MenuState lastState = MenuState.Initial)
{
if (logo == null) return;
logoDelayedAction?.Cancel();
switch (state)
{
case MenuState.Exit:
case MenuState.Initial:
logoTracking = false;
logoDelayedAction = Scheduler.AddDelayed(() =>
{
toolbar?.Hide();
logo.ClearTransforms(targetMember: nameof(Position));
logo.RelativePositionAxes = Axes.Both;
logo.MoveTo(new Vector2(0.5f), 800, Easing.OutExpo);
logo.ScaleTo(1, 800, Easing.OutExpo);
}, 150);
break;
case MenuState.TopLevel:
case MenuState.Play:
logo.ClearTransforms(targetMember: nameof(Position));
logo.RelativePositionAxes = Axes.None;
switch (lastState)
{
case MenuState.TopLevel: // coming from toplevel to play
case MenuState.Initial:
logoTracking = false;
logo.ScaleTo(0.5f, 200, Easing.In);
logo.MoveTo(logoTrackingPosition, lastState == MenuState.EnteringMode ? 0 : 200, Easing.In);
logoDelayedAction = Scheduler.AddDelayed(() =>
{
logoTracking = true;
logo.Impact();
toolbar?.Show();
}, 200);
break;
default:
logoTracking = true;
logo.ScaleTo(0.5f, 200, Easing.OutQuint);
break;
}
break;
case MenuState.EnteringMode:
logoTracking = true;
break;
}
}
private Vector2 logoTrackingPosition => logo.Parent.ToLocalSpace(iconFacade.ScreenSpaceDrawQuad.Centre);
private bool logoTracking;
protected override void Update()
{
@@ -333,8 +355,8 @@ namespace osu.Game.Screens.Menu
if (logo != null)
{
if (trackingPosition)
logo.Position = iconTrackingPosition;
if (logoTracking)
logo.Position = logoTrackingPosition;
iconFacade.Width = logo.SizeForFlow * 0.5f;
}
-4
View File
@@ -12,7 +12,6 @@ using osu.Framework.MathUtils;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.IO;
using osu.Game.Configuration;
using osu.Game.Graphics.Containers;
using osu.Game.Screens.Backgrounds;
using OpenTK;
using OpenTK.Graphics;
@@ -21,8 +20,6 @@ namespace osu.Game.Screens.Menu
{
public class Intro : OsuScreen
{
private readonly IntroSequence introSequence;
private const string menu_music_beatmap_hash = "3c8b1fcc9434dbb29e2fb613d3b9eada9d7bb6c125ceb32396c3b53437280c83";
/// <summary>
@@ -43,7 +40,6 @@ namespace osu.Game.Screens.Menu
private Bindable<bool> menuVoice;
private Bindable<bool> menuMusic;
private Track track;
private readonly ParallaxContainer parallax;
[BackgroundDependencyLoader]
private void load(AudioManager audio, OsuConfigManager config, BeatmapManager beatmaps, Framework.Game game)
+1 -5
View File
@@ -55,11 +55,7 @@ namespace osu.Game.Screens.Play.HUD
iconsContainer.Clear();
foreach (Mod mod in mods)
{
iconsContainer.Add(new ModIcon(mod)
{
AutoSizeAxes = Axes.Both,
Scale = new Vector2(0.6f),
});
iconsContainer.Add(new ModIcon(mod) { Scale = new Vector2(0.6f) });
}
if (IsLoaded)
+2
View File
@@ -231,6 +231,8 @@ namespace osu.Game.Screens.Play
private void applyRateFromMods()
{
if (adjustableSourceClock == null) return;
adjustableSourceClock.Rate = 1;
foreach (var mod in Beatmap.Value.Mods.Value.OfType<IApplicableToClock>())
mod.ApplyToClock(adjustableSourceClock);
@@ -30,9 +30,9 @@ namespace osu.Game.Screens.Select.Details
metrics = value;
var ratings = Metrics.Ratings.ToList();
negativeRatings.Text = ratings.GetRange(0, ratings.Count / 2).Sum().ToString();
positiveRatings.Text = ratings.GetRange(ratings.Count / 2, ratings.Count / 2).Sum().ToString();
ratingsBar.Length = (float)ratings.GetRange(0, ratings.Count / 2).Sum() / ratings.Sum();
negativeRatings.Text = ratings.GetRange(0, ratings.Count / 2 + 1).Sum().ToString();
positiveRatings.Text = ratings.GetRange(ratings.Count / 2 + 1, ratings.Count / 2).Sum().ToString();
ratingsBar.Length = (float)ratings.GetRange(0, ratings.Count / 2 + 1).Sum() / ratings.Sum();
graph.Values = Metrics.Ratings.Select(r => (float)r);
}
}
@@ -14,15 +14,10 @@ namespace osu.Game.Screens.Select.Leaderboards
public class DrawableRank : Container
{
private readonly Sprite rankSprite;
private TextureStore textures;
public ScoreRank Rank { get; private set; }
[BackgroundDependencyLoader]
private void load(TextureStore textures)
{
rankSprite.Texture = textures.Get($@"Grades/{Rank.GetDescription()}");
}
public DrawableRank(ScoreRank rank)
{
Rank = rank;
@@ -38,5 +33,20 @@ namespace osu.Game.Screens.Select.Leaderboards
},
};
}
[BackgroundDependencyLoader]
private void load(TextureStore textures)
{
this.textures = textures;
updateTexture();
}
private void updateTexture() => rankSprite.Texture = textures.Get($@"Grades/{Rank.GetDescription()}");
public void UpdateRank(ScoreRank newRank)
{
Rank = newRank;
updateTexture();
}
}
}
@@ -17,19 +17,21 @@ using osu.Game.Graphics.UserInterface;
using osu.Game.Rulesets.Scoring;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using System.Linq;
namespace osu.Game.Screens.Select.Leaderboards
{
public class Leaderboard : Container
{
private readonly ScrollContainer scrollContainer;
private readonly FillFlowContainer<LeaderboardScore> scrollFlow;
private FillFlowContainer<LeaderboardScore> scrollFlow;
public Action<Score> ScoreSelected;
private readonly LoadingAnimation loading;
private IEnumerable<Score> scores;
public IEnumerable<Score> Scores
{
get { return scores; }
@@ -41,33 +43,43 @@ namespace osu.Game.Screens.Select.Leaderboards
int i = 150;
if (scores == null)
{
foreach (var c in scrollFlow.Children)
c.FadeOut(i += 10);
if (scrollFlow != null)
{
foreach (var c in scrollFlow.Children)
c.FadeOut(i += 10);
foreach (var c in scrollFlow.Children)
c.LifetimeEnd = Time.Current + i;
foreach (var c in scrollFlow.Children)
c.LifetimeEnd = Time.Current + i;
}
return;
}
scrollFlow.Clear();
i = 0;
foreach (var s in scores)
// schedule because we may not be loaded yet (LoadComponentAsync complains).
Schedule(() =>
{
var ls = new LeaderboardScore(s, 1 + i)
LoadComponentAsync(new FillFlowContainer<LeaderboardScore>
{
AlwaysPresent = true,
Action = () => ScoreSelected?.Invoke(s),
State = Visibility.Hidden,
};
scrollFlow.Add(ls);
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Spacing = new Vector2(0f, 5f),
Padding = new MarginPadding { Top = 10, Bottom = 5 },
ChildrenEnumerable = scores.Select((s, index) => new LeaderboardScore(s, index + 1) { Action = () => ScoreSelected?.Invoke(s) })
}, f =>
{
scrollFlow?.Expire();
scrollContainer.Add(scrollFlow = f);
using (BeginDelayedSequence(i++ * 50, true))
ls.Show();
}
i = 0;
foreach (var s in f.Children)
{
using (s.BeginDelayedSequence(i++ * 50, true))
s.Show();
}
scrollContainer.ScrollTo(0f, false);
scrollContainer.ScrollTo(0f, false);
});
});
}
}
@@ -79,16 +91,6 @@ namespace osu.Game.Screens.Select.Leaderboards
{
RelativeSizeAxes = Axes.Both,
ScrollbarVisible = false,
Children = new Drawable[]
{
scrollFlow = new FillFlowContainer<LeaderboardScore>
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Spacing = new Vector2(0f, 5f),
Padding = new MarginPadding { Top = 10, Bottom = 5 },
},
},
},
loading = new LoadingAnimation()
};
@@ -152,6 +154,8 @@ namespace osu.Game.Screens.Select.Leaderboards
if (!scrollContainer.IsScrolledToEnd())
fadeStart -= LeaderboardScore.HEIGHT;
if (scrollFlow == null) return;
foreach (var c in scrollFlow.Children)
{
var topY = c.ToSpaceOfOtherDrawable(Vector2.Zero, scrollFlow).Y;
@@ -2,9 +2,10 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Linq;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@@ -13,14 +14,13 @@ using osu.Framework.Input;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
using osu.Game.Users;
namespace osu.Game.Screens.Select.Leaderboards
{
public class LeaderboardScore : OsuClickableContainer, IStateful<Visibility>
public class LeaderboardScore : OsuClickableContainer
{
public static readonly float HEIGHT = 60;
@@ -34,72 +34,16 @@ namespace osu.Game.Screens.Select.Leaderboards
private const float background_alpha = 0.25f;
private const float rank_width = 30;
private readonly Box background;
private readonly Container content;
private readonly Container avatar;
private readonly DrawableRank scoreRank;
private readonly OsuSpriteText nameLabel;
private readonly GlowingSpriteText scoreLabel;
private readonly ScoreComponentLabel maxCombo;
private readonly ScoreComponentLabel accuracy;
private readonly Container flagBadgeContainer;
private readonly FillFlowContainer<ModIcon> modsContainer;
private Visibility state;
public Visibility State
{
get { return state; }
set
{
if (state == value)
return;
state = value;
switch (state)
{
case Visibility.Hidden:
foreach (var d in new Drawable[] { avatar, nameLabel, scoreLabel, scoreRank, flagBadgeContainer, maxCombo, accuracy, modsContainer })
d.FadeOut();
Alpha = 0;
content.MoveToY(75);
avatar.MoveToX(75);
nameLabel.MoveToX(150);
break;
case Visibility.Visible:
this.FadeIn(200);
content.MoveToY(0, 800, Easing.OutQuint);
using (BeginDelayedSequence(100, true))
{
avatar.FadeIn(300, Easing.OutQuint);
nameLabel.FadeIn(350, Easing.OutQuint);
avatar.MoveToX(0, 300, Easing.OutQuint);
nameLabel.MoveToX(0, 350, Easing.OutQuint);
using (BeginDelayedSequence(250, true))
{
scoreLabel.FadeIn(200);
scoreRank.FadeIn(200);
using (BeginDelayedSequence(50, true))
{
var drawables = new Drawable[] { flagBadgeContainer, maxCombo, accuracy, modsContainer, };
for (int i = 0; i < drawables.Length; i++)
drawables[i].FadeIn(100 + i * 50);
}
}
}
break;
}
StateChanged?.Invoke(State);
}
}
private Box background;
private Container content;
private Container avatar;
private DrawableRank scoreRank;
private OsuSpriteText nameLabel;
private GlowingSpriteText scoreLabel;
private ScoreComponentLabel maxCombo;
private ScoreComponentLabel accuracy;
private Container flagBadgeContainer;
private FillFlowContainer<ModIcon> modsContainer;
public LeaderboardScore(Score score, int rank)
{
@@ -108,7 +52,11 @@ namespace osu.Game.Screens.Select.Leaderboards
RelativeSizeAxes = Axes.X;
Height = HEIGHT;
}
[BackgroundDependencyLoader]
private void load()
{
Children = new Drawable[]
{
new Container
@@ -255,27 +203,51 @@ namespace osu.Game.Screens.Select.Leaderboards
Origin = Anchor.BottomRight,
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
ChildrenEnumerable = Score.Mods.Select(mod => new ModIcon(mod) { Scale = new Vector2(0.375f) })
},
},
},
},
},
};
foreach (Mod mod in Score.Mods)
{
modsContainer.Add(new ModIcon(mod)
{
AutoSizeAxes = Axes.Both,
Scale = new Vector2(0.375f)
});
}
}
public void ToggleVisibility() => State = State == Visibility.Visible ? Visibility.Hidden : Visibility.Visible;
public override void Show()
{
foreach (var d in new Drawable[] { avatar, nameLabel, scoreLabel, scoreRank, flagBadgeContainer, maxCombo, accuracy, modsContainer })
d.FadeOut();
public override void Hide() => State = Visibility.Hidden;
public override void Show() => State = Visibility.Visible;
Alpha = 0;
content.MoveToY(75);
avatar.MoveToX(75);
nameLabel.MoveToX(150);
this.FadeIn(200);
content.MoveToY(0, 800, Easing.OutQuint);
using (BeginDelayedSequence(100, true))
{
avatar.FadeIn(300, Easing.OutQuint);
nameLabel.FadeIn(350, Easing.OutQuint);
avatar.MoveToX(0, 300, Easing.OutQuint);
nameLabel.MoveToX(0, 350, Easing.OutQuint);
using (BeginDelayedSequence(250, true))
{
scoreLabel.FadeIn(200);
scoreRank.FadeIn(200);
using (BeginDelayedSequence(50, true))
{
var drawables = new Drawable[] { flagBadgeContainer, maxCombo, accuracy, modsContainer, };
for (int i = 0; i < drawables.Length; i++)
drawables[i].FadeIn(100 + i * 50);
}
}
}
}
protected override bool OnHover(InputState state)
{
+7 -1
View File
@@ -282,12 +282,17 @@
<Compile Include="Migrations\OsuDbContextModelSnapshot.cs" />
<Compile Include="Online\API\Requests\GetBeatmapSetRequest.cs" />
<Compile Include="Online\API\Requests\GetBeatmapSetsResponse.cs" />
<Compile Include="Overlays\BeatmapSet\Scores\ClickableUsername.cs" />
<Compile Include="Overlays\BeatmapSet\Scores\DrawableScore.cs" />
<Compile Include="Overlays\BeatmapSet\Scores\DrawableTopScore.cs" />
<Compile Include="Overlays\BeatmapSet\Scores\ScoresContainer.cs" />
<Compile Include="Online\API\Requests\GetUserBeatmapsRequest.cs" />
<Compile Include="Overlays\Profile\Sections\Beatmaps\PaginatedBeatmapContainer.cs" />
<Compile Include="Overlays\Profile\Sections\PaginatedContainer.cs" />
<Compile Include="Overlays\Profile\Sections\Ranks\DrawablePerformanceScore.cs" />
<Compile Include="Overlays\Profile\Sections\Ranks\PaginatedScoreContainer.cs" />
<Compile Include="Overlays\Profile\Sections\Ranks\DrawableTotalScore.cs" />
<Compile Include="Overlays\Profile\Sections\Ranks\ScoreModsContainer.cs" />
<Compile Include="Overlays\Settings\SettingsButton.cs" />
<Compile Include="Screens\Edit\Screens\Compose\Timeline\BeatmapWaveformGraph.cs" />
<Compile Include="Beatmaps\Drawables\DifficultyColouredContainer.cs" />
@@ -544,9 +549,10 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Rulesets\Judgements\DrawableJudgement.cs" />
<Compile Include="Rulesets\Judgements\Judgement.cs" />
<Compile Include="Rulesets\Mods\IApplicableMod.cs" />
<Compile Include="Rulesets\Mods\IApplicableToClock.cs" />
<Compile Include="Rulesets\Mods\IApplicableToDifficulty.cs" />
<Compile Include="Rulesets\Mods\IApplicableToHitObject.cs" />
<Compile Include="Rulesets\Mods\IApplicableToRulesetContainer.cs" />
<Compile Include="Rulesets\Mods\Mod.cs" />
<Compile Include="Rulesets\Mods\ModAutoplay.cs" />
<Compile Include="Rulesets\Mods\ModCinema.cs" />