1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-14 16:52:54 +08:00

Merge branch 'master' into spectator-driven-leaderboard

This commit is contained in:
Dean Herbert 2020-12-20 01:13:59 +09:00 committed by GitHub
commit b3bff281ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 220 additions and 215 deletions

View File

@ -39,7 +39,7 @@ namespace osu.Game.Tests.Visual.Gameplay
playerScore.Value = 1222333;
});
AddStep("add local player", () => createLeaderboardScore(playerScore, "You", true));
AddStep("add local player", () => createLeaderboardScore(playerScore, new User { Username = "You", Id = 3 }, true));
AddSliderStep("set player score", 50, 5000000, 1222333, v => playerScore.Value = v);
}
@ -49,8 +49,8 @@ namespace osu.Game.Tests.Visual.Gameplay
var player2Score = new BindableDouble(1234567);
var player3Score = new BindableDouble(1111111);
AddStep("add player 2", () => createLeaderboardScore(player2Score, "Player 2"));
AddStep("add player 3", () => createLeaderboardScore(player3Score, "Player 3"));
AddStep("add player 2", () => createLeaderboardScore(player2Score, new User { Username = "Player 2" }));
AddStep("add player 3", () => createLeaderboardScore(player3Score, new User { Username = "Player 3" }));
AddAssert("is player 2 position #1", () => leaderboard.CheckPositionByUsername("Player 2", 1));
AddAssert("is player position #2", () => leaderboard.CheckPositionByUsername("You", 2));
@ -71,12 +71,23 @@ namespace osu.Game.Tests.Visual.Gameplay
public void TestRandomScores()
{
int playerNumber = 1;
AddRepeatStep("add player with random score", () => createLeaderboardScore(new BindableDouble(RNG.Next(0, 5_000_000)), $"Player {playerNumber++}"), 10);
AddRepeatStep("add player with random score", () => createRandomScore(new User { Username = $"Player {playerNumber++}" }), 10);
}
private void createLeaderboardScore(BindableDouble score, string username, bool isTracked = false)
[Test]
public void TestExistingUsers()
{
var leaderboardScore = leaderboard.AddPlayer(new User { Username = username }, isTracked);
AddStep("add peppy", () => createRandomScore(new User { Username = "peppy", Id = 2 }));
AddStep("add smoogipoo", () => createRandomScore(new User { Username = "smoogipoo", Id = 1040328 }));
AddStep("add flyte", () => createRandomScore(new User { Username = "flyte", Id = 3103765 }));
AddStep("add frenzibyte", () => createRandomScore(new User { Username = "frenzibyte", Id = 14210502 }));
}
private void createRandomScore(User user) => createLeaderboardScore(new BindableDouble(RNG.Next(0, 5_000_000)), user);
private void createLeaderboardScore(BindableDouble score, User user, bool isTracked = false)
{
var leaderboardScore = leaderboard.AddPlayer(user, isTracked);
leaderboardScore.TotalScore.BindTo(score);
}

View File

