diff --git a/osu-framework b/osu-framework index e6394035d4..405537bd35 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit e6394035d443d4498b71e845e5763dd3faf98c7c +Subproject commit 405537bd351954878ddc1d2ba53e5d0563528446 diff --git a/osu.Desktop.VisualTests/Tests/TestCaseDrawings.cs b/osu.Desktop.VisualTests/Tests/TestCaseDrawings.cs index 7aa6e1aee1..00e41de254 100644 --- a/osu.Desktop.VisualTests/Tests/TestCaseDrawings.cs +++ b/osu.Desktop.VisualTests/Tests/TestCaseDrawings.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using osu.Framework.Screens.Testing; using osu.Game.Screens.Tournament; using osu.Game.Screens.Tournament.Teams; +using osu.Game.Users; namespace osu.Desktop.VisualTests.Tests { @@ -24,57 +25,57 @@ namespace osu.Desktop.VisualTests.Tests private class TestTeamList : ITeamList { - public IEnumerable Teams { get; } = new[] + public IEnumerable Teams { get; } = new[] { - new Team + new Country { FlagName = "GB", FullName = "United Kingdom", Acronym = "UK" }, - new Team + new Country { FlagName = "FR", FullName = "France", Acronym = "FRA" }, - new Team + new Country { FlagName = "CN", FullName = "China", Acronym = "CHN" }, - new Team + new Country { FlagName = "AU", FullName = "Australia", Acronym = "AUS" }, - new Team + new Country { FlagName = "JP", FullName = "Japan", Acronym = "JPN" }, - new Team + new Country { FlagName = "RO", FullName = "Romania", Acronym = "ROM" }, - new Team + new Country { FlagName = "IT", FullName = "Italy", Acronym = "PIZZA" }, - new Team + new Country { FlagName = "VE", FullName = "Venezuela", Acronym = "VNZ" }, - new Team + new Country { FlagName = "US", FullName = "United States of America", diff --git a/osu.Desktop.VisualTests/Tests/TestCaseLeaderboard.cs b/osu.Desktop.VisualTests/Tests/TestCaseLeaderboard.cs new file mode 100644 index 0000000000..cc30e3de95 --- /dev/null +++ b/osu.Desktop.VisualTests/Tests/TestCaseLeaderboard.cs @@ -0,0 +1,225 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using OpenTK; +using osu.Framework.Graphics; +using osu.Framework.Screens.Testing; +using osu.Game.Modes; +using osu.Game.Modes.Mods; +using osu.Game.Modes.Osu.Mods; +using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Users; + +namespace osu.Desktop.VisualTests.Tests +{ + internal class TestCaseLeaderboard : TestCase + { + public override string Description => @"From song select"; + + private Leaderboard leaderboard; + + private void newScores() + { + var scores = new[] + { + new Score + { + Rank = ScoreRank.XH, + Accuracy = 100, + MaxCombo = 244, + TotalScore = 1707827, + Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, + User = new User + { + Id = 6602580, + Username = @"waaiiru", + Country = new Country + { + FullName = @"Spain", + FlagName = @"ES", + }, + }, + }, + new Score + { + Rank = ScoreRank.X, + Accuracy = 100, + MaxCombo = 244, + TotalScore = 1707827, + Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, + User = new User + { + Id = 4608074, + Username = @"Skycries", + Country = new Country + { + FullName = @"Brazil", + FlagName = @"BR", + }, + }, + }, + new Score + { + Rank = ScoreRank.SH, + Accuracy = 100, + MaxCombo = 244, + TotalScore = 1707827, + Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, + User = new User + { + Id = 1014222, + Username = @"eLy", + Country = new Country + { + FullName = @"Japan", + FlagName = @"JP", + }, + }, + }, + new Score + { + Rank = ScoreRank.S, + Accuracy = 100, + MaxCombo = 244, + TotalScore = 1707827, + Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, + User = new User + { + Id = 1541390, + Username = @"Toukai", + Country = new Country + { + FullName = @"Canada", + FlagName = @"CA", + }, + }, + }, + new Score + { + Rank = ScoreRank.A, + Accuracy = 100, + MaxCombo = 244, + TotalScore = 1707827, + Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, + User = new User + { + Id = 2243452, + Username = @"Satoruu", + Country = new Country + { + FullName = @"Venezuela", + FlagName = @"VE", + }, + }, + }, + new Score + { + Rank = ScoreRank.B, + Accuracy = 98.26, + MaxCombo = 244, + TotalScore = 1707827, + Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, + User = new User + { + Id = 2705430, + Username = @"Mooha", + Country = new Country + { + FullName = @"France", + FlagName = @"FR", + }, + }, + }, + new Score + { + Rank = ScoreRank.C, + Accuracy = 96.54, + MaxCombo = 244, + TotalScore = 1707827, + Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, + User = new User + { + Id = 7151382, + Username = @"Mayuri Hana", + Country = new Country + { + FullName = @"Thailand", + FlagName = @"TH", + }, + }, + }, + new Score + { + Rank = ScoreRank.F, + Accuracy = 60.25, + MaxCombo = 244, + TotalScore = 1707827, + Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, + User = new User + { + Id = 2051389, + Username = @"FunOrange", + Country = new Country + { + FullName = @"Canada", + FlagName = @"CA", + }, + }, + }, + new Score + { + Rank = ScoreRank.F, + Accuracy = 51.40, + MaxCombo = 244, + TotalScore = 1707827, + Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, + User = new User + { + Id = 6169483, + Username = @"-Hebel-", + Country = new Country + { + FullName = @"Mexico", + FlagName = @"MX", + }, + }, + }, + new Score + { + Rank = ScoreRank.F, + Accuracy = 42.22, + MaxCombo = 244, + TotalScore = 1707827, + Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, + User = new User + { + Id = 6702666, + Username = @"prhtnsm", + Country = new Country + { + FullName = @"Germany", + FlagName = @"DE", + }, + }, + }, + }; + + leaderboard.Scores = scores; + } + + public override void Reset() + { + base.Reset(); + + Add(leaderboard = new Leaderboard + { + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Size = new Vector2(550f, 450f), + }); + + AddButton(@"New Scores", newScores); + newScores(); + } + } +} diff --git a/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj b/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj index 68aed38b34..6eb9e5e648 100644 --- a/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj +++ b/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj @@ -204,6 +204,7 @@ + diff --git a/osu.Desktop/Overlays/VersionManager.cs b/osu.Desktop/Overlays/VersionManager.cs index b93636331a..70925f6cf4 100644 --- a/osu.Desktop/Overlays/VersionManager.cs +++ b/osu.Desktop/Overlays/VersionManager.cs @@ -215,6 +215,7 @@ namespace osu.Desktop.Overlays Origin = Anchor.Centre, Icon = FontAwesome.fa_upload, Colour = Color4.White, + TextSize = 20 } }); } diff --git a/osu.Game.Modes.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Modes.Osu/Objects/Drawables/DrawableSlider.cs index a2a52c7d94..e9db97a67b 100644 --- a/osu.Game.Modes.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Modes.Osu/Objects/Drawables/DrawableSlider.cs @@ -158,6 +158,8 @@ namespace osu.Game.Modes.Osu.Objects.Drawables protected override void UpdateState(ArmedState state) { + if (!IsLoaded) return; + base.UpdateState(state); ball.FadeIn(); diff --git a/osu.Game.Modes.Taiko/Judgements/TaikoHitResult.cs b/osu.Game.Modes.Taiko/Judgements/TaikoHitResult.cs new file mode 100644 index 0000000000..d425616b66 --- /dev/null +++ b/osu.Game.Modes.Taiko/Judgements/TaikoHitResult.cs @@ -0,0 +1,11 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +namespace osu.Game.Modes.Taiko.Judgements +{ + public enum TaikoHitResult + { + Good, + Great + } +} diff --git a/osu.Game.Modes.Taiko/Judgements/TaikoJudgementInfo.cs b/osu.Game.Modes.Taiko/Judgements/TaikoJudgementInfo.cs index 38b9d784dd..d9e81d4d77 100644 --- a/osu.Game.Modes.Taiko/Judgements/TaikoJudgementInfo.cs +++ b/osu.Game.Modes.Taiko/Judgements/TaikoJudgementInfo.cs @@ -7,5 +7,77 @@ namespace osu.Game.Modes.Taiko.Judgements { public class TaikoJudgementInfo : JudgementInfo { + /// + /// The maximum score value. + /// + public const TaikoHitResult MAX_HIT_RESULT = TaikoHitResult.Great; + + /// + /// The score value. + /// + public TaikoHitResult TaikoResult; + + /// + /// The score value for the combo portion of the score. + /// + public int ScoreValue => NumericResultForScore(TaikoResult); + + /// + /// The score value for the accuracy portion of the score. + /// + public int AccuracyScoreValue => NumericResultForAccuracy(TaikoResult); + + /// + /// The maximum score value for the combo portion of the score. + /// + public int MaxScoreValue => NumericResultForScore(MAX_HIT_RESULT); + + /// + /// The maximum score value for the accuracy portion of the score. + /// + public int MaxAccuracyScoreValue => NumericResultForAccuracy(MAX_HIT_RESULT); + + /// + /// Whether this Judgement has a secondary hit in the case of finishers. + /// + public bool SecondHit; + + /// + /// Computes the numeric score value for the combo portion of the score. + /// For the accuracy portion of the score (including accuracy percentage), see . + /// + /// The result to compute the score value for. + /// The numeric score value. + protected virtual int NumericResultForScore(TaikoHitResult result) + { + switch (result) + { + default: + return 0; + case TaikoHitResult.Good: + return 100; + case TaikoHitResult.Great: + return 300; + } + } + + /// + /// Computes the numeric score value for the accuracy portion of the score. + /// For the combo portion of the score, see . + /// + /// The result to compute the score value for. + /// The numeric score value. + protected virtual int NumericResultForAccuracy(TaikoHitResult result) + { + switch (result) + { + default: + return 0; + case TaikoHitResult.Good: + return 150; + case TaikoHitResult.Great: + return 300; + } + } } } diff --git a/osu.Game.Modes.Taiko/osu.Game.Modes.Taiko.csproj b/osu.Game.Modes.Taiko/osu.Game.Modes.Taiko.csproj index 7ea6dfeadb..65ee442d33 100644 --- a/osu.Game.Modes.Taiko/osu.Game.Modes.Taiko.csproj +++ b/osu.Game.Modes.Taiko/osu.Game.Modes.Taiko.csproj @@ -50,6 +50,7 @@ + diff --git a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs index af90e35da7..20b977499e 100644 --- a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs @@ -207,7 +207,8 @@ namespace osu.Game.Beatmaps.Formats VelocityAdjustment = beatLength < 0 ? -beatLength / 100.0 : 1, TimingChange = split.Length <= 6 || split[6][0] == '1', KiaiMode = (effectFlags & 1) > 0, - OmitFirstBarLine = (effectFlags & 8) > 0 + OmitFirstBarLine = (effectFlags & 8) > 0, + TimeSignature = (TimeSignatures)int.Parse(split[2]) }; } diff --git a/osu.Game/Beatmaps/Timing/ControlPoint.cs b/osu.Game/Beatmaps/Timing/ControlPoint.cs index e323412f81..40320a88d7 100644 --- a/osu.Game/Beatmaps/Timing/ControlPoint.cs +++ b/osu.Game/Beatmaps/Timing/ControlPoint.cs @@ -11,18 +11,12 @@ namespace osu.Game.Beatmaps.Timing TimingChange = true, }; + public TimeSignatures TimeSignature; public double Time; public double BeatLength; public double VelocityAdjustment; public bool TimingChange; public bool KiaiMode; public bool OmitFirstBarLine; - - } - - internal enum TimeSignatures - { - SimpleQuadruple = 4, - SimpleTriple = 3 } } diff --git a/osu.Game/Beatmaps/Timing/TimeSignatures.cs b/osu.Game/Beatmaps/Timing/TimeSignatures.cs new file mode 100644 index 0000000000..94b36591f5 --- /dev/null +++ b/osu.Game/Beatmaps/Timing/TimeSignatures.cs @@ -0,0 +1,11 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +namespace osu.Game.Beatmaps.Timing +{ + public enum TimeSignatures + { + SimpleQuadruple = 4, + SimpleTriple = 3 + } +} \ No newline at end of file diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 70bfbb5992..1442a26a06 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -23,7 +23,8 @@ namespace osu.Game.Configuration Set(OsuConfig.SavePassword, false); Set(OsuConfig.SaveUsername, true); - Set(OsuConfig.CursorSize, 1.0, 0.5f, 2); + Set(OsuConfig.MenuCursorSize, 1.0, 0.5f, 2); + Set(OsuConfig.GameplayCursorSize, 1.0, 0.5f, 2); Set(OsuConfig.DimLevel, 30, 0, 100); Set(OsuConfig.MouseDisableButtons, false); @@ -223,7 +224,8 @@ namespace osu.Game.Configuration ComboFireHeight, ConfirmExit, AutoSendNowPlaying, - CursorSize, + MenuCursorSize, + GameplayCursorSize, AutomaticCursorSizing, DimLevel, Display, diff --git a/osu.Game/Graphics/Cursor/GameplayCursor.cs b/osu.Game/Graphics/Cursor/GameplayCursor.cs index a544a8e1bb..42d7e83750 100644 --- a/osu.Game/Graphics/Cursor/GameplayCursor.cs +++ b/osu.Game/Graphics/Cursor/GameplayCursor.cs @@ -54,7 +54,7 @@ namespace osu.Game.Graphics.Cursor [BackgroundDependencyLoader] private void load(OsuConfigManager config) { - cursorScale = config.GetBindable(OsuConfig.CursorSize); + cursorScale = config.GetBindable(OsuConfig.GameplayCursorSize); Children = new Drawable[] { diff --git a/osu.Game/Graphics/Cursor/MenuCursor.cs b/osu.Game/Graphics/Cursor/MenuCursor.cs index 1a21875cae..0f90a5aa0e 100644 --- a/osu.Game/Graphics/Cursor/MenuCursor.cs +++ b/osu.Game/Graphics/Cursor/MenuCursor.cs @@ -97,7 +97,7 @@ namespace osu.Game.Graphics.Cursor [BackgroundDependencyLoader] private void load(OsuConfigManager config, TextureStore textures, OsuColour colour) { - cursorScale = config.GetBindable(OsuConfig.CursorSize); + cursorScale = config.GetBindable(OsuConfig.MenuCursorSize); Children = new Drawable[] { diff --git a/osu.Game/Graphics/TextAwesome.cs b/osu.Game/Graphics/TextAwesome.cs index 45f9ddeec9..1bae165e45 100644 --- a/osu.Game/Graphics/TextAwesome.cs +++ b/osu.Game/Graphics/TextAwesome.cs @@ -1,11 +1,11 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics.Sprites; namespace osu.Game.Graphics { - public class TextAwesome : SpriteText + public class TextAwesome : OsuSpriteText { //public override FontFace FontFace => (int)Icon < 0xf000 ? FontFace.OsuFont : FontFace.FontAwesome; diff --git a/osu.Game/Graphics/UserInterface/OsuDropDownHeader.cs b/osu.Game/Graphics/UserInterface/OsuDropDownHeader.cs index 00dc510338..559ffca283 100644 --- a/osu.Game/Graphics/UserInterface/OsuDropDownHeader.cs +++ b/osu.Game/Graphics/UserInterface/OsuDropDownHeader.cs @@ -54,6 +54,7 @@ namespace osu.Game.Graphics.UserInterface Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, Margin = new MarginPadding { Right = 4 }, + TextSize = 20 } }; } diff --git a/osu.Game/Modes/Score.cs b/osu.Game/Modes/Score.cs index 4effe9affd..55bbed8e77 100644 --- a/osu.Game/Modes/Score.cs +++ b/osu.Game/Modes/Score.cs @@ -1,19 +1,63 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; +using Newtonsoft.Json; +using osu.Game.Users; using osu.Game.Database; +using osu.Game.Modes.Mods; namespace osu.Game.Modes { public class Score { + [JsonProperty(@"rank")] + public ScoreRank Rank { get; set; } + + [JsonProperty(@"score")] public double TotalScore { get; set; } public double Accuracy { get; set; } public double Health { get; set; } + + [JsonProperty(@"maxcombo")] public int MaxCombo { get; set; } public int Combo { get; set; } + public Mod[] Mods { get; set; } + public User User { get; set; } + + [JsonProperty(@"replay_data")] public Replay Replay; + public BeatmapInfo Beatmap; + + [JsonProperty(@"score_id")] + public long OnlineScoreID; + + [JsonProperty(@"username")] + public string Username; + + [JsonProperty(@"user_id")] + public long UserID; + + [JsonProperty(@"date")] + public DateTime Date; + + // [JsonProperty(@"count50")] 0, + //[JsonProperty(@"count100")] 0, + //[JsonProperty(@"count300")] 100, + //[JsonProperty(@"countmiss")] 0, + //[JsonProperty(@"countkatu")] 0, + //[JsonProperty(@"countgeki")] 31, + //[JsonProperty(@"perfect")] true, + //[JsonProperty(@"enabled_mods")] [ + // "DT", + // "FL", + // "HD", + // "HR" + //], + //[JsonProperty(@"rank")] "XH", + //[JsonProperty(@"pp")] 26.1816, + //[JsonProperty(@"replay")] true } } diff --git a/osu.Game/Modes/ScoreRank.cs b/osu.Game/Modes/ScoreRank.cs new file mode 100644 index 0000000000..433158f249 --- /dev/null +++ b/osu.Game/Modes/ScoreRank.cs @@ -0,0 +1,29 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.ComponentModel; + +namespace osu.Game.Modes +{ + public enum ScoreRank + { + [Description(@"F")] + F, + [Description(@"F")] + D, + [Description(@"C")] + C, + [Description(@"B")] + B, + [Description(@"A")] + A, + [Description(@"S")] + S, + [Description(@"SPlus")] + SH, + [Description(@"SS")] + X, + [Description(@"SSPlus")] + XH, + } +} diff --git a/osu.Game/Modes/UI/ModIcon.cs b/osu.Game/Modes/UI/ModIcon.cs index b1017a670e..65a570fea7 100644 --- a/osu.Game/Modes/UI/ModIcon.cs +++ b/osu.Game/Modes/UI/ModIcon.cs @@ -66,12 +66,14 @@ namespace osu.Game.Modes.UI Anchor = Anchor.Centre, Icon = FontAwesome.fa_osu_mod_bg, Shadow = true, + TextSize = 20 }, modIcon = new TextAwesome { Origin = Anchor.Centre, Anchor = Anchor.Centre, Colour = OsuColour.Gray(84), + TextSize = 20 }, }; diff --git a/osu.Game/Modes/UI/Playfield.cs b/osu.Game/Modes/UI/Playfield.cs index bff461f649..e5babecad9 100644 --- a/osu.Game/Modes/UI/Playfield.cs +++ b/osu.Game/Modes/UI/Playfield.cs @@ -7,6 +7,7 @@ using osu.Game.Modes.Objects; using osu.Game.Modes.Objects.Drawables; using OpenTK; using osu.Game.Modes.Judgements; +using osu.Framework.Allocation; namespace osu.Game.Modes.UI { @@ -45,10 +46,16 @@ namespace osu.Game.Modes.UI } }); - Add(HitObjects = new HitObjectContainer> + HitObjects = new HitObjectContainer> { RelativeSizeAxes = Axes.Both, - }); + }; + } + + [BackgroundDependencyLoader] + private void load() + { + Add(HitObjects); } /// diff --git a/osu.Game/Online/API/APIRequest.cs b/osu.Game/Online/API/APIRequest.cs index f871e5e20a..23268a9ca9 100644 --- a/osu.Game/Online/API/APIRequest.cs +++ b/osu.Game/Online/API/APIRequest.cs @@ -58,13 +58,20 @@ namespace osu.Game.Online.API public event APISuccessHandler Success; public event APIFailureHandler Failure; + private bool cancelled; + + private Action pendingFailure; + public void Perform(APIAccess api) { + this.api = api; + + if (checkAndProcessFailure()) + return; + if (startTime == null) startTime = DateTime.Now.TotalMilliseconds(); - this.api = api; - if (remainingTime <= 0) throw new TimeoutException(@"API request timeout hit"); @@ -72,18 +79,41 @@ namespace osu.Game.Online.API WebRequest.RetryCount = 0; WebRequest.Headers[@"Authorization"] = $@"Bearer {api.AccessToken}"; - WebRequest.BlockingPerform(); + if (checkAndProcessFailure()) + return; + + if (!WebRequest.Aborted) //could have been aborted by a Cancel() call + WebRequest.BlockingPerform(); + + if (checkAndProcessFailure()) + return; api.Scheduler.Add(delegate { Success?.Invoke(); }); } + public void Cancel() => Fail(new OperationCanceledException(@"Request cancelled")); + public void Fail(Exception e) { + cancelled = true; + WebRequest?.Abort(); - api.Scheduler.Add(delegate - { - Failure?.Invoke(e); - }); + + pendingFailure = () => Failure?.Invoke(e); + checkAndProcessFailure(); + } + + /// + /// Checked for cancellation or error. Also queues up the Failed event if we can. + /// + /// Whether we are in a failed or cancelled state. + private bool checkAndProcessFailure() + { + if (api == null || pendingFailure == null) return cancelled; + + api.Scheduler.Add(pendingFailure); + pendingFailure = null; + return true; } } diff --git a/osu.Game/Online/API/Requests/GetScoresRequest.cs b/osu.Game/Online/API/Requests/GetScoresRequest.cs new file mode 100644 index 0000000000..8c0fc4383a --- /dev/null +++ b/osu.Game/Online/API/Requests/GetScoresRequest.cs @@ -0,0 +1,40 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Collections.Generic; +using Newtonsoft.Json; +using osu.Framework.IO.Network; +using osu.Game.Database; +using osu.Game.Modes; + +namespace osu.Game.Online.API.Requests +{ + public class GetScoresRequest : APIRequest + { + private readonly BeatmapInfo beatmap; + + public GetScoresRequest(BeatmapInfo beatmap) + { + this.beatmap = beatmap; + } + + protected override WebRequest CreateWebRequest() + { + var req = base.CreateWebRequest(); + req.AddParameter(@"c", beatmap.Hash); + req.AddParameter(@"f", beatmap.Path); + return req; + } + + protected override string Target => @"beatmaps/scores"; + } + + public class GetScoresResponse + { + [JsonProperty(@"beatmap")] + public BeatmapInfo Beatmap; + + [JsonProperty(@"scores")] + public IEnumerable Scores; + } +} \ No newline at end of file diff --git a/osu.Game/Online/API/Requests/ListChannels.cs b/osu.Game/Online/API/Requests/ListChannelsRequest.cs similarity index 100% rename from osu.Game/Online/API/Requests/ListChannels.cs rename to osu.Game/Online/API/Requests/ListChannelsRequest.cs diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 9bd2ef9f75..5e7c47c9a9 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -279,6 +279,7 @@ namespace osu.Game //central game mode change logic. if (!currentScreen.ShowOverlays) { + options.State = Visibility.Hidden; Toolbar.State = Visibility.Hidden; musicController.State = Visibility.Hidden; chat.State = Visibility.Hidden; diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs index ea07d7806a..e003a0e9dd 100644 --- a/osu.Game/Overlays/Notifications/Notification.cs +++ b/osu.Game/Overlays/Notifications/Notification.cs @@ -169,6 +169,7 @@ namespace osu.Game.Overlays.Notifications Anchor = Anchor.Centre, Origin = Anchor.Centre, Icon = FontAwesome.fa_times_circle, + TextSize = 20 } }; } diff --git a/osu.Game/Overlays/Notifications/SimpleNotification.cs b/osu.Game/Overlays/Notifications/SimpleNotification.cs index b06994d61a..19034d6d1c 100644 --- a/osu.Game/Overlays/Notifications/SimpleNotification.cs +++ b/osu.Game/Overlays/Notifications/SimpleNotification.cs @@ -53,6 +53,7 @@ namespace osu.Game.Overlays.Notifications Anchor = Anchor.Centre, Origin = Anchor.Centre, Icon = icon, + TextSize = 20 } }); diff --git a/osu.Game/Overlays/Options/OptionsFooter.cs b/osu.Game/Overlays/Options/OptionsFooter.cs index 23622aef08..c42fe42428 100644 --- a/osu.Game/Overlays/Options/OptionsFooter.cs +++ b/osu.Game/Overlays/Options/OptionsFooter.cs @@ -32,6 +32,7 @@ namespace osu.Game.Overlays.Options { Icon = Ruleset.GetRuleset(m).Icon, Colour = Color4.Gray, + TextSize = 20 }); Children = new Drawable[] diff --git a/osu.Game/Overlays/Options/Sections/Graphics/LayoutOptions.cs b/osu.Game/Overlays/Options/Sections/Graphics/LayoutOptions.cs index a3dbb9c76f..0a2e8f91a4 100644 --- a/osu.Game/Overlays/Options/Sections/Graphics/LayoutOptions.cs +++ b/osu.Game/Overlays/Options/Sections/Graphics/LayoutOptions.cs @@ -5,6 +5,7 @@ using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Game.Graphics.UserInterface; +using System; namespace osu.Game.Overlays.Options.Sections.Graphics { @@ -12,9 +13,16 @@ namespace osu.Game.Overlays.Options.Sections.Graphics { protected override string Header => "Layout"; + private OptionSlider letterboxPositionX; + private OptionSlider letterboxPositionY; + + private Bindable letterboxing; + [BackgroundDependencyLoader] private void load(FrameworkConfigManager config) { + letterboxing = config.GetBindable(FrameworkConfig.Letterboxing); + Children = new Drawable[] { new OptionLabel { Text = "Resolution: TODO dropdown" }, @@ -26,19 +34,36 @@ namespace osu.Game.Overlays.Options.Sections.Graphics new OsuCheckbox { LabelText = "Letterboxing", - Bindable = config.GetBindable(FrameworkConfig.Letterboxing), + Bindable = letterboxing, }, - new OptionSlider + letterboxPositionX = new OptionSlider { LabelText = "Horizontal position", Bindable = (BindableInt)config.GetBindable(FrameworkConfig.LetterboxPositionX) }, - new OptionSlider + letterboxPositionY = new OptionSlider { LabelText = "Vertical position", Bindable = (BindableInt)config.GetBindable(FrameworkConfig.LetterboxPositionY) }, }; + + letterboxing.ValueChanged += visibilityChanged; + letterboxing.TriggerChange(); + } + + private void visibilityChanged(object sender, EventArgs e) + { + if (letterboxing) + { + letterboxPositionX.Show(); + letterboxPositionY.Show(); + } + else + { + letterboxPositionX.Hide(); + letterboxPositionY.Hide(); + } } } } \ No newline at end of file diff --git a/osu.Game/Overlays/Options/Sections/SkinSection.cs b/osu.Game/Overlays/Options/Sections/SkinSection.cs index 56dd9ca318..0ee561c1ad 100644 --- a/osu.Game/Overlays/Options/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Options/Sections/SkinSection.cs @@ -61,8 +61,13 @@ namespace osu.Game.Overlays.Options.Sections }, new OptionSlider { - LabelText = "Cursor size", - Bindable = (BindableDouble)config.GetBindable(OsuConfig.CursorSize) + LabelText = "Menu cursor size", + Bindable = (BindableDouble)config.GetBindable(OsuConfig.MenuCursorSize) + }, + new OptionSlider + { + LabelText = "Gameplay cursor size", + Bindable = (BindableDouble)config.GetBindable(OsuConfig.GameplayCursorSize) }, new OsuCheckbox { @@ -72,4 +77,4 @@ namespace osu.Game.Overlays.Options.Sections }; } } -} \ No newline at end of file +} diff --git a/osu.Game/Overlays/Options/SidebarButton.cs b/osu.Game/Overlays/Options/SidebarButton.cs index 83c2227763..729a9be326 100644 --- a/osu.Game/Overlays/Options/SidebarButton.cs +++ b/osu.Game/Overlays/Options/SidebarButton.cs @@ -87,6 +87,7 @@ namespace osu.Game.Overlays.Options { Anchor = Anchor.Centre, Origin = Anchor.Centre, + TextSize = 20 }, } }, diff --git a/osu.Game/Overlays/Toolbar/ToolbarButton.cs b/osu.Game/Overlays/Toolbar/ToolbarButton.cs index 17cef48f38..be4a23722f 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarButton.cs @@ -98,6 +98,7 @@ namespace osu.Game.Overlays.Toolbar { Anchor = Anchor.Centre, Origin = Anchor.Centre, + TextSize = 20 }, DrawableText = new OsuSpriteText { diff --git a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs index 89af56c18c..52c9ab5aa4 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs @@ -1,14 +1,12 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System.Diagnostics; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Graphics.Textures; using osu.Game.Online.API; +using osu.Game.Users; using OpenTK; using OpenTK.Graphics; @@ -26,7 +24,20 @@ namespace osu.Game.Overlays.Toolbar Add(new OpaqueBackground { Depth = 1 }); - Flow.Add(avatar = new Avatar()); + Flow.Add(avatar = new Avatar + { + Masking = true, + Size = new Vector2(32), + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + CornerRadius = 4, + EdgeEffect = new EdgeEffect + { + Type = EdgeEffectType.Shadow, + Radius = 4, + Colour = Color4.Black.Opacity(0.1f), + } + }); } [BackgroundDependencyLoader] @@ -49,86 +60,5 @@ namespace osu.Game.Overlays.Toolbar break; } } - - public class Avatar : Container - { - public Drawable Sprite; - - private int userId; - private OsuGame game; - private Texture guestTexture; - - public Avatar() - { - Size = new Vector2(32); - Anchor = Anchor.CentreLeft; - Origin = Anchor.CentreLeft; - - CornerRadius = Size.X / 8; - - EdgeEffect = new EdgeEffect - { - Type = EdgeEffectType.Shadow, - Radius = 4, - Colour = Color4.Black.Opacity(0.1f), - }; - - Masking = true; - } - - [BackgroundDependencyLoader] - private void load(OsuGame game, TextureStore textures) - { - this.game = game; - - guestTexture = textures.Get(@"Online/avatar-guest"); - } - - public int UserId - { - get { return userId; } - set - { - if (userId == value) - return; - - userId = value; - - var newSprite = userId > 1 ? new OnlineSprite($@"https://a.ppy.sh/{userId}") : new Sprite { Texture = guestTexture }; - - newSprite.FillMode = FillMode.Fit; - - newSprite.LoadAsync(game, s => - { - Sprite?.FadeOut(); - Sprite?.Expire(); - Sprite = s; - - Add(s); - - //todo: fix this... clock dependencies are a pain - if (s.Clock != null) - s.FadeInFromZero(200); - }); - } - } - - public class OnlineSprite : Sprite - { - private readonly string url; - - public OnlineSprite(string url) - { - Debug.Assert(url != null); - this.url = url; - } - - [BackgroundDependencyLoader] - private void load(TextureStore textures) - { - Texture = textures.Get(url); - } - } - } } } diff --git a/osu.Game/Screens/OsuGameScreen.cs b/osu.Game/Screens/OsuGameScreen.cs index 736f9f96ae..a5c6cec09e 100644 --- a/osu.Game/Screens/OsuGameScreen.cs +++ b/osu.Game/Screens/OsuGameScreen.cs @@ -71,6 +71,8 @@ namespace osu.Game.Screens BackgroundScreen bg = CreateBackground(); + OnBeatmapChanged(Beatmap); + if (lastOsu?.Background != null) { if (bg == null || lastOsu.Background.Equals(bg)) diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index 5285d26264..d0805c19bd 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -237,14 +237,16 @@ namespace osu.Game.Screens.Select Icon = FontAwesome.fa_square, Origin = Anchor.Centre, Colour = new Color4(68, 17, 136, 255), - Rotation = 45 + Rotation = 45, + TextSize = 20 }, new TextAwesome { Icon = statistic.Icon, Origin = Anchor.Centre, Colour = new Color4(255, 221, 85, 255), - Scale = new Vector2(0.8f) + Scale = new Vector2(0.8f), + TextSize = 20 }, new OsuSpriteText { diff --git a/osu.Game/Screens/Select/Leaderboards/DrawableRank.cs b/osu.Game/Screens/Select/Leaderboards/DrawableRank.cs new file mode 100644 index 0000000000..5bfe3d6be0 --- /dev/null +++ b/osu.Game/Screens/Select/Leaderboards/DrawableRank.cs @@ -0,0 +1,39 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; +using osu.Game.Modes; +using osu.Framework.Extensions; + +namespace osu.Game.Screens.Select.Leaderboards +{ + public class DrawableRank : Container + { + private Sprite sprite; + + public ScoreRank Rank { get; private set; } + + [BackgroundDependencyLoader] + private void load(TextureStore textures) + { + sprite.Texture = textures.Get($@"Badges/ScoreRanks/{Rank.GetDescription()}"); + } + + public DrawableRank(ScoreRank rank) + { + Rank = rank; + + Children = new Drawable[] + { + sprite = new Sprite + { + RelativeSizeAxes = Axes.Both, + }, + }; + } + } +} diff --git a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs new file mode 100644 index 0000000000..20e6db6241 --- /dev/null +++ b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs @@ -0,0 +1,111 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Collections.Generic; +using OpenTK; +using OpenTK.Graphics; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Primitives; +using osu.Game.Modes; +using System; + +namespace osu.Game.Screens.Select.Leaderboards +{ + public class Leaderboard : Container + { + private ScrollContainer scrollContainer; + private FillFlowContainer scrollFlow; + + private IEnumerable scores; + public IEnumerable Scores + { + get { return scores; } + set + { + scores = value; + + int i = 150; + if (scores == null) + { + foreach (var c in scrollFlow.Children) + c.FadeOut(i += 10); + + foreach (var c in scrollFlow.Children) + c.LifetimeEnd = Time.Current + i; + + return; + } + + scrollFlow.Clear(); + + i = 0; + foreach (var s in scores) + { + var ls = new LeaderboardScore(s, 1 + i) + { + AlwaysPresent = true, + State = Visibility.Hidden, + }; + scrollFlow.Add(ls); + + ls.Delay(i++ * 50, true); + ls.Show(); + } + + scrollContainer.ScrollTo(0f, false); + } + } + + public Leaderboard() + { + Children = new Drawable[] + { + scrollContainer = new ScrollContainer + { + RelativeSizeAxes = Axes.Both, + ScrollDraggerVisible = false, + Children = new Drawable[] + { + scrollFlow = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Spacing = new Vector2(0f, 5f), + Padding = new MarginPadding(5), + }, + }, + }, + }; + } + + protected override void Update() + { + base.Update(); + + var fadeStart = scrollContainer.Current + scrollContainer.DrawHeight; + + if (!scrollContainer.IsScrolledToEnd()) + fadeStart -= LeaderboardScore.HEIGHT; + + foreach (var c in scrollFlow.Children) + { + var topY = c.ToSpaceOfOtherDrawable(Vector2.Zero, scrollFlow).Y; + var bottomY = topY + LeaderboardScore.HEIGHT; + + if (bottomY < fadeStart) + c.Colour = Color4.White; + else if (topY > fadeStart + LeaderboardScore.HEIGHT) + c.Colour = Color4.Transparent; + else + { + c.ColourInfo = ColourInfo.GradientVertical( + Color4.White.Opacity(Math.Min(1 - (topY - fadeStart) / LeaderboardScore.HEIGHT, 1)), + Color4.White.Opacity(Math.Min(1 - (bottomY - fadeStart) / LeaderboardScore.HEIGHT, 1))); + } + } + } + } +} diff --git a/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs b/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs new file mode 100644 index 0000000000..d1a48d7867 --- /dev/null +++ b/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs @@ -0,0 +1,386 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using OpenTK; +using OpenTK.Graphics; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Primitives; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Transforms; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Modes; +using osu.Framework.Extensions.Color4Extensions; +using osu.Game.Modes.Mods; +using osu.Game.Users; +using osu.Framework; + +namespace osu.Game.Screens.Select.Leaderboards +{ + public class LeaderboardScore : Container, IStateful + { + public static readonly float HEIGHT = 60; + + public readonly int RankPosition; + public readonly Score Score; + + private const float corner_radius = 5; + private const float edge_margin = 5; + private const float background_alpha = 0.25f; + private const float rank_width = 30; + + private Box background; + private Container content, avatar; + private DrawableRank scoreRank; + private OsuSpriteText nameLabel; + private GlowingSpriteText scoreLabel; + private ScoreComponentLabel maxCombo, accuracy; + private Container flagBadgeContainer; + private FillFlowContainer modsContainer; + + private Visibility state; + public Visibility State + { + get { return state; } + set + { + 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: + FadeIn(200); + content.MoveToY(0, 800, EasingTypes.OutQuint); + + Delay(100, true); + avatar.FadeIn(300, EasingTypes.OutQuint); + nameLabel.FadeIn(350, EasingTypes.OutQuint); + + avatar.MoveToX(0, 300, EasingTypes.OutQuint); + nameLabel.MoveToX(0, 350, EasingTypes.OutQuint); + + Delay(250, true); + scoreLabel.FadeIn(200); + scoreRank.FadeIn(200); + + Delay(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; + } + } + } + + public LeaderboardScore(Score score, int rank) + { + Score = score; + RankPosition = rank; + + RelativeSizeAxes = Axes.X; + Height = HEIGHT; + + Children = new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Y, + Width = rank_width, + Children = new[] + { + new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = @"Exo2.0-MediumItalic", + TextSize = 22, + Text = RankPosition.ToString(), + }, + }, + }, + content = new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Left = rank_width, }, + Children = new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + CornerRadius = corner_radius, + Masking = true, + Children = new[] + { + background = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + Alpha = background_alpha, + }, + }, + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding(edge_margin), + Children = new Drawable[] + { + avatar = new Avatar + { + Size = new Vector2(HEIGHT - edge_margin * 2, HEIGHT - edge_margin * 2), + CornerRadius = corner_radius, + Masking = true, + EdgeEffect = new EdgeEffect + { + Type = EdgeEffectType.Shadow, + Radius = 1, + Colour = Color4.Black.Opacity(0.2f), + }, + UserId = Score.User?.Id ?? Score.UserID, + }, + new Container + { + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + Position = new Vector2(HEIGHT - edge_margin, 0f), + Children = new Drawable[] + { + nameLabel = new OsuSpriteText + { + Text = Score.User?.Username ?? Score.Username, + Font = @"Exo2.0-BoldItalic", + TextSize = 23, + }, + new FillFlowContainer + { + Origin = Anchor.BottomLeft, + Anchor = Anchor.BottomLeft, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(10f, 0f), + Children = new Drawable[] + { + flagBadgeContainer = new Container + { + Size = new Vector2(87f, 20f), + Masking = true, + Children = new Drawable[] + { + new DrawableFlag(Score.User?.Country?.FlagName ?? "__") + { + Width = 30, + RelativeSizeAxes = Axes.Y, + }, + }, + }, + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(10f, 0f), + Margin = new MarginPadding { Left = edge_margin, }, + Children = new Drawable[] + { + maxCombo = new ScoreComponentLabel(FontAwesome.fa_link, Score.MaxCombo.ToString()), + accuracy = new ScoreComponentLabel(FontAwesome.fa_crosshairs, string.Format(Score.Accuracy % 1 == 0 ? @"{0:0}" : @"{0:0.00}", Score.Accuracy)), + }, + }, + }, + }, + }, + }, + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(5f, 0f), + Children = new Drawable[] + { + scoreLabel = new GlowingSpriteText(Score.TotalScore.ToString(@"N0"), @"Venera", 23, Color4.White, OsuColour.FromHex(@"83ccfa")), + new Container + { + Size = new Vector2(40f, 20f), + Children = new[] + { + scoreRank = new DrawableRank(Score.Rank) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(40f), + }, + }, + }, + }, + }, + modsContainer = new FillFlowContainer + { + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + }, + }, + }, + }, + }, + }; + + if (Score.Mods != null) + { + foreach (Mod mod in Score.Mods) + { + // TODO: Get actual mod colours + modsContainer.Add(new ScoreModIcon(mod.Icon, OsuColour.FromHex(@"ffcc22"))); + } + } + } + + public void ToggleVisibility() => State = State == Visibility.Visible ? Visibility.Hidden : Visibility.Visible; + + public override void Hide() => State = Visibility.Hidden; + public override void Show() => State = Visibility.Visible; + + protected override bool OnHover(Framework.Input.InputState state) + { + background.FadeTo(0.5f, 300, EasingTypes.OutQuint); + return base.OnHover(state); + } + + protected override void OnHoverLost(Framework.Input.InputState state) + { + background.FadeTo(background_alpha, 200, EasingTypes.OutQuint); + base.OnHoverLost(state); + } + + private class GlowingSpriteText : Container + { + public GlowingSpriteText(string text, string font, int textSize, Color4 textColour, Color4 glowColour) + { + AutoSizeAxes = Axes.Both; + + Children = new Drawable[] + { + new BufferedContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + BlurSigma = new Vector2(4), + CacheDrawnFrameBuffer = true, + RelativeSizeAxes = Axes.Both, + BlendingMode = BlendingMode.Additive, + Size = new Vector2(3f), + Children = new[] + { + new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = font, + TextSize = textSize, + FixedWidth = true, + Text = text, + Colour = glowColour, + Shadow = false, + }, + }, + }, + new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = font, + FixedWidth = true, + TextSize = textSize, + Text = text, + Colour = textColour, + Shadow = false, + }, + }; + } + } + + private class ScoreModIcon : Container + { + public ScoreModIcon(FontAwesome icon, Color4 colour) + { + AutoSizeAxes = Axes.Both; + + Children = new[] + { + new TextAwesome + { + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Icon = FontAwesome.fa_osu_mod_bg, + Colour = colour, + Shadow = true, + TextSize = 30, + UseFullGlyphHeight = false, + }, + new TextAwesome + { + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Icon = icon, + Colour = OsuColour.Gray(84), + TextSize = 18, + Position = new Vector2(0f, 2f), + UseFullGlyphHeight = false, + }, + }; + } + } + + private class ScoreComponentLabel : Container + { + public ScoreComponentLabel(FontAwesome icon, string value) + { + Anchor = Anchor.CentreLeft; + Origin = Anchor.CentreLeft; + Size = new Vector2(60f, 20f); + Padding = new MarginPadding { Top = 10f, }; + + Children = new Drawable[] + { + new TextAwesome + { + Origin = Anchor.Centre, + Icon = FontAwesome.fa_square, + Colour = OsuColour.FromHex(@"3087ac"), + Rotation = 45, + Shadow = true, + }, + new TextAwesome + { + Origin = Anchor.Centre, + Icon = icon, + Colour = OsuColour.FromHex(@"a4edff"), + Scale = new Vector2(0.8f), + }, + new GlowingSpriteText(value, @"Exo2.0-Bold", 17, Color4.White, OsuColour.FromHex(@"83ccfa")) + { + Origin = Anchor.CentreLeft, + Margin = new MarginPadding { Left = 15, }, + }, + }; + } + } + } +} diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index 53f3a3a596..c5c8543e6b 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -8,9 +8,11 @@ using osu.Framework.Graphics.Primitives; using osu.Framework.Screens; using osu.Game.Beatmaps; using osu.Game.Graphics; +using osu.Game.Online.API.Requests; using osu.Game.Overlays.Mods; using osu.Game.Screens.Edit; using osu.Game.Screens.Play; +using osu.Game.Screens.Select.Leaderboards; namespace osu.Game.Screens.Select { @@ -18,6 +20,7 @@ namespace osu.Game.Screens.Select { private OsuScreen player; private ModSelectOverlay modSelect; + private Leaderboard leaderboard; public PlaySongSelect() { @@ -28,6 +31,11 @@ namespace osu.Game.Screens.Select Anchor = Anchor.BottomCentre, Margin = new MarginPadding { Bottom = 50 } }); + + LeftContent.Add(leaderboard = new Leaderboard + { + RelativeSizeAxes = Axes.Both, + }); } [BackgroundDependencyLoader] @@ -44,12 +52,29 @@ namespace osu.Game.Screens.Select }, Key.Number3); } + private GetScoresRequest getScoresRequest; + protected override void OnBeatmapChanged(WorkingBeatmap beatmap) { beatmap?.Mods.BindTo(modSelect.SelectedMods); + + updateLeaderboard(beatmap); + base.OnBeatmapChanged(beatmap); } + private void updateLeaderboard(WorkingBeatmap beatmap) + { + leaderboard.Scores = null; + getScoresRequest?.Cancel(); + + if (beatmap?.BeatmapInfo == null) return; + + getScoresRequest = new GetScoresRequest(beatmap.BeatmapInfo); + getScoresRequest.Success += r => leaderboard.Scores = r.Scores; + Game.API.Queue(getScoresRequest); + } + protected override void OnResuming(Screen last) { player = null; diff --git a/osu.Game/Screens/Select/SearchTextBox.cs b/osu.Game/Screens/Select/SearchTextBox.cs index bb1edfd0d7..4f2ab221cb 100644 --- a/osu.Game/Screens/Select/SearchTextBox.cs +++ b/osu.Game/Screens/Select/SearchTextBox.cs @@ -26,6 +26,7 @@ namespace osu.Game.Screens.Select Origin = Anchor.CentreRight, Anchor = Anchor.CentreRight, Margin = new MarginPadding { Right = 10 }, + TextSize = 20 } }); diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 60017bfbd8..7504dc1823 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -39,9 +39,15 @@ namespace osu.Game.Screens.Select private TrackManager trackManager; private DialogOverlay dialogOverlay; - private static readonly Vector2 wedged_container_size = new Vector2(0.5f, 225); + + private static readonly Vector2 wedged_container_size = new Vector2(0.5f, 245); + + private const float left_area_padding = 20; + private BeatmapInfoWedge beatmapInfoWedge; + protected Container LeftContent; + private static readonly Vector2 background_blur = new Vector2(20); private CancellationTokenSource initialAddSetsTask; @@ -81,6 +87,20 @@ namespace osu.Game.Screens.Select } } }); + Add(LeftContent = new Container + { + Origin = Anchor.BottomLeft, + Anchor = Anchor.BottomLeft, + RelativeSizeAxes = Axes.Both, + Size = new Vector2(wedged_container_size.X, 1), + Padding = new MarginPadding + { + Bottom = 50, + Top = wedged_container_size.Y + left_area_padding, + Left = left_area_padding, + Right = left_area_padding * 2, + } + }); Add(carousel = new BeatmapCarousel { RelativeSizeAxes = Axes.Y, @@ -104,8 +124,8 @@ namespace osu.Game.Screens.Select RelativeSizeAxes = Axes.X, Margin = new MarginPadding { - Top = 20, - Right = 20, + Top = left_area_padding, + Right = left_area_padding, }, X = -50, }); diff --git a/osu.Game/Screens/Tournament/Drawings.cs b/osu.Game/Screens/Tournament/Drawings.cs index 61f75021dc..b97b33b47e 100644 --- a/osu.Game/Screens/Tournament/Drawings.cs +++ b/osu.Game/Screens/Tournament/Drawings.cs @@ -21,6 +21,7 @@ using osu.Game.Screens.Tournament.Components; using osu.Game.Screens.Tournament.Teams; using OpenTK; using OpenTK.Graphics; +using osu.Game.Users; namespace osu.Game.Screens.Tournament { @@ -36,7 +37,7 @@ namespace osu.Game.Screens.Tournament private GroupContainer groupsContainer; private OsuSpriteText fullTeamNameText; - private List allTeams = new List(); + private List allTeams = new List(); private DrawingsConfigManager drawingsConfig; @@ -160,7 +161,7 @@ namespace osu.Game.Screens.Tournament Text = "Control Panel", TextSize = 22f, - Font = "Exo2.0-Boldd" + Font = "Exo2.0-Bold" }, new FillFlowContainer { @@ -238,7 +239,7 @@ namespace osu.Game.Screens.Tournament reset(true); } - private void onTeamSelected(Team team) + private void onTeamSelected(Country team) { groupsContainer.AddTeam(team); @@ -275,7 +276,7 @@ namespace osu.Game.Screens.Tournament teamsContainer.ClearTeams(); allTeams.Clear(); - foreach (Team t in TeamList.Teams) + foreach (Country t in TeamList.Teams) { if (groupsContainer.ContainsTeam(t.FullName)) continue; @@ -311,7 +312,7 @@ namespace osu.Game.Screens.Tournament if (line.ToUpper().StartsWith("GROUP")) continue; - Team teamToAdd = allTeams.FirstOrDefault(t => t.FullName == line); + Country teamToAdd = allTeams.FirstOrDefault(t => t.FullName == line); if (teamToAdd == null) continue; diff --git a/osu.Game/Screens/Tournament/Group.cs b/osu.Game/Screens/Tournament/Group.cs index b785e809f9..fb85262d9a 100644 --- a/osu.Game/Screens/Tournament/Group.cs +++ b/osu.Game/Screens/Tournament/Group.cs @@ -11,9 +11,9 @@ using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Game.Graphics.Sprites; -using osu.Game.Screens.Tournament.Teams; using OpenTK; using OpenTK.Graphics; +using osu.Game.Users; namespace osu.Game.Screens.Tournament { @@ -73,7 +73,7 @@ namespace osu.Game.Screens.Tournament }; } - public void AddTeam(Team team) + public void AddTeam(Country team) { GroupTeam gt = new GroupTeam(team); @@ -91,7 +91,7 @@ namespace osu.Game.Screens.Tournament return allTeams.Any(t => t.Team.FullName == fullName); } - public bool RemoveTeam(Team team) + public bool RemoveTeam(Country team) { allTeams.RemoveAll(gt => gt.Team == team); @@ -122,12 +122,12 @@ namespace osu.Game.Screens.Tournament private class GroupTeam : Container { - public Team Team; + public Country Team; private FillFlowContainer innerContainer; private Sprite flagSprite; - public GroupTeam(Team team) + public GroupTeam(Country team) { Team = team; diff --git a/osu.Game/Screens/Tournament/GroupContainer.cs b/osu.Game/Screens/Tournament/GroupContainer.cs index ffc1ca8247..25fd06c9c5 100644 --- a/osu.Game/Screens/Tournament/GroupContainer.cs +++ b/osu.Game/Screens/Tournament/GroupContainer.cs @@ -7,8 +7,8 @@ using System.Linq; using System.Text; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Screens.Tournament.Teams; using OpenTK; +using osu.Game.Users; namespace osu.Game.Screens.Tournament { @@ -64,7 +64,7 @@ namespace osu.Game.Screens.Tournament } } - public void AddTeam(Team team) + public void AddTeam(Country team) { if (groups[currentGroup].TeamsCount == maxTeams) return; diff --git a/osu.Game/Screens/Tournament/ScrollingTeamContainer.cs b/osu.Game/Screens/Tournament/ScrollingTeamContainer.cs index 899c329be4..425ff0bd51 100644 --- a/osu.Game/Screens/Tournament/ScrollingTeamContainer.cs +++ b/osu.Game/Screens/Tournament/ScrollingTeamContainer.cs @@ -13,18 +13,18 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Framework.Graphics.Transforms; using osu.Framework.Threading; -using osu.Game.Screens.Tournament.Teams; using OpenTK; using OpenTK.Graphics; +using osu.Game.Users; namespace osu.Game.Screens.Tournament { public class ScrollingTeamContainer : Container { public event Action OnScrollStarted; - public event Action OnSelected; + public event Action OnSelected; - private readonly List availableTeams = new List(); + private readonly List availableTeams = new List(); private Container tracker; @@ -158,7 +158,7 @@ namespace osu.Game.Screens.Tournament } } - public void AddTeam(Team team) + public void AddTeam(Country team) { if (availableTeams.Contains(team)) return; @@ -169,12 +169,12 @@ namespace osu.Game.Screens.Tournament scrollState = ScrollState.Idle; } - public void AddTeams(IEnumerable teams) + public void AddTeams(IEnumerable teams) { if (teams == null) return; - foreach (Team t in teams) + foreach (Country t in teams) AddTeam(t); } @@ -185,7 +185,7 @@ namespace osu.Game.Screens.Tournament scrollState = ScrollState.Idle; } - public void RemoveTeam(Team team) + public void RemoveTeam(Country team) { availableTeams.Remove(team); @@ -270,7 +270,7 @@ namespace osu.Game.Screens.Tournament private void addFlags() { - foreach (Team t in availableTeams) + foreach (Country t in availableTeams) { Add(new ScrollingTeam(t) { @@ -326,7 +326,7 @@ namespace osu.Game.Screens.Tournament public const float WIDTH = 58; public const float HEIGHT = 41; - public Team Team; + public Country Team; private Sprite flagSprite; private Box outline; @@ -346,7 +346,7 @@ namespace osu.Game.Screens.Tournament } } - public ScrollingTeam(Team team) + public ScrollingTeam(Country team) { Team = team; diff --git a/osu.Game/Screens/Tournament/Teams/ITeamList.cs b/osu.Game/Screens/Tournament/Teams/ITeamList.cs index a4476b64c6..d4b644e2aa 100644 --- a/osu.Game/Screens/Tournament/Teams/ITeamList.cs +++ b/osu.Game/Screens/Tournament/Teams/ITeamList.cs @@ -2,11 +2,12 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System.Collections.Generic; +using osu.Game.Users; namespace osu.Game.Screens.Tournament.Teams { public interface ITeamList { - IEnumerable Teams { get; } + IEnumerable Teams { get; } } } diff --git a/osu.Game/Screens/Tournament/Teams/StorageBackedTeamList.cs b/osu.Game/Screens/Tournament/Teams/StorageBackedTeamList.cs index 9cdf527eff..aca36a484d 100644 --- a/osu.Game/Screens/Tournament/Teams/StorageBackedTeamList.cs +++ b/osu.Game/Screens/Tournament/Teams/StorageBackedTeamList.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.IO; using osu.Framework.Logging; using osu.Framework.Platform; +using osu.Game.Users; namespace osu.Game.Screens.Tournament.Teams { @@ -20,11 +21,11 @@ namespace osu.Game.Screens.Tournament.Teams this.storage = storage; } - public IEnumerable Teams + public IEnumerable Teams { get { - var teams = new List(); + var teams = new List(); try { @@ -52,7 +53,7 @@ namespace osu.Game.Screens.Tournament.Teams string acronym = split.Length >= 3 ? split[2].Trim() : teamName; acronym = acronym.Substring(0, Math.Min(3, acronym.Length)); - teams.Add(new Team + teams.Add(new Country { FlagName = flagName, FullName = teamName, diff --git a/osu.Game/Screens/Tournament/Teams/Team.cs b/osu.Game/Screens/Tournament/Teams/Team.cs deleted file mode 100644 index 226f35ec1d..0000000000 --- a/osu.Game/Screens/Tournament/Teams/Team.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -namespace osu.Game.Screens.Tournament.Teams -{ - public class Team - { - /// - /// The name of this team. - /// - public string FullName; - - /// - /// Short acronym which appears in the group boxes post-selection. - /// - public string Acronym; - - /// - /// Two-letter flag acronym (ISO 3166 standard) - /// - public string FlagName; - } -} diff --git a/osu.Game/Users/Avatar.cs b/osu.Game/Users/Avatar.cs new file mode 100644 index 0000000000..a6ce9f1e41 --- /dev/null +++ b/osu.Game/Users/Avatar.cs @@ -0,0 +1,114 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Diagnostics; +using System.Threading.Tasks; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; + +namespace osu.Game.Users +{ + public class Avatar : Container + { + public Drawable Sprite; + + private long userId; + private OsuGameBase game; + private Texture guestTexture; + + [BackgroundDependencyLoader(permitNulls: true)] + private void load(OsuGameBase game, TextureStore textures) + { + this.game = game; + guestTexture = textures.Get(@"Online/avatar-guest"); + } + + public long UserId + { + get { return userId; } + set + { + if (userId == value) + return; + + userId = value; + invalidateSprite(); + } + } + + private Task loadTask; + + private void invalidateSprite() + { + Sprite?.FadeOut(100); + Sprite?.Expire(); + Sprite = null; + } + + private void updateSprite() + { + if (loadTask != null || Sprite != null) return; + + var newSprite = userId > 1 ? new OnlineSprite($@"https://a.ppy.sh/{userId}", guestTexture) : new Sprite { Texture = guestTexture }; + + newSprite.FillMode = FillMode.Fill; + + loadTask = newSprite.LoadAsync(game, s => + { + Sprite = s; + Add(Sprite); + + Sprite.FadeInFromZero(200); + loadTask = null; + }); + } + + private double timeVisible; + + private bool shouldUpdate => Sprite != null || timeVisible > 500; + + protected override void Update() + { + base.Update(); + + if (!shouldUpdate) + { + //Special optimisation to not start loading until we are within bounds of our closest ScrollContainer parent. + ScrollContainer scroll = null; + IContainer cursor = this; + while (scroll == null && (cursor = cursor.Parent) != null) + scroll = cursor as ScrollContainer; + + if (scroll?.ScreenSpaceDrawQuad.Intersects(ScreenSpaceDrawQuad) ?? true) + timeVisible += Time.Elapsed; + else + timeVisible = 0; + } + + if (shouldUpdate) + updateSprite(); + } + + public class OnlineSprite : Sprite + { + private readonly string url; + private readonly Texture fallbackTexture; + + public OnlineSprite(string url, Texture fallbackTexture = null) + { + Debug.Assert(url != null); + this.url = url; + this.fallbackTexture = fallbackTexture; + } + + [BackgroundDependencyLoader] + private void load(TextureStore textures) + { + Texture = textures.Get(url) ?? fallbackTexture; + } + } + } +} diff --git a/osu.Game/Users/Country.cs b/osu.Game/Users/Country.cs new file mode 100644 index 0000000000..513d256808 --- /dev/null +++ b/osu.Game/Users/Country.cs @@ -0,0 +1,67 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; + +namespace osu.Game.Users +{ + public class Country + { + /// + /// The name of this country. + /// + public string FullName; + + /// + /// Short acronym which appears in the group boxes post-selection. + /// + public string Acronym; + + /// + /// Two-letter flag acronym (ISO 3166 standard) + /// + public string FlagName; + } + + public class DrawableFlag : Container + { + private Sprite sprite; + private TextureStore textures; + + private string flagName; + public string FlagName + { + get { return flagName; } + set + { + if (value == flagName) return; + flagName = value; + sprite.Texture = textures.Get($@"Flags/{flagName}"); + } + } + + [BackgroundDependencyLoader] + private void load(TextureStore ts) + { + textures = ts; + sprite.Texture = textures.Get($@"Flags/{flagName}"); + } + + public DrawableFlag(string name = @"__") + { + flagName = name; + + Children = new Drawable[] + { + sprite = new Sprite + { + RelativeSizeAxes = Axes.Both, + }, + }; + } + } +} diff --git a/osu.Game/Users/Team.cs b/osu.Game/Users/Team.cs new file mode 100644 index 0000000000..7d5c0322fe --- /dev/null +++ b/osu.Game/Users/Team.cs @@ -0,0 +1,10 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +namespace osu.Game.Users +{ + public class Team + { + public string Name; + } +} diff --git a/osu.Game/Users/User.cs b/osu.Game/Users/User.cs index 540bfdbbf9..2763b3100f 100644 --- a/osu.Game/Users/User.cs +++ b/osu.Game/Users/User.cs @@ -7,5 +7,7 @@ namespace osu.Game.Users { public int Id; public string Username; + public Country Country; + public Team Team; } } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 3f97e196db..39b9d8d9e5 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -76,6 +76,7 @@ + @@ -129,6 +130,7 @@ + @@ -241,7 +243,7 @@ - + @@ -265,7 +267,6 @@ - @@ -354,6 +355,13 @@ + + + + + + + @@ -377,6 +385,7 @@ +