1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 16:27:26 +08:00

Merge branch 'master' into playlist-empty-romanised

This commit is contained in:
Dan Balasescu 2021-07-05 10:20:33 +09:00 committed by GitHub
commit 5f10edee39
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 254 additions and 165 deletions

View File

@ -5,8 +5,8 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Description>A free-to-win rhythm game. Rhythm is just a *click* away!</Description>
<AssemblyName>osu!</AssemblyName>
<Title>osu!lazer</Title>
<Product>osu!lazer</Product>
<Title>osu!</Title>
<Product>osu!</Product>
<ApplicationIcon>lazer.ico</ApplicationIcon>
<ApplicationManifest>app.manifest</ApplicationManifest>
<Version>0.0.0</Version>

View File

@ -3,7 +3,7 @@
<metadata>
<id>osulazer</id>
<version>0.0.0</version>
<title>osu!lazer</title>
<title>osu!</title>
<authors>ppy Pty Ltd</authors>
<owners>Dean Herbert</owners>
<projectUrl>https://osu.ppy.sh/</projectUrl>
@ -20,4 +20,3 @@
<file src="**.config" target="lib\net45\"/>
</files>
</package>

View File

@ -194,9 +194,9 @@ namespace osu.Game.Rulesets.Catch.Tests
AddStep("catch more fruits", () => attemptCatch(() => new Fruit(), 9));
checkPlate(10);
AddAssert("caught objects are stacked", () =>
catcher.CaughtObjects.All(obj => obj.Y <= Catcher.CAUGHT_FRUIT_VERTICAL_OFFSET) &&
catcher.CaughtObjects.Any(obj => obj.Y == Catcher.CAUGHT_FRUIT_VERTICAL_OFFSET) &&
catcher.CaughtObjects.Any(obj => obj.Y < -25));
catcher.CaughtObjects.All(obj => obj.Y <= 0) &&
catcher.CaughtObjects.Any(obj => obj.Y == 0) &&
catcher.CaughtObjects.Any(obj => obj.Y < 0));
}
[Test]

View File