@ -4,7 +4,6 @@
using System;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Multiplayer.RoomStatuses;
using osu.Game.Screens.Multi.Lounge.Components;
using osu.Game.Users;
@ -14,10 +13,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
public class TestSceneLoungeRoomInfo : MultiplayerTestScene
{
[SetUp]
public void Setup() => Schedule(() =>
public new void Setup() => Schedule(() =>
{
Room = new Room();
Child = new RoomInfo
{
Anchor = Anchor.Centre,

View File

@ -24,10 +24,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
private RulesetStore rulesetStore { get; set; }
[SetUp]
public void Setup() => Schedule(() =>
public new void Setup() => Schedule(() =>
{
Room = new Room();
Child = new MatchBeatmapDetailArea
{
Anchor = Anchor.Centre,

View File

@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using NUnit.Framework;
using osu.Game.Beatmaps;
using osu.Game.Online.Multiplayer;
using osu.Game.Rulesets.Osu;
@ -14,7 +15,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
public TestSceneMatchHeader()
{
Room = new Room();
Child = new Header();
}
[SetUp]
public new void Setup() => Schedule(() =>
{
Room.Playlist.Add(new PlaylistItem
{
Beatmap =
@ -41,8 +47,6 @@ namespace osu.Game.Tests.Visual.Multiplayer
Room.Name.Value = "A very awesome room";
Room.Host.Value = new User { Id = 2, Username = "peppy" };
Child = new Header();
}
});
}
}

View File

@ -3,10 +3,10 @@
using System.Collections.Generic;
using Newtonsoft.Json;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Online.API;
using osu.Game.Online.Multiplayer;
using osu.Game.Screens.Multi.Match.Components;
using osu.Game.Users;
using osuTK;
@ -19,8 +19,6 @@ namespace osu.Game.Tests.Visual.Multiplayer
public TestSceneMatchLeaderboard()
{
Room = new Room { RoomID = { Value = 3 } };
Add(new MatchLeaderboard
{
Origin = Anchor.Centre,
@ -40,6 +38,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
api.Queue(req);
}
[SetUp]
public new void Setup() => Schedule(() =>
{
Room.RoomID.Value = 3;
});
private class GetRoomScoresRequest : APIRequest<List<RoomScore>>
{
protected override string Target => "rooms/3/leaderboard";

View File

@ -23,10 +23,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
private TestRoomSettings settings;
[SetUp]
public void Setup() => Schedule(() =>
public new void Setup() => Schedule(() =>
{
Room = new Room();
settings = new TestRoomSettings
{
RelativeSizeAxes = Axes.Both,

View File

@ -14,7 +14,6 @@ using osu.Framework.Platform;
using osu.Framework.Screens;
using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Online.Multiplayer;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu;
@ -94,12 +93,6 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddUntilStep("wait for present", () => songSelect.IsCurrentScreen());
}
[SetUp]
public void Setup() => Schedule(() =>
{
Room = new Room();
});
[Test]
public void TestItemAddedIfEmptyOnStart()
{

View File

@ -45,12 +45,6 @@ namespace osu.Game.Tests.Visual.Multiplayer
manager.Import(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo.BeatmapSet).Wait();
}
[SetUp]
public void Setup() => Schedule(() =>
{
Room = new Room();
});
[SetUpSteps]
public void SetupSteps()
{

View File

@ -1,50 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Game.Online.Multiplayer;
using osu.Game.Screens.Multi.Components;
using osuTK;
namespace osu.Game.Tests.Visual.Multiplayer
{
public class TestSceneOverlinedParticipants : MultiplayerTestScene
{
protected override bool UseOnlineAPI => true;
[SetUp]
public void Setup() => Schedule(() =>
{
Room = new Room { RoomID = { Value = 7 } };
});
[Test]
public void TestHorizontalLayout()
{
AddStep("create component", () =>
{
Child = new ParticipantsDisplay(Direction.Horizontal)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Width = 500,
};
});
}
[Test]
public void TestVerticalLayout()
{
AddStep("create component", () =>
{
Child = new ParticipantsDisplay(Direction.Vertical)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(500)
};
});
}
}
}

View File

@ -1,39 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics;
using osu.Game.Online.Multiplayer;
using osu.Game.Rulesets.Osu;
using osu.Game.Screens.Multi;
using osu.Game.Tests.Beatmaps;
using osuTK;
namespace osu.Game.Tests.Visual.Multiplayer
{
public class TestSceneOverlinedPlaylist : MultiplayerTestScene
{
protected override bool UseOnlineAPI => true;
public TestSceneOverlinedPlaylist()
{
Room = new Room { RoomID = { Value = 7 } };
for (int i = 0; i < 10; i++)
{
Room.Playlist.Add(new PlaylistItem
{
ID = i,
Beatmap = { Value = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo },
Ruleset = { Value = new OsuRuleset().RulesetInfo }
});
}
Add(new DrawableRoomPlaylist(false, false)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(500),
});
}
}
}

View File

@ -3,24 +3,55 @@
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Game.Online.Multiplayer;
using osu.Game.Screens.Multi.Components;
using osu.Game.Users;
namespace osu.Game.Tests.Visual.Multiplayer
{
public class TestSceneParticipantsList : MultiplayerTestScene
{
protected override bool UseOnlineAPI => true;
[SetUp]
public void Setup() => Schedule(() =>
public new void Setup() => Schedule(() =>
{
Room = new Room { RoomID = { Value = 7 } };
Room.RoomID.Value = 7;
for (int i = 0; i < 50; i++)
{
Room.RecentParticipants.Add(new User
{
Username = "peppy",
Id = 2
});
}
});
public TestSceneParticipantsList()
[Test]
public void TestHorizontalLayout()
{
Add(new ParticipantsList { RelativeSizeAxes = Axes.Both });
AddStep("create component", () =>
{
Child = new ParticipantsDisplay(Direction.Horizontal)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Width = 0.2f,
};
});
}
[Test]
public void TestVerticalLayout()
{
AddStep("create component", () =>
{
Child = new ParticipantsDisplay(Direction.Vertical)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Width = 0.2f,
Height = 0.2f,
};
});
}
}
}

View File

@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Online.Multiplayer;
@ -22,18 +23,21 @@ namespace osu.Game.Tests.Visual.Multiplayer
new DrawableRoom(new Room
{
Name = { Value = "Room 1" },
Status = { Value = new RoomStatusOpen() }
}),
Status = { Value = new RoomStatusOpen() },
EndDate = { Value = DateTimeOffset.Now.AddDays(1) }
}) { MatchingFilter = true },
new DrawableRoom(new Room
{
Name = { Value = "Room 2" },
Status = { Value = new RoomStatusPlaying() }
}),
Status = { Value = new RoomStatusPlaying() },
EndDate = { Value = DateTimeOffset.Now.AddDays(1) }
}) { MatchingFilter = true },
new DrawableRoom(new Room
{
Name = { Value = "Room 3" },
Status = { Value = new RoomStatusEnded() }
}),
Status = { Value = new RoomStatusEnded() },
EndDate = { Value = DateTimeOffset.Now }
}) { MatchingFilter = true },
}
};
}

View File

@ -24,8 +24,8 @@ using osu.Game.Scoring;
using osu.Game.Users.Drawables;
using osuTK;
using osuTK.Graphics;
using Humanizer;
using osu.Game.Online.API;
using osu.Game.Utils;
namespace osu.Game.Online.Leaderboards
{
@ -358,7 +358,7 @@ namespace osu.Game.Online.Leaderboards
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Font = OsuFont.GetFont(size: 20, italics: true),
Text = rank == null ? "-" : rank.Value.ToMetric(decimals: rank < 100000 ? 1 : 0),
Text = rank == null ? "-" : rank.Value.FormatRank()
};
}

View File

@ -92,6 +92,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
}
}
private Container dragHandles;
private FillFlowContainer buttons;
public const float BORDER_RADIUS = 3;
@ -151,6 +152,12 @@ namespace osu.Game.Screens.Edit.Compose.Components
},
}
},
dragHandles = new Container
{
RelativeSizeAxes = Axes.Both,
// ensures that the centres of all drag handles line up with the middle of the selection box border.
Padding = new MarginPadding(BORDER_RADIUS / 2)
},
buttons = new FillFlowContainer
{
Y = 20,
@ -232,7 +239,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
});
}
private void addDragHandle(Anchor anchor) => AddInternal(new SelectionBoxDragHandle
private void addDragHandle(Anchor anchor) => dragHandles.Add(new SelectionBoxDragHandle
{
Anchor = anchor,
HandleDrag = e => OnScale?.Invoke(e.Delta, anchor),

View File

@ -24,6 +24,14 @@ namespace osu.Game.Screens.Play.HUD
LayoutEasing = Easing.OutQuint;
}
/// <summary>
/// Adds a player to the leaderboard.
/// </summary>
/// <param name="user">The player.</param>
/// <param name="isTracked">
/// Whether the player should be tracked on the leaderboard.
/// Set to <c>true</c> for the local player or a player whose replay is currently being played.
/// </param>
public ILeaderboardScore AddPlayer(User user, bool isTracked)
{
var drawable = new GameplayLeaderboardScore(user, isTracked)
@ -40,9 +48,9 @@ namespace osu.Game.Screens.Play.HUD
return drawable;
}
public override void Add(GameplayLeaderboardScore drawable)
public sealed override void Add(GameplayLeaderboardScore drawable)
{
throw new InvalidOperationException($"Use {nameof(AddPlayer)} instead.");
throw new NotSupportedException($"Use {nameof(AddPlayer)} instead.");
}
private void sort()

View File

@ -1,7 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using Humanizer;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
@ -11,6 +10,7 @@ using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Users;
using osu.Game.Users.Drawables;
using osu.Game.Utils;
using osuTK;
using osuTK.Graphics;
@ -19,9 +19,9 @@ namespace osu.Game.Screens.Play.HUD
{
public class GameplayLeaderboardScore : CompositeDrawable, ILeaderboardScore
{
public const float EXTENDED_WIDTH = 235f;
public const float EXTENDED_WIDTH = 255f;
private const float regular_width = 215f;
private const float regular_width = 235f;
public const float PANEL_HEIGHT = 35f;
@ -48,7 +48,7 @@ namespace osu.Game.Screens.Play.HUD
scorePosition = value;
if (scorePosition.HasValue)
positionText.Text = $"#{scorePosition.Value.ToMetric(decimals: scorePosition < 100000 ? 1 : 0)}";
positionText.Text = $"#{scorePosition.Value.FormatRank()}";
positionText.FadeTo(scorePosition.HasValue ? 1 : 0);
updateColour();
@ -75,61 +75,8 @@ namespace osu.Game.Screens.Play.HUD
Size = new Vector2(EXTENDED_WIDTH, PANEL_HEIGHT);
}
protected override void LoadComplete()
{
base.LoadComplete();
updateColour();
FinishTransforms(true);
}
private const double transition_duration = 500;
private void updateColour()
{
if (scorePosition == 1)
{
mainFillContainer.ResizeWidthTo(EXTENDED_WIDTH, transition_duration, Easing.OutElastic);
panelColour = Color4Extensions.FromHex("7fcc33");
textColour = Color4.White;
}
else if (trackedPlayer)
{
mainFillContainer.ResizeWidthTo(EXTENDED_WIDTH, transition_duration, Easing.OutElastic);
panelColour = Color4Extensions.FromHex("ffd966");
textColour = Color4Extensions.FromHex("2e576b");
}
else
{
mainFillContainer.ResizeWidthTo(regular_width, transition_duration, Easing.OutElastic);
panelColour = Color4Extensions.FromHex("3399cc");
textColour = Color4.White;
}
}
private Color4 panelColour
{
set
{
mainFillContainer.FadeColour(value, transition_duration, Easing.OutQuint);
centralFill.FadeColour(value, transition_duration, Easing.OutQuint);
}
}
private Color4 textColour
{
set
{
scoreText.FadeColour(value, 200, Easing.OutQuint);
accuracyText.FadeColour(value, 200, Easing.OutQuint);
comboText.FadeColour(value, 200, Easing.OutQuint);
usernameText.FadeColour(value, 200, Easing.OutQuint);
positionText.FadeColour(value, 200, Easing.OutQuint);
}
}
[BackgroundDependencyLoader]
private void load()
private void load(OsuColour colours)
{
InternalChildren = new Drawable[]
{
@ -195,19 +142,51 @@ namespace osu.Game.Screens.Play.HUD
},
}
},
usernameText = new OsuSpriteText
new FillFlowContainer
{
Padding = new MarginPadding { Left = SHEAR_WIDTH },
RelativeSizeAxes = Axes.X,
Width = 0.8f,
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Colour = Color4.White,
Font = OsuFont.Torus.With(size: 14, weight: FontWeight.SemiBold),
Text = User.Username,
Truncate = true,
Shadow = false,
}
RelativeSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(4f, 0f),
Children = new Drawable[]
{
new CircularContainer
{
Masking = true,
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Size = new Vector2(25f),
Children = new Drawable[]
{
new Box
{
Name = "Placeholder while avatar loads",
Alpha = 0.3f,
RelativeSizeAxes = Axes.Both,
Colour = colours.Gray4,
},
new UpdateableAvatar(User)
{
RelativeSizeAxes = Axes.Both,
},
}
},
usernameText = new OsuSpriteText
{
RelativeSizeAxes = Axes.X,
Width = 0.8f,
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Colour = Color4.White,
Font = OsuFont.Torus.With(size: 14, weight: FontWeight.SemiBold),
Text = User.Username,
Truncate = true,
Shadow = false,
}
}
},
}
},
new Container
@ -252,5 +231,60 @@ namespace osu.Game.Screens.Play.HUD
Accuracy.BindValueChanged(v => accuracyText.Text = v.NewValue.FormatAccuracy(), true);
Combo.BindValueChanged(v => comboText.Text = $"{v.NewValue}x", true);
}
protected override void LoadComplete()
{
base.LoadComplete();
updateColour();
FinishTransforms(true);
}
private const double panel_transition_duration = 500;
private void updateColour()
{
if (scorePosition == 1)
{
mainFillContainer.ResizeWidthTo(EXTENDED_WIDTH, panel_transition_duration, Easing.OutElastic);
panelColour = Color4Extensions.FromHex("7fcc33");
textColour = Color4.White;
}
else if (trackedPlayer)
{
mainFillContainer.ResizeWidthTo(EXTENDED_WIDTH, panel_transition_duration, Easing.OutElastic);
panelColour = Color4Extensions.FromHex("ffd966");
textColour = Color4Extensions.FromHex("2e576b");
}
else
{
mainFillContainer.ResizeWidthTo(regular_width, panel_transition_duration, Easing.OutElastic);
panelColour = Color4Extensions.FromHex("3399cc");
textColour = Color4.White;
}
}
private Color4 panelColour
{
set
{
mainFillContainer.FadeColour(value, panel_transition_duration, Easing.OutQuint);
centralFill.FadeColour(value, panel_transition_duration, Easing.OutQuint);
}
}
private const double text_transition_duration = 200;
private Color4 textColour
{
set
{
scoreText.FadeColour(value, text_transition_duration, Easing.OutQuint);
accuracyText.FadeColour(value, text_transition_duration, Easing.OutQuint);
comboText.FadeColour(value, text_transition_duration, Easing.OutQuint);
usernameText.FadeColour(value, text_transition_duration, Easing.OutQuint);
positionText.FadeColour(value, text_transition_duration, Easing.OutQuint);
}
}
}
}

