1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 15:07:44 +08:00

Merge branch 'master' into catcher-area-catcher

This commit is contained in:
Dean Herbert 2021-07-21 18:00:35 +09:00
commit 6effa24157
11 changed files with 251 additions and 192 deletions

View File

@ -0,0 +1,7 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Dual client test" type="CompoundRunConfigurationType">
<toRun name="osu!" type="DotNetProject" />
<toRun name="osu! (Second Client)" type="DotNetProject" />
<method v="2" />
</configuration>
</component>

View File

@ -0,0 +1,20 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="osu! (Second Client)" type="DotNetProject" factoryName=".NET Project" folderName="osu!" activateToolWindowBeforeRun="false">
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/net5.0/osu!.dll" />
<option name="PROGRAM_PARAMETERS" value="--debug-client-id=1" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/net5.0" />
<option name="PASS_PARENT_ENVS" value="1" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
<option name="RUNTIME_ARGUMENTS" value="" />
<option name="PROJECT_PATH" value="$PROJECT_DIR$/osu.Desktop/osu.Desktop.csproj" />
<option name="PROJECT_EXE_PATH_TRACKING" value="1" />
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value="net5.0" />
<method v="2">
<option name="Build" />
</method>
</configuration>
</component>

View File

@ -3,7 +3,6 @@
using System; using System;
using System.IO; using System.IO;
using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using osu.Framework; using osu.Framework;
@ -17,13 +16,43 @@ namespace osu.Desktop
{ {
public static class Program public static class Program
{ {
private const string base_game_name = @"osu";
[STAThread] [STAThread]
public static int Main(string[] args) public static int Main(string[] args)
{ {
// Back up the cwd before DesktopGameHost changes it // Back up the cwd before DesktopGameHost changes it
var cwd = Environment.CurrentDirectory; 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; host.ExceptionThrown += handleException;
@ -48,16 +77,10 @@ namespace osu.Desktop
return 0; return 0;
} }
switch (args.FirstOrDefault() ?? string.Empty) if (tournamentClient)
{ host.Run(new TournamentGame());
default: else
host.Run(new OsuGameDesktop(args)); host.Run(new OsuGameDesktop(args));
break;
case "--tournament":
host.Run(new TournamentGame());
break;
}
return 0; return 0;
} }

View File

@ -12,6 +12,7 @@ using osu.Framework.Testing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu;
using osu.Game.Scoring; using osu.Game.Scoring;
using osu.Game.Screens.Ranking; using osu.Game.Screens.Ranking;
@ -50,9 +51,33 @@ namespace osu.Game.Tests.Visual.Ranking
AddAssert("mapped by text not present", () => AddAssert("mapped by text not present", () =>
this.ChildrenOfType<OsuSpriteText>().All(spriteText => !containsAny(spriteText.Text.ToString(), "mapped", "by"))); this.ChildrenOfType<OsuSpriteText>().All(spriteText => !containsAny(spriteText.Text.ToString(), "mapped", "by")));
AddAssert("play time displayed", () => this.ChildrenOfType<ExpandedPanelMiddleContent.PlayedOnText>().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<ExpandedPanelMiddleContent.PlayedOnText>().Any());
}
private void showPanel(ScoreInfo score) =>
Child = new ExpandedPanelMiddleContentContainer(score);
private BeatmapInfo createTestBeatmap(User author) private BeatmapInfo createTestBeatmap(User author)
{ {

View File

@ -11,10 +11,8 @@ namespace osu.Game.Tests.Visual.UserInterface
{ {
public class TestSceneModDisplay : OsuTestScene public class TestSceneModDisplay : OsuTestScene
{ {
[TestCase(ExpansionMode.ExpandOnHover)] [Test]
[TestCase(ExpansionMode.AlwaysExpanded)] public void TestMode([Values] ExpansionMode mode)
[TestCase(ExpansionMode.AlwaysContracted)]
public void TestMode(ExpansionMode mode)
{ {
AddStep("create mod display", () => AddStep("create mod display", () =>
{ {

View File

@ -416,7 +416,6 @@ namespace osu.Game.Tests.Visual.UserInterface
{ {
Anchor = Anchor.TopRight, Anchor = Anchor.TopRight,
Origin = Anchor.TopRight, Origin = Anchor.TopRight,
AutoSizeAxes = Axes.Both,
Position = new Vector2(-5, 25), Position = new Vector2(-5, 25),
Current = { BindTarget = modSelect.SelectedMods } Current = { BindTarget = modSelect.SelectedMods }
} }

View File

@ -172,7 +172,6 @@ namespace osu.Game.Screens.Play
{ {
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre, Origin = Anchor.TopCentre,
AutoSizeAxes = Axes.Both,
Margin = new MarginPadding { Top = 20 }, Margin = new MarginPadding { Top = 20 },
Current = mods Current = mods
}, },

View File

@ -15,24 +15,26 @@ using osuTK;
namespace osu.Game.Screens.Play.HUD namespace osu.Game.Screens.Play.HUD
{ {
public class ModDisplay : Container, IHasCurrentValue<IReadOnlyList<Mod>> /// <summary>
/// Displays a single-line horizontal auto-sized flow of mods.
/// </summary>
public class ModDisplay : CompositeDrawable, IHasCurrentValue<IReadOnlyList<Mod>>
{ {
private const int fade_duration = 1000; private const int fade_duration = 1000;
public ExpansionMode ExpansionMode = ExpansionMode.ExpandOnHover; public ExpansionMode ExpansionMode = ExpansionMode.ExpandOnHover;
private readonly Bindable<IReadOnlyList<Mod>> current = new Bindable<IReadOnlyList<Mod>>(); private readonly BindableWithCurrent<IReadOnlyList<Mod>> current = new BindableWithCurrent<IReadOnlyList<Mod>>();
public Bindable<IReadOnlyList<Mod>> Current public Bindable<IReadOnlyList<Mod>> Current
{ {
get => current; get => current.Current;
set set
{ {
if (value == null) if (value == null)
throw new ArgumentNullException(nameof(value)); throw new ArgumentNullException(nameof(value));
current.UnbindBindings(); current.Current = value;
current.BindTo(value);
} }
} }
@ -42,51 +44,34 @@ namespace osu.Game.Screens.Play.HUD
{ {
AutoSizeAxes = Axes.Both; AutoSizeAxes = Axes.Both;
Child = new FillFlowContainer InternalChild = iconsContainer = new ReverseChildIDFillFlowContainer<ModIcon>
{ {
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
AutoSizeAxes = Axes.Both, AutoSizeAxes = Axes.Both,
Direction = FillDirection.Vertical, Direction = FillDirection.Horizontal,
Children = new Drawable[]
{
iconsContainer = new ReverseChildIDFillFlowContainer<ModIcon>
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
},
},
}; };
} }
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
Current.UnbindAll();
}
protected override void LoadComplete() protected override void LoadComplete()
{ {
base.LoadComplete(); base.LoadComplete();
Current.BindValueChanged(mods => Current.BindValueChanged(updateDisplay, true);
{
iconsContainer.Clear();
if (mods.NewValue != null)
{
foreach (Mod mod in mods.NewValue)
iconsContainer.Add(new ModIcon(mod) { Scale = new Vector2(0.6f) });
appearTransform();
}
}, true);
iconsContainer.FadeInFromZero(fade_duration, Easing.OutQuint); iconsContainer.FadeInFromZero(fade_duration, Easing.OutQuint);
} }
private void updateDisplay(ValueChangedEvent<IReadOnlyList<Mod>> mods)
{
iconsContainer.Clear();
if (mods.NewValue == null) return;
foreach (Mod mod in mods.NewValue)
iconsContainer.Add(new ModIcon(mod) { Scale = new Vector2(0.6f) });
appearTransform();
}
private void appearTransform() private void appearTransform()
{ {
expand(); expand();

View File

@ -282,7 +282,6 @@ namespace osu.Game.Screens.Play
{ {
Anchor = Anchor.TopRight, Anchor = Anchor.TopRight,
Origin = Anchor.TopRight, Origin = Anchor.TopRight,
AutoSizeAxes = Axes.Both,
}; };
protected PlayerSettingsOverlay CreatePlayerSettingsOverlay() => new PlayerSettingsOverlay(); protected PlayerSettingsOverlay CreatePlayerSettingsOverlay() => new PlayerSettingsOverlay();

View File

@ -135,7 +135,6 @@ namespace osu.Game.Screens.Ranking.Contracted
{ {
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre, Origin = Anchor.TopCentre,
AutoSizeAxes = Axes.Both,
ExpansionMode = ExpansionMode.AlwaysExpanded, ExpansionMode = ExpansionMode.AlwaysExpanded,
Current = { Value = score.Mods }, Current = { Value = score.Mods },
Scale = new Vector2(0.5f), Scale = new Vector2(0.5f),

View File

@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
@ -79,162 +80,155 @@ namespace osu.Game.Screens.Ranking.Expanded
var starDifficulty = beatmapDifficultyCache.GetDifficultyAsync(beatmap, score.Ruleset, score.Mods).Result; 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, new FillFlowContainer
Direction = FillDirection.Vertical,
Spacing = new Vector2(20),
Children = new Drawable[]
{ {
new FillFlowContainer Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Children = new Drawable[]
{ {
Anchor = Anchor.TopCentre, new OsuSpriteText
Origin = Anchor.TopCentre,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Children = new Drawable[]
{ {
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, Anchor = Anchor.Centre,
Origin = Anchor.TopCentre, Origin = Anchor.Centre,
Text = new RomanisableString(metadata.TitleUnicode, metadata.Title), RelativeSizeAxes = Axes.Both,
Font = OsuFont.Torus.With(size: 20, weight: FontWeight.SemiBold), FillMode = FillMode.Fit,
MaxWidth = ScorePanel.EXPANDED_WIDTH - padding * 2, }
Truncate = true, },
}, scoreCounter = new TotalScoreCounter
new OsuSpriteText {
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, new StarRatingDisplay(starDifficulty)
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.Centre, Anchor = Anchor.CentreLeft,
Origin = Anchor.Centre, Origin = Anchor.CentreLeft
RelativeSizeAxes = Axes.Both, },
FillMode = FillMode.Fit, }
} },
}, new FillFlowContainer
scoreCounter = new TotalScoreCounter {
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Direction = FillDirection.Vertical,
AutoSizeAxes = Axes.Both,
Children = new Drawable[]
{ {
Margin = new MarginPadding { Top = 0, Bottom = 5 }, new OsuSpriteText
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 StarRatingDisplay(starDifficulty) Anchor = Anchor.TopCentre,
{ Origin = Anchor.TopCentre,
Anchor = Anchor.CentreLeft, Text = beatmap.Version,
Origin = Anchor.CentreLeft Font = OsuFont.Torus.With(size: 16, weight: FontWeight.SemiBold),
}, },
} new OsuTextFlowContainer(s => s.Font = OsuFont.Torus.With(size: 12))
},
new FillFlowContainer
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Direction = FillDirection.Vertical,
AutoSizeAxes = Axes.Both,
Children = new Drawable[]
{ {
new OsuSpriteText Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
}.With(t =>
{
if (!string.IsNullOrEmpty(creator))
{ {
Anchor = Anchor.TopCentre, t.AddText("mapped by ");
Origin = Anchor.TopCentre, t.AddText(creator, s => s.Font = s.Font.With(weight: FontWeight.SemiBold));
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, new FillFlowContainer
AutoSizeAxes = Axes.Both, {
Direction = FillDirection.Horizontal, RelativeSizeAxes = Axes.X,
}.With(t => AutoSizeAxes = Axes.Y,
{ Direction = FillDirection.Vertical,
if (!string.IsNullOrEmpty(creator)) Spacing = new Vector2(0, 5),
{ Children = new Drawable[]
t.AddText("mapped by ");
t.AddText(creator, s => s.Font = s.Font.With(weight: FontWeight.SemiBold));
}
})
}
},
}
},
new FillFlowContainer
{ {
RelativeSizeAxes = Axes.X, new GridContainer
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 5),
Children = new Drawable[]
{ {
new GridContainer RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Content = new[] { topStatistics.Cast<Drawable>().ToArray() },
RowDimensions = new[]
{ {
RelativeSizeAxes = Axes.X, new Dimension(GridSizeMode.AutoSize),
AutoSizeAxes = Axes.Y, }
Content = new[] { topStatistics.Cast<Drawable>().ToArray() }, },
RowDimensions = new[] new GridContainer
{ {
new Dimension(GridSizeMode.AutoSize), RelativeSizeAxes = Axes.X,
} AutoSizeAxes = Axes.Y,
}, Content = new[] { bottomStatistics.Where(s => s.Result <= HitResult.Perfect).ToArray() },
new GridContainer RowDimensions = new[]
{ {
RelativeSizeAxes = Axes.X, new Dimension(GridSizeMode.AutoSize),
AutoSizeAxes = Axes.Y, }
Content = new[] { bottomStatistics.Where(s => s.Result <= HitResult.Perfect).ToArray() }, },
RowDimensions = new[] new GridContainer
{ {
new Dimension(GridSizeMode.AutoSize), RelativeSizeAxes = Axes.X,
} AutoSizeAxes = Axes.Y,
}, Content = new[] { bottomStatistics.Where(s => s.Result > HitResult.Perfect).ToArray() },
new GridContainer RowDimensions = new[]
{ {
RelativeSizeAxes = Axes.X, new Dimension(GridSizeMode.AutoSize),
AutoSizeAxes = Axes.Y,
Content = new[] { bottomStatistics.Where(s => s.Result > HitResult.Perfect).ToArray() },
RowDimensions = new[]
{
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()) if (score.Mods.Any())
{ {
@ -276,5 +270,16 @@ namespace osu.Game.Screens.Ranking.Expanded
FinishTransforms(true); 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}";
}
}
} }
} }