@ -56,11 +56,6 @@ namespace osu.Game.Rulesets.Catch.UI
/// </summary>
public double Speed => (Dashing ? 1 : 0.5) * BASE_SPEED * hyperDashModifier;
/// <summary>
/// The amount by which caught fruit should be offset from the plate surface to make them look visually "caught".
/// </summary>
public const float CAUGHT_FRUIT_VERTICAL_OFFSET = -5;
/// <summary>
/// The amount by which caught fruit should be scaled down to fit on the plate.
/// </summary>
@ -157,6 +152,8 @@ namespace osu.Game.Rulesets.Catch.UI
{
Anchor = Anchor.TopCentre,
Origin = Anchor.BottomCentre,
// offset fruit vertically to better place "above" the plate.
Y = -5
},
body = new SkinnableCatcher(),
hitExplosionContainer = new HitExplosionContainer
@ -388,9 +385,6 @@ namespace osu.Game.Rulesets.Catch.UI
float adjustedRadius = displayRadius * lenience_adjust;
float checkDistance = MathF.Pow(adjustedRadius, 2);
// offset fruit vertically to better place "above" the plate.
position.Y += CAUGHT_FRUIT_VERTICAL_OFFSET;
while (caughtObjectContainer.Any(f => Vector2Extensions.DistanceSquared(f.Position, position) < checkDistance))
{
position.X += RNG.NextSingle(-adjustedRadius, adjustedRadius);

View File

@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
/// <remarks>
/// All constants are in osu!stable's gamefield space, which is shifted 16px downwards.
/// This offset is negated in both osu!stable and osu!lazer to bring all constants into window-space.
/// This offset is negated to bring all constants into window-space.
/// Note: SPINNER_Y_CENTRE + SPINNER_TOP_OFFSET - Position.Y = 240 (=480/2, or half the window-space in osu!stable)
/// </remarks>
protected const float SPINNER_TOP_OFFSET = 45f - 16f;

View File

@ -9,6 +9,8 @@ using osu.Game.Online.Rooms;
using osu.Game.Online.Solo;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu.Judgements;
using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Ranking;
namespace osu.Game.Tests.Visual.Gameplay
@ -35,6 +37,9 @@ namespace osu.Game.Tests.Visual.Gameplay
AddUntilStep("wait for token request", () => Player.TokenCreationRequested);
AddUntilStep("wait for track to start running", () => Beatmap.Value.Track.IsRunning);
addFakeHit();
AddStep("seek to completion", () => Player.GameplayClockContainer.Seek(Player.DrawableRuleset.Objects.Last().GetEndTime()));
AddUntilStep("results displayed", () => Player.GetChildScreen() is ResultsScreen);
@ -52,6 +57,9 @@ namespace osu.Game.Tests.Visual.Gameplay
AddUntilStep("wait for token request", () => Player.TokenCreationRequested);
AddUntilStep("wait for track to start running", () => Beatmap.Value.Track.IsRunning);
addFakeHit();
AddStep("seek to completion", () => Player.GameplayClockContainer.Seek(Player.DrawableRuleset.Objects.Last().GetEndTime()));
AddUntilStep("results displayed", () => Player.GetChildScreen() is ResultsScreen);
@ -67,10 +75,29 @@ namespace osu.Game.Tests.Visual.Gameplay
AddUntilStep("wait for token request", () => Player.TokenCreationRequested);
AddUntilStep("wait for track to start running", () => Beatmap.Value.Track.IsRunning);
addFakeHit();
AddStep("exit", () => Player.Exit());
AddAssert("ensure no submission", () => Player.SubmittedScore == null);
}
[Test]
public void TestNoSubmissionOnEmptyFail()
{
prepareTokenResponse(true);
CreateTest(() => allowFail = true);
AddUntilStep("wait for token request", () => Player.TokenCreationRequested);
AddUntilStep("wait for fail", () => Player.HasFailed);
AddStep("exit", () => Player.Exit());
AddAssert("ensure no submission", () => Player.SubmittedScore == null);
}
[Test]
public void TestSubmissionOnFail()
{
@ -79,12 +106,28 @@ namespace osu.Game.Tests.Visual.Gameplay
CreateTest(() => allowFail = true);
AddUntilStep("wait for token request", () => Player.TokenCreationRequested);
addFakeHit();
AddUntilStep("wait for fail", () => Player.HasFailed);
AddStep("exit", () => Player.Exit());
AddAssert("ensure failing submission", () => Player.SubmittedScore?.ScoreInfo.Passed == false);
}
[Test]
public void TestNoSubmissionOnEmptyExit()
{
prepareTokenResponse(true);
CreateTest(() => allowFail = false);
AddUntilStep("wait for token request", () => Player.TokenCreationRequested);
AddStep("exit", () => Player.Exit());
AddAssert("ensure no submission", () => Player.SubmittedScore == null);
}
[Test]
public void TestSubmissionOnExit()
{
@ -93,10 +136,27 @@ namespace osu.Game.Tests.Visual.Gameplay
CreateTest(() => allowFail = false);
AddUntilStep("wait for token request", () => Player.TokenCreationRequested);
addFakeHit();
AddStep("exit", () => Player.Exit());
AddAssert("ensure failing submission", () => Player.SubmittedScore?.ScoreInfo.Passed == false);
}
private void addFakeHit()
{
AddUntilStep("wait for first result", () => Player.Results.Count > 0);
AddStep("force successfuly hit", () =>
{
Player.ScoreProcessor.RevertResult(Player.Results.First());
Player.ScoreProcessor.ApplyResult(new OsuJudgementResult(Beatmap.Value.Beatmap.HitObjects.First(), new OsuJudgement())
{
Type = HitResult.Great,
});
});
}
private void prepareTokenResponse(bool validToken)
{
AddStep("Prepare test API", () =>

View File

@ -39,7 +39,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Version = "All Metrics",
Metadata = new BeatmapMetadata
{
Source = "osu!lazer",
Source = "osu!",
Tags = "this beatmap has all the metrics",
},
BaseDifficulty = new BeatmapDifficulty
@ -100,7 +100,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Version = "Only Ratings",
Metadata = new BeatmapMetadata
{
Source = "osu!lazer",
Source = "osu!",
Tags = "this beatmap has ratings metrics but not retries or fails",
},
BaseDifficulty = new BeatmapDifficulty
@ -122,7 +122,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Version = "Only Retries and Fails",
Metadata = new BeatmapMetadata
{
Source = "osu!lazer",
Source = "osu!",
Tags = "this beatmap has retries and fails but no ratings",
},
BaseDifficulty = new BeatmapDifficulty
@ -149,7 +149,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Version = "No Metrics",
Metadata = new BeatmapMetadata
{
Source = "osu!lazer",
Source = "osu!",
Tags = "this beatmap has no metrics",
},
BaseDifficulty = new BeatmapDifficulty

View File

@ -320,6 +320,7 @@ namespace osu.Game.Online.Chat
JoinMultiplayerMatch,
Spectate,
OpenUserProfile,
SearchBeatmapSet,
OpenWiki,
Custom,
}

View File

@ -305,6 +305,10 @@ namespace osu.Game
ShowChannel(link.Argument);
break;
case LinkAction.SearchBeatmapSet:
SearchBeatmapSet(link.Argument);
break;
case LinkAction.OpenEditorTimestamp:
case LinkAction.JoinMultiplayerMatch:
case LinkAction.Spectate:
@ -375,6 +379,12 @@ namespace osu.Game
/// <param name="beatmapId">The beatmap to show.</param>
public void ShowBeatmap(int beatmapId) => waitForReady(() => beatmapSetOverlay, _ => beatmapSetOverlay.FetchAndShowBeatmap(beatmapId));
/// <summary>
/// Shows the beatmap listing overlay, with the given <paramref name="query"/> in the search box.
/// </summary>
/// <param name="query">The query to search for.</param>
public void SearchBeatmapSet(string query) => waitForReady(() => beatmapListing, _ => beatmapListing.ShowWithSearch(query));
/// <summary>
/// Show a wiki's page as an overlay
/// </summary>

View File

@ -80,7 +80,7 @@ namespace osu.Game
return @"local " + (DebugUtils.IsDebugBuild ? @"debug" : @"release");
var version = AssemblyVersion;
return $@"{version.Major}.{version.Minor}.{version.Build}";
return $@"{version.Major}.{version.Minor}.{version.Build}-lazer";
}
}
@ -162,7 +162,7 @@ namespace osu.Game
public OsuGameBase()
{
UseDevelopmentServer = DebugUtils.IsDebugBuild;
Name = @"osu!lazer";
Name = @"osu!";
}
[BackgroundDependencyLoader]

