diff --git a/.run/Dual client test.run.xml b/.run/Dual client test.run.xml
new file mode 100644
index 0000000000..e112aa3d5d
--- /dev/null
+++ b/.run/Dual client test.run.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.run/osu! (Second Client).run.xml b/.run/osu! (Second Client).run.xml
new file mode 100644
index 0000000000..599b4b986b
--- /dev/null
+++ b/.run/osu! (Second Client).run.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/osu.Desktop/Program.cs b/osu.Desktop/Program.cs
index 5fb09c0cef..cbee1694ba 100644
--- a/osu.Desktop/Program.cs
+++ b/osu.Desktop/Program.cs
@@ -3,7 +3,6 @@
using System;
using System.IO;
-using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using osu.Framework;
@@ -17,13 +16,43 @@ namespace osu.Desktop
{
public static class Program
{
+ private const string base_game_name = @"osu";
+
[STAThread]
public static int Main(string[] args)
{
// Back up the cwd before DesktopGameHost changes it
var cwd = Environment.CurrentDirectory;
- using (DesktopGameHost host = Host.GetSuitableHost(@"osu", true))
+ string gameName = base_game_name;
+ bool tournamentClient = false;
+
+ foreach (var arg in args)
+ {
+ var split = arg.Split('=');
+
+ var key = split[0];
+ var val = split[1];
+
+ switch (key)
+ {
+ case "--tournament":
+ tournamentClient = true;
+ break;
+
+ case "--debug-client-id":
+ if (!DebugUtils.IsDebugBuild)
+ throw new InvalidOperationException("Cannot use this argument in a non-debug build.");
+
+ if (!int.TryParse(val, out int clientID))
+ throw new ArgumentException("Provided client ID must be an integer.");
+
+ gameName = $"{base_game_name}-{clientID}";
+ break;
+ }
+ }
+
+ using (DesktopGameHost host = Host.GetSuitableHost(gameName, true))
{
host.ExceptionThrown += handleException;
@@ -48,16 +77,10 @@ namespace osu.Desktop
return 0;
}
- switch (args.FirstOrDefault() ?? string.Empty)
- {
- default:
- host.Run(new OsuGameDesktop(args));
- break;
-
- case "--tournament":
- host.Run(new TournamentGame());
- break;
- }
+ if (tournamentClient)
+ host.Run(new TournamentGame());
+ else
+ host.Run(new OsuGameDesktop(args));
return 0;
}
diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs b/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs
index 495c369eac..5180854aba 100644
--- a/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs
+++ b/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs
@@ -12,6 +12,7 @@ using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets;
+using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu;
using osu.Game.Scoring;
using osu.Game.Screens.Ranking;
@@ -61,9 +62,33 @@ namespace osu.Game.Tests.Visual.Ranking
AddAssert("mapped by text not present", () =>
this.ChildrenOfType().All(spriteText => !containsAny(spriteText.Text.ToString(), "mapped", "by")));
+
+ AddAssert("play time displayed", () => this.ChildrenOfType().Any());
}
- private void showPanel(ScoreInfo score) => Child = new ExpandedPanelMiddleContentContainer(score);
+ [Test]
+ public void TestWithDefaultDate()
+ {
+ AddStep("show autoplay score", () =>
+ {
+ var ruleset = new OsuRuleset();
+
+ var mods = new Mod[] { ruleset.GetAutoplayMod() };
+ var beatmap = createTestBeatmap(null);
+
+ showPanel(new TestScoreInfo(ruleset.RulesetInfo)
+ {
+ Mods = mods,
+ Beatmap = beatmap,
+ Date = default,
+ });
+ });
+
+ AddAssert("play time not displayed", () => !this.ChildrenOfType().Any());
+ }
+
+ private void showPanel(ScoreInfo score) =>
+ Child = new ExpandedPanelMiddleContentContainer(score);
private BeatmapInfo createTestBeatmap(User author)
{
diff --git a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs
index 4d3f7a4184..e10fe5726d 100644
--- a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs
+++ b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs
@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
@@ -79,162 +80,155 @@ namespace osu.Game.Screens.Ranking.Expanded
var starDifficulty = beatmapDifficultyCache.GetDifficultyAsync(beatmap, score.Ruleset, score.Mods).Result;
- InternalChildren = new Drawable[]
+ AddInternal(new FillFlowContainer
{
- new FillFlowContainer
+ RelativeSizeAxes = Axes.Both,
+ Direction = FillDirection.Vertical,
+ Spacing = new Vector2(20),
+ Children = new Drawable[]
{
- RelativeSizeAxes = Axes.Both,
- Direction = FillDirection.Vertical,
- Spacing = new Vector2(20),
- Children = new Drawable[]
+ new FillFlowContainer
{
- new FillFlowContainer
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre,
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Direction = FillDirection.Vertical,
+ Children = new Drawable[]
{
- Anchor = Anchor.TopCentre,
- Origin = Anchor.TopCentre,
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Direction = FillDirection.Vertical,
- Children = new Drawable[]
+ new OsuSpriteText
{
- new OsuSpriteText
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre,
+ Text = new RomanisableString(metadata.TitleUnicode, metadata.Title),
+ Font = OsuFont.Torus.With(size: 20, weight: FontWeight.SemiBold),
+ MaxWidth = ScorePanel.EXPANDED_WIDTH - padding * 2,
+ Truncate = true,
+ },
+ new OsuSpriteText
+ {
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre,
+ Text = new RomanisableString(metadata.ArtistUnicode, metadata.Artist),
+ Font = OsuFont.Torus.With(size: 14, weight: FontWeight.SemiBold),
+ MaxWidth = ScorePanel.EXPANDED_WIDTH - padding * 2,
+ Truncate = true,
+ },
+ new Container
+ {
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre,
+ Margin = new MarginPadding { Top = 40 },
+ RelativeSizeAxes = Axes.X,
+ Height = 230,
+ Child = new AccuracyCircle(score, withFlair)
{
- Anchor = Anchor.TopCentre,
- Origin = Anchor.TopCentre,
- Text = new RomanisableString(metadata.TitleUnicode, metadata.Title),
- Font = OsuFont.Torus.With(size: 20, weight: FontWeight.SemiBold),
- MaxWidth = ScorePanel.EXPANDED_WIDTH - padding * 2,
- Truncate = true,
- },
- new OsuSpriteText
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.Both,
+ FillMode = FillMode.Fit,
+ }
+ },
+ scoreCounter = new TotalScoreCounter
+ {
+ Margin = new MarginPadding { Top = 0, Bottom = 5 },
+ Current = { Value = 0 },
+ Alpha = 0,
+ AlwaysPresent = true
+ },
+ starAndModDisplay = new FillFlowContainer
+ {
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre,
+ AutoSizeAxes = Axes.Both,
+ Spacing = new Vector2(5, 0),
+ Children = new Drawable[]
{
- Anchor = Anchor.TopCentre,
- Origin = Anchor.TopCentre,
- Text = new RomanisableString(metadata.ArtistUnicode, metadata.Artist),
- Font = OsuFont.Torus.With(size: 14, weight: FontWeight.SemiBold),
- MaxWidth = ScorePanel.EXPANDED_WIDTH - padding * 2,
- Truncate = true,
- },
- new Container
- {
- Anchor = Anchor.TopCentre,
- Origin = Anchor.TopCentre,
- Margin = new MarginPadding { Top = 40 },
- RelativeSizeAxes = Axes.X,
- Height = 230,
- Child = new AccuracyCircle(score, withFlair)
+ new StarRatingDisplay(starDifficulty)
{
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- RelativeSizeAxes = Axes.Both,
- FillMode = FillMode.Fit,
- }
- },
- scoreCounter = new TotalScoreCounter
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.CentreLeft
+ },
+ }
+ },
+ new FillFlowContainer
+ {
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre,
+ Direction = FillDirection.Vertical,
+ AutoSizeAxes = Axes.Both,
+ Children = new Drawable[]
{
- Margin = new MarginPadding { Top = 0, Bottom = 5 },
- Current = { Value = 0 },
- Alpha = 0,
- AlwaysPresent = true
- },
- starAndModDisplay = new FillFlowContainer
- {
- Anchor = Anchor.TopCentre,
- Origin = Anchor.TopCentre,
- AutoSizeAxes = Axes.Both,
- Spacing = new Vector2(5, 0),
- Children = new Drawable[]
+ new OsuSpriteText
{
- new StarRatingDisplay(starDifficulty)
- {
- Anchor = Anchor.CentreLeft,
- Origin = Anchor.CentreLeft
- },
- }
- },
- new FillFlowContainer
- {
- Anchor = Anchor.TopCentre,
- Origin = Anchor.TopCentre,
- Direction = FillDirection.Vertical,
- AutoSizeAxes = Axes.Both,
- Children = new Drawable[]
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre,
+ Text = beatmap.Version,
+ Font = OsuFont.Torus.With(size: 16, weight: FontWeight.SemiBold),
+ },
+ new OsuTextFlowContainer(s => s.Font = OsuFont.Torus.With(size: 12))
{
- new OsuSpriteText
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre,
+ AutoSizeAxes = Axes.Both,
+ Direction = FillDirection.Horizontal,
+ }.With(t =>
+ {
+ if (!string.IsNullOrEmpty(creator))
{
- Anchor = Anchor.TopCentre,
- Origin = Anchor.TopCentre,
- Text = beatmap.Version,
- Font = OsuFont.Torus.With(size: 16, weight: FontWeight.SemiBold),
- },
- new OsuTextFlowContainer(s => s.Font = OsuFont.Torus.With(size: 12))
- {
- Anchor = Anchor.TopCentre,
- Origin = Anchor.TopCentre,
- AutoSizeAxes = Axes.Both,
- Direction = FillDirection.Horizontal,
- }.With(t =>
- {
- if (!string.IsNullOrEmpty(creator))
- {
- t.AddText("mapped by ");
- t.AddText(creator, s => s.Font = s.Font.With(weight: FontWeight.SemiBold));
- }
- })
- }
- },
- }
- },
- new FillFlowContainer
+ t.AddText("mapped by ");
+ t.AddText(creator, s => s.Font = s.Font.With(weight: FontWeight.SemiBold));
+ }
+ })
+ }
+ },
+ }
+ },
+ new FillFlowContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Direction = FillDirection.Vertical,
+ Spacing = new Vector2(0, 5),
+ Children = new Drawable[]
{
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Direction = FillDirection.Vertical,
- Spacing = new Vector2(0, 5),
- Children = new Drawable[]
+ new GridContainer
{
- new GridContainer
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Content = new[] { topStatistics.Cast().ToArray() },
+ RowDimensions = new[]
{
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Content = new[] { topStatistics.Cast().ToArray() },
- RowDimensions = new[]
- {
- new Dimension(GridSizeMode.AutoSize),
- }
- },
- new GridContainer
+ new Dimension(GridSizeMode.AutoSize),
+ }
+ },
+ new GridContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Content = new[] { bottomStatistics.Where(s => s.Result <= HitResult.Perfect).ToArray() },
+ RowDimensions = new[]
{
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Content = new[] { bottomStatistics.Where(s => s.Result <= HitResult.Perfect).ToArray() },
- RowDimensions = new[]
- {
- new Dimension(GridSizeMode.AutoSize),
- }
- },
- new GridContainer
+ new Dimension(GridSizeMode.AutoSize),
+ }
+ },
+ new GridContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Content = new[] { bottomStatistics.Where(s => s.Result > HitResult.Perfect).ToArray() },
+ RowDimensions = new[]
{
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Content = new[] { bottomStatistics.Where(s => s.Result > HitResult.Perfect).ToArray() },
- RowDimensions = new[]
- {
- new Dimension(GridSizeMode.AutoSize),
- }
+ new Dimension(GridSizeMode.AutoSize),
}
}
}
}
- },
- new OsuSpriteText
- {
- Anchor = Anchor.BottomCentre,
- Origin = Anchor.BottomCentre,
- Font = OsuFont.GetFont(size: 10, weight: FontWeight.SemiBold),
- Text = $"Played on {score.Date.ToLocalTime():d MMMM yyyy HH:mm}"
}
- };
+ });
+
+ if (score.Date != default)
+ AddInternal(new PlayedOnText(score.Date));
if (score.Mods.Any())
{
@@ -276,5 +270,16 @@ namespace osu.Game.Screens.Ranking.Expanded
FinishTransforms(true);
});
}
+
+ public class PlayedOnText : OsuSpriteText
+ {
+ public PlayedOnText(DateTimeOffset time)
+ {
+ Anchor = Anchor.BottomCentre;
+ Origin = Anchor.BottomCentre;
+ Font = OsuFont.GetFont(size: 10, weight: FontWeight.SemiBold);
+ Text = $"Played on {time.ToLocalTime():d MMMM yyyy HH:mm}";
+ }
+ }
}
}