View File

@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Game.Online.Multiplayer;
@ -12,11 +13,7 @@ namespace osu.Game.Tests.Visual
[Cached]
private readonly Bindable<Room> currentRoom = new Bindable<Room>();
protected Room Room
{
get => currentRoom.Value;
set => currentRoom.Value = value;
}
protected Room Room => currentRoom.Value;
private CachedModelDependencyContainer<Room> dependencies;
@ -26,5 +23,11 @@ namespace osu.Game.Tests.Visual
dependencies.Model.BindTo(currentRoom);
return dependencies;
}
[SetUp]
public void Setup() => Schedule(() =>
{
currentRoom.Value = new Room();
});
}
}

View File

@ -1,6 +1,8 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using Humanizer;
namespace osu.Game.Utils
{
public static class FormatUtils
@ -18,5 +20,11 @@ namespace osu.Game.Utils
/// <param name="accuracy">The accuracy to be formatted</param>
/// <returns>formatted accuracy in percentage</returns>
public static string FormatAccuracy(this decimal accuracy) => $"{accuracy:0.00}%";
/// <summary>
/// Formats the supplied rank/leaderboard position in a consistent, simplified way.
/// </summary>
/// <param name="rank">The rank/position to be formatted.</param>
public static string FormatRank(this int rank) => rank.ToMetric(decimals: rank < 100_000 ? 1 : 0);
}
}