View File

@ -122,6 +122,9 @@ namespace osu.Game.Overlays.BeatmapListing
sortControlBackground.Colour = colourProvider.Background5;
}
public void Search(string query)
=> searchControl.Query.Value = query;
protected override void LoadComplete()
{
base.LoadComplete();

View File

@ -89,6 +89,12 @@ namespace osu.Game.Overlays
};
}
public void ShowWithSearch(string query)
{
filterControl.Search(query);
Show();
}
protected override BeatmapListingHeader CreateHeader() => new BeatmapListingHeader();
protected override Color4 BackgroundColour => ColourProvider.Background6;

View File

@ -8,15 +8,12 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osuTK;
namespace osu.Game.Overlays.BeatmapSet
{
public class Info : Container
{
private const float transition_duration = 250;
private const float metadata_width = 175;
private const float spacing = 20;
private const float base_height = 220;
@ -60,7 +57,7 @@ namespace osu.Game.Overlays.BeatmapSet
Child = new Container
{
RelativeSizeAxes = Axes.Both,
Child = new MetadataSection("Description"),
Child = new MetadataSection(MetadataType.Description),
},
},
new Container
@ -78,10 +75,10 @@ namespace osu.Game.Overlays.BeatmapSet
Direction = FillDirection.Full,
Children = new[]
{
source = new MetadataSection("Source"),
genre = new MetadataSection("Genre") { Width = 0.5f },
language = new MetadataSection("Language") { Width = 0.5f },
tags = new MetadataSection("Tags"),
source = new MetadataSection(MetadataType.Source),
genre = new MetadataSection(MetadataType.Genre) { Width = 0.5f },
language = new MetadataSection(MetadataType.Language) { Width = 0.5f },
tags = new MetadataSection(MetadataType.Tags),
},
},
},
@ -135,48 +132,5 @@ namespace osu.Game.Overlays.BeatmapSet
successRateBackground.Colour = colourProvider.Background4;
background.Colour = colourProvider.Background5;
}
private class MetadataSection : FillFlowContainer
{
private readonly TextFlowContainer textFlow;
public string Text
{
set
{
if (string.IsNullOrEmpty(value))
{
Hide();
return;
}
this.FadeIn(transition_duration);
textFlow.Clear();
textFlow.AddText(value, s => s.Font = s.Font.With(size: 12));
}
}
public MetadataSection(string title)
{
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
Spacing = new Vector2(5f);
InternalChildren = new Drawable[]
{
new OsuSpriteText
{
Text = title,
Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold),
Margin = new MarginPadding { Top = 15 },
},
textFlow = new OsuTextFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
},
};
}
}
}
}

