diff --git a/osu-framework b/osu-framework index e6394035d4..31cf1c4b58 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit e6394035d443d4498b71e845e5763dd3faf98c7c +Subproject commit 31cf1c4b58c866d047876b15a95a4cf0115d3105 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.Game.Modes.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Modes.Osu/Objects/Drawables/DrawableHitCircle.cs index 20bb937b76..e8c74d4f8d 100644 --- a/osu.Game.Modes.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Modes.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -111,8 +111,6 @@ namespace osu.Game.Modes.Osu.Objects.Drawables protected override void UpdateState(ArmedState state) { - if (!IsLoaded) return; - base.UpdateState(state); ApproachCircle.FadeOut(); diff --git a/osu.Game.Modes.Osu/Objects/Drawables/DrawableOsuHitObject.cs b/osu.Game.Modes.Osu/Objects/Drawables/DrawableOsuHitObject.cs index 5e6249d66f..b2af678cae 100644 --- a/osu.Game.Modes.Osu/Objects/Drawables/DrawableOsuHitObject.cs +++ b/osu.Game.Modes.Osu/Objects/Drawables/DrawableOsuHitObject.cs @@ -22,8 +22,6 @@ namespace osu.Game.Modes.Osu.Objects.Drawables protected override void UpdateState(ArmedState state) { - if (!IsLoaded) return; - Flush(); UpdateInitialState(); diff --git a/osu.Game.Modes.Osu/Objects/Drawables/DrawableSliderTick.cs b/osu.Game.Modes.Osu/Objects/Drawables/DrawableSliderTick.cs index 0400d4a866..fff08b9f60 100644 --- a/osu.Game.Modes.Osu/Objects/Drawables/DrawableSliderTick.cs +++ b/osu.Game.Modes.Osu/Objects/Drawables/DrawableSliderTick.cs @@ -95,8 +95,6 @@ namespace osu.Game.Modes.Osu.Objects.Drawables protected override void UpdateState(ArmedState state) { - if (!IsLoaded) return; - base.UpdateState(state); switch (state) diff --git a/osu.Game.Modes.Osu/Objects/Drawables/DrawableSpinner.cs b/osu.Game.Modes.Osu/Objects/Drawables/DrawableSpinner.cs index 77bfb97ad4..8098e87b12 100644 --- a/osu.Game.Modes.Osu/Objects/Drawables/DrawableSpinner.cs +++ b/osu.Game.Modes.Osu/Objects/Drawables/DrawableSpinner.cs @@ -134,8 +134,6 @@ namespace osu.Game.Modes.Osu.Objects.Drawables protected override void UpdateState(ArmedState state) { - if (!IsLoaded) return; - base.UpdateState(state); Delay(spinner.Duration, true); diff --git a/osu.Game.Modes.Osu/Objects/Drawables/Pieces/NumberPiece.cs b/osu.Game.Modes.Osu/Objects/Drawables/Pieces/NumberPiece.cs index 8d8aadbb60..750f203a8d 100644 --- a/osu.Game.Modes.Osu/Objects/Drawables/Pieces/NumberPiece.cs +++ b/osu.Game.Modes.Osu/Objects/Drawables/Pieces/NumberPiece.cs @@ -29,6 +29,8 @@ namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces { new CircularContainer { + Masking = true, + Origin = Anchor.Centre, EdgeEffect = new EdgeEffect { Type = EdgeEffectType.Glow, diff --git a/osu.Game.Modes.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs b/osu.Game.Modes.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs index 906a3cd7c3..a4fce3deb5 100644 --- a/osu.Game.Modes.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs +++ b/osu.Game.Modes.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs @@ -33,6 +33,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces private void load(OsuColour colours) { completeColour = colours.YellowLight.Opacity(0.8f); + Masking = true; } private class SpinnerBorder : Container @@ -61,6 +62,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces { Colour = Color4.White, RelativePositionAxes = Axes.Both, + Masking = true, Origin = Anchor.Centre, Size = new Vector2(1 / ScreenSpaceDrawQuad.Width * 2000), Children = new[] diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 70bfbb5992..6190678e1e 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); @@ -175,11 +176,11 @@ namespace osu.Game.Configuration ConfineMouseMode.Fullscreen : ConfineMouseMode.Never).Disabled = true; - GetBindable(OsuConfig.SavePassword).ValueChanged += delegate + GetOriginalBindable(OsuConfig.SavePassword).ValueChanged += delegate { if (Get(OsuConfig.SavePassword)) Set(OsuConfig.SaveUsername, true); }; - GetBindable(OsuConfig.SaveUsername).ValueChanged += delegate + GetOriginalBindable(OsuConfig.SaveUsername).ValueChanged += delegate { if (!Get(OsuConfig.SaveUsername)) Set(OsuConfig.SavePassword, 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..ed9d52d0b7 100644 --- a/osu.Game/Graphics/Cursor/GameplayCursor.cs +++ b/osu.Game/Graphics/Cursor/GameplayCursor.cs @@ -54,8 +54,6 @@ namespace osu.Game.Graphics.Cursor [BackgroundDependencyLoader] private void load(OsuConfigManager config) { - cursorScale = config.GetBindable(OsuConfig.CursorSize); - Children = new Drawable[] { cursorContainer = new CircularContainer @@ -63,7 +61,6 @@ namespace osu.Game.Graphics.Cursor Origin = Anchor.Centre, Anchor = Anchor.Centre, RelativeSizeAxes = Axes.Both, - Scale = new Vector2((float)cursorScale), Masking = true, BorderThickness = Size.X / 6, BorderColour = Color4.White, @@ -119,7 +116,9 @@ namespace osu.Game.Graphics.Cursor }, }; + cursorScale = config.GetBindable(OsuConfig.GameplayCursorSize); cursorScale.ValueChanged += scaleChanged; + cursorScale.TriggerChange(); } private void scaleChanged(object sender, EventArgs e) diff --git a/osu.Game/Graphics/Cursor/MenuCursor.cs b/osu.Game/Graphics/Cursor/MenuCursor.cs index 1a21875cae..3ab6fa7093 100644 --- a/osu.Game/Graphics/Cursor/MenuCursor.cs +++ b/osu.Game/Graphics/Cursor/MenuCursor.cs @@ -97,8 +97,6 @@ namespace osu.Game.Graphics.Cursor [BackgroundDependencyLoader] private void load(OsuConfigManager config, TextureStore textures, OsuColour colour) { - cursorScale = config.GetBindable(OsuConfig.CursorSize); - Children = new Drawable[] { cursorContainer = new Container @@ -122,7 +120,10 @@ namespace osu.Game.Graphics.Cursor } } }; + + cursorScale = config.GetBindable(OsuConfig.MenuCursorSize); cursorScale.ValueChanged += scaleChanged; + cursorScale.TriggerChange(); } private void scaleChanged(object sender, EventArgs e) diff --git a/osu.Game/Graphics/UserInterface/Nub.cs b/osu.Game/Graphics/UserInterface/Nub.cs index 6f3529b67d..a32e047af9 100644 --- a/osu.Game/Graphics/UserInterface/Nub.cs +++ b/osu.Game/Graphics/UserInterface/Nub.cs @@ -30,6 +30,8 @@ namespace osu.Game.Graphics.UserInterface BorderColour = Color4.White; BorderThickness = border_width; + Masking = true; + Children = new[] { fill = new Box diff --git a/osu.Game/Graphics/UserInterface/OsuPasswordTextBox.cs b/osu.Game/Graphics/UserInterface/OsuPasswordTextBox.cs index df48694249..c9d8f936f6 100644 --- a/osu.Game/Graphics/UserInterface/OsuPasswordTextBox.cs +++ b/osu.Game/Graphics/UserInterface/OsuPasswordTextBox.cs @@ -28,6 +28,8 @@ namespace osu.Game.Graphics.UserInterface circle = new CircularContainer { Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Masking = true, Alpha = 0, RelativeSizeAxes = Axes.Both, Size = new Vector2(0.8f, 0), diff --git a/osu.Game/Modes/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Modes/Objects/Drawables/DrawableHitObject.cs index f3bb07d2d8..277e65c1b1 100644 --- a/osu.Game/Modes/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Modes/Objects/Drawables/DrawableHitObject.cs @@ -39,6 +39,9 @@ namespace osu.Game.Modes.Objects.Drawables return; state = value; + if (!IsLoaded) + return; + UpdateState(state); if (State == ArmedState.Hit) 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/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/Overlays/Dialog/PopupDialog.cs b/osu.Game/Overlays/Dialog/PopupDialog.cs index 908dbf8ebc..7936339e0c 100644 --- a/osu.Game/Overlays/Dialog/PopupDialog.cs +++ b/osu.Game/Overlays/Dialog/PopupDialog.cs @@ -193,6 +193,7 @@ namespace osu.Game.Overlays.Dialog { Origin = Anchor.Centre, Anchor = Anchor.Centre, + Masking = true, BorderColour = Color4.White, BorderThickness = 5f, Children = new Drawable[] 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/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/Menu/OsuLogo.cs b/osu.Game/Screens/Menu/OsuLogo.cs index 259e98c483..90223616d0 100644 --- a/osu.Game/Screens/Menu/OsuLogo.cs +++ b/osu.Game/Screens/Menu/OsuLogo.cs @@ -91,8 +91,10 @@ namespace osu.Game.Screens.Menu logoContainer = new CircularContainer { Anchor = Anchor.Centre, + Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, Scale = new Vector2(0.8f), + Masking = true, Children = new Drawable[] { colourAndTriangles = new Container 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/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/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 b31a73b230..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; @@ -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 50809cddf7..9cedaa1b09 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -129,6 +129,7 @@ + @@ -241,7 +242,7 @@ - + @@ -265,7 +266,6 @@ - @@ -354,6 +354,13 @@ + + + + + + + @@ -377,6 +384,7 @@ +