View File

@ -0,0 +1,115 @@
// 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.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Online.Chat;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Overlays.BeatmapSet
{
public class MetadataSection : Container
{
private readonly FillFlowContainer textContainer;
private readonly MetadataType type;
private TextFlowContainer textFlow;
private const float transition_duration = 250;
public MetadataSection(MetadataType type)
{
this.type = type;
Alpha = 0;
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
InternalChild = textContainer = new FillFlowContainer
{
Alpha = 0,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Margin = new MarginPadding { Top = 15 },
Spacing = new Vector2(5),
Children = new Drawable[]
{
new Container
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Child = new OsuSpriteText
{
Text = this.type.ToString(),
Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 14),
},
},
},
};
}
public string Text
{
set
{
if (string.IsNullOrEmpty(value))
{
this.FadeOut(transition_duration);
return;
}
this.FadeIn(transition_duration);
setTextAsync(value);
}
}
private void setTextAsync(string text)
{
LoadComponentAsync(new LinkFlowContainer(s => s.Font = s.Font.With(size: 14))
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Colour = Color4.White.Opacity(0.75f),
}, loaded =>
{
textFlow?.Expire();
switch (type)
{
case MetadataType.Tags:
string[] tags = text.Split(" ");
for (int i = 0; i <= tags.Length - 1; i++)
{
loaded.AddLink(tags[i], LinkAction.SearchBeatmapSet, tags[i]);
if (i != tags.Length - 1)
loaded.AddText(" ");
}
break;
case MetadataType.Source:
loaded.AddLink(text, LinkAction.SearchBeatmapSet, text);
break;
default:
loaded.AddText(text);
break;
}
textContainer.Add(textFlow = loaded);
// fade in if we haven't yet.
textContainer.FadeIn(transition_duration);
});
}
}
}

View File

@ -0,0 +1,14 @@
// 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.
namespace osu.Game.Overlays.BeatmapSet
{
public enum MetadataType
{
Tags,
Source,
Description,
Genre,
Language
}
}

View File

@ -191,7 +191,7 @@ namespace osu.Game.Overlays.Volume
bgProgress.Current.Value = 0.75f;
}
private int displayVolumeInt;
private int? displayVolumeInt;
private double displayVolume;
@ -200,9 +200,6 @@ namespace osu.Game.Overlays.Volume
get => displayVolume;
set
{
if (value == displayVolume)
return;
displayVolume = value;
int intValue = (int)Math.Round(displayVolume * 100);
@ -218,7 +215,7 @@ namespace osu.Game.Overlays.Volume
else
{
maxGlow.EffectColour = Color4.Transparent;
text.Text = displayVolumeInt.ToString(CultureInfo.CurrentCulture);
text.Text = intValue.ToString(CultureInfo.CurrentCulture);
}
volumeCircle.Current.Value = displayVolume * 0.75f;

View File

@ -208,7 +208,7 @@ namespace osu.Game.Scoring
}
else
{
// This score is guaranteed to be an osu!lazer score.
// This is guaranteed to be a non-legacy score.
// The combo must be determined through the score's statistics, as both the beatmap's max combo and the difficulty calculator will provide osu!stable combo values.
beatmapMaxCombo = Enum.GetValues(typeof(HitResult)).OfType<HitResult>().Where(r => r.AffectsCombo()).Select(r => score.Statistics.GetOrDefault(r)).Sum();
}

View File

@ -230,7 +230,7 @@ namespace osu.Game.Screens.Menu
"New features are coming online every update. Make sure to stay up-to-date!",
"If you find the UI too large or small, try adjusting UI scale in settings!",
"Try adjusting the \"Screen Scaling\" mode to change your gameplay or UI area, even in fullscreen!",
"For now, what used to be \"osu!direct\" is available to all users on lazer. You can access it anywhere using Ctrl-D!",
"What used to be \"osu!direct\" is available to all users just like on the website. You can access it anywhere using Ctrl-D!",
"Seeking in replays is available by dragging on the difficulty bar at the bottom of the screen!",
"Multithreading support means that even with low \"FPS\" your input and judgements will be accurate!",
"Try scrolling down in the mod select panel to find a bunch of new fun mods!",

View File

@ -10,6 +10,7 @@ using osu.Framework.Logging;
using osu.Framework.Screens;
using osu.Game.Online.API;
using osu.Game.Online.Rooms;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
namespace osu.Game.Screens.Play
@ -144,6 +145,10 @@ namespace osu.Game.Screens.Play
if (scoreSubmissionSource != null)
return scoreSubmissionSource.Task;
// if the user never hit anything, this score should not be counted in any way.
if (!score.ScoreInfo.Statistics.Any(s => s.Key.IsHit() && s.Value > 0))
return Task.CompletedTask;
scoreSubmissionSource = new TaskCompletionSource<bool>();
var request = CreateSubmissionRequest(score, token.Value);

View File

@ -1,24 +1,25 @@
// 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 osuTK;
using osuTK.Graphics;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using System.Linq;
using osu.Game.Online.API;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Extensions.Color4Extensions;
using osu.Game.Screens.Select.Details;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API.Requests;
using osu.Game.Rulesets;
using osu.Game.Online;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Overlays.BeatmapSet;
using osu.Game.Rulesets;
using osu.Game.Screens.Select.Details;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Screens.Select
{
@ -128,13 +129,11 @@ namespace osu.Game.Screens.Select
AutoSizeAxes = Axes.Y,
LayoutDuration = transition_duration,
LayoutEasing = Easing.OutQuad,
Spacing = new Vector2(spacing * 2),
Margin = new MarginPadding { Top = spacing * 2 },
Children = new[]
{
description = new MetadataSection("Description"),
source = new MetadataSection("Source"),
tags = new MetadataSection("Tags"),
description = new MetadataSection(MetadataType.Description),
source = new MetadataSection(MetadataType.Source),
tags = new MetadataSection(MetadataType.Tags),
},
},
},
@ -290,73 +289,5 @@ namespace osu.Game.Screens.Select
};
}
}
private class MetadataSection : Container
{
private readonly FillFlowContainer textContainer;
private TextFlowContainer textFlow;
public MetadataSection(string title)
{
Alpha = 0;
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
InternalChild = textContainer = new FillFlowContainer
{
Alpha = 0,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Spacing = new Vector2(spacing / 2),
Children = new Drawable[]
{
new Container
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Child = new OsuSpriteText
{
Text = title,
Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 14),
},
},
},
};
}
public string Text
{
set
{
if (string.IsNullOrEmpty(value))
{
this.FadeOut(transition_duration);
return;
}
this.FadeIn(transition_duration);
setTextAsync(value);
}
}
private void setTextAsync(string text)
{
LoadComponentAsync(new OsuTextFlowContainer(s => s.Font = s.Font.With(size: 14))
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Colour = Color4.White.Opacity(0.75f),
Text = text
}, loaded =>
{
textFlow?.Expire();
textContainer.Add(textFlow = loaded);
// fade in if we haven't yet.
textContainer.FadeIn(transition_duration);
});
}
}
}
}

View File

@ -7,7 +7,7 @@ using osuTK.Graphics;
namespace osu.Game.Skinning
{
/// <summary>
/// Compatibility methods to convert osu!stable colours to osu!lazer-compatible ones. Should be used for legacy skins only.
/// Compatibility methods to apply osu!stable quirks to colours. Should be used for legacy skins only.
/// </summary>
public static class LegacyColourCompatibility
{

View File

@ -46,7 +46,7 @@ namespace osu.Game.Skinning
public static SkinInfo Default { get; } = new SkinInfo
{
ID = DEFAULT_SKIN,
Name = "osu!lazer",
Name = "osu! (triangles)",
Creator = "team osu!",
InstantiationInfo = typeof(DefaultSkin).GetInvariantInstantiationInfo()
};

View File

@ -90,7 +90,7 @@ namespace osu.Game.Updater
public UpdateCompleteNotification(string version)
{
this.version = version;
Text = $"You are now running osu!lazer {version}.\nClick to see what's new!";
Text = $"You are now running osu! {version}.\nClick to see what's new!";
}
[BackgroundDependencyLoader]