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

Merge branch 'master' into beatmap-refactor/playlist-use-api-beatmap-extended

This commit is contained in:
Dan Balasescu 2021-11-04 18:59:04 +09:00 committed by GitHub
commit 45dcf187b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 94 additions and 55 deletions

View File

@ -15,7 +15,7 @@
] ]
}, },
"smoogipoo.nvika": { "smoogipoo.nvika": {
"version": "1.0.3", "version": "1.0.4",
"commands": [ "commands": [
"nvika" "nvika"
] ]

View File

@ -673,6 +673,8 @@ namespace osu.Game.Tests.Beatmaps.Formats
Assert.That(first.ControlPoints[1].Position, Is.EqualTo(new Vector2(161, -244))); Assert.That(first.ControlPoints[1].Position, Is.EqualTo(new Vector2(161, -244)));
Assert.That(first.ControlPoints[1].Type, Is.EqualTo(null)); Assert.That(first.ControlPoints[1].Type, Is.EqualTo(null));
// ReSharper disable once HeuristicUnreachableCode
// weird one, see https://youtrack.jetbrains.com/issue/RIDER-70159.
Assert.That(first.ControlPoints[2].Position, Is.EqualTo(new Vector2(376, -3))); Assert.That(first.ControlPoints[2].Position, Is.EqualTo(new Vector2(376, -3)));
Assert.That(first.ControlPoints[2].Type, Is.EqualTo(PathType.Bezier)); Assert.That(first.ControlPoints[2].Type, Is.EqualTo(PathType.Bezier));
Assert.That(first.ControlPoints[3].Position, Is.EqualTo(new Vector2(68, 15))); Assert.That(first.ControlPoints[3].Position, Is.EqualTo(new Vector2(68, 15)));

View File

@ -35,7 +35,7 @@ namespace osu.Game.Tests.Editing.Checks
public void TestMissing() public void TestMissing()
{ {
// While this is a problem, it is out of scope for this check and is caught by a different one. // While this is a problem, it is out of scope for this check and is caught by a different one.
beatmap.Metadata.AudioFile = null; beatmap.Metadata.AudioFile = string.Empty;
var mock = new Mock<IWorkingBeatmap>(); var mock = new Mock<IWorkingBeatmap>();
mock.SetupGet(w => w.Beatmap).Returns(beatmap); mock.SetupGet(w => w.Beatmap).Returns(beatmap);

View File

@ -53,7 +53,7 @@ namespace osu.Game.Tests.Editing.Checks
public void TestMissing() public void TestMissing()
{ {
// While this is a problem, it is out of scope for this check and is caught by a different one. // While this is a problem, it is out of scope for this check and is caught by a different one.
beatmap.Metadata.BackgroundFile = null; beatmap.Metadata.BackgroundFile = string.Empty;
var context = getContext(null, System.Array.Empty<byte>()); var context = getContext(null, System.Array.Empty<byte>());
Assert.That(check.Run(context), Is.Empty); Assert.That(check.Run(context), Is.Empty);

View File

@ -65,7 +65,7 @@ namespace osu.Game.Tests.Editing.Checks
[Test] [Test]
public void TestBackgroundNotSet() public void TestBackgroundNotSet()
{ {
beatmap.Metadata.BackgroundFile = null; beatmap.Metadata.BackgroundFile = string.Empty;
var context = new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap)); var context = new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap));
var issues = check.Run(context).ToList(); var issues = check.Run(context).ToList();

View File

@ -189,7 +189,7 @@ namespace osu.Game.Tests.NonVisual.Filtering
public void TestCriteriaMatchingArtistWithNullUnicodeName(string artistName, bool filtered) public void TestCriteriaMatchingArtistWithNullUnicodeName(string artistName, bool filtered)
{ {
var exampleBeatmapInfo = getExampleBeatmap(); var exampleBeatmapInfo = getExampleBeatmap();
exampleBeatmapInfo.Metadata.ArtistUnicode = null; exampleBeatmapInfo.Metadata.ArtistUnicode = string.Empty;
var criteria = new FilterCriteria var criteria = new FilterCriteria
{ {

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 Newtonsoft.Json; using Newtonsoft.Json;
using NUnit.Framework; using NUnit.Framework;
@ -67,9 +68,11 @@ namespace osu.Game.Tests.Online
var deserialised = JsonConvert.DeserializeObject<APIMod>(JsonConvert.SerializeObject(apiMod)); var deserialised = JsonConvert.DeserializeObject<APIMod>(JsonConvert.SerializeObject(apiMod));
var converted = (TestModTimeRamp)deserialised?.ToMod(new TestRuleset()); var converted = (TestModTimeRamp)deserialised?.ToMod(new TestRuleset());
Assert.That(converted?.AdjustPitch.Value, Is.EqualTo(false)); Assert.That(converted, Is.Not.Null);
Assert.That(converted?.InitialRate.Value, Is.EqualTo(1.25));
Assert.That(converted?.FinalRate.Value, Is.EqualTo(0.25)); Assert.That(converted.AdjustPitch.Value, Is.EqualTo(false));
Assert.That(converted.InitialRate.Value, Is.EqualTo(1.25));
Assert.That(converted.FinalRate.Value, Is.EqualTo(0.25));
} }
[Test] [Test]
@ -121,11 +124,11 @@ namespace osu.Game.Tests.Online
new TestModDifficultyAdjust() new TestModDifficultyAdjust()
}; };
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null) => throw new System.NotImplementedException(); public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null) => throw new NotImplementedException();
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => throw new System.NotImplementedException(); public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => throw new NotImplementedException();
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => throw new System.NotImplementedException(); public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => throw new NotImplementedException();
public override string Description { get; } = string.Empty; public override string Description { get; } = string.Empty;
public override string ShortName { get; } = string.Empty; public override string ShortName { get; } = string.Empty;

View File

@ -5,7 +5,10 @@ using System;
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Testing; using osu.Framework.Testing;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Graphics.UserInterface;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu;
@ -29,6 +32,9 @@ namespace osu.Game.Tests.Visual.Editing
private ComposeBlueprintContainer blueprintContainer private ComposeBlueprintContainer blueprintContainer
=> Editor.ChildrenOfType<ComposeBlueprintContainer>().First(); => Editor.ChildrenOfType<ComposeBlueprintContainer>().First();
private ContextMenuContainer contextMenuContainer
=> Editor.ChildrenOfType<ContextMenuContainer>().First();
private void moveMouseToObject(Func<HitObject> targetFunc) private void moveMouseToObject(Func<HitObject> targetFunc)
{ {
AddStep("move mouse to object", () => AddStep("move mouse to object", () =>
@ -42,6 +48,19 @@ namespace osu.Game.Tests.Visual.Editing
}); });
} }
[Test]
public void TestSelectAndShowContextMenu()
{
var addedObject = new HitCircle { StartTime = 100, Position = new Vector2(100, 100) };
AddStep("add hitobject", () => EditorBeatmap.Add(addedObject));
moveMouseToObject(() => addedObject);
AddStep("right click", () => InputManager.Click(MouseButton.Right));
AddUntilStep("hitobject selected", () => EditorBeatmap.SelectedHitObjects.Single() == addedObject);
AddUntilStep("context menu is visible", () => contextMenuContainer.ChildrenOfType<OsuContextMenu>().Single().State == MenuState.Open);
}
[Test] [Test]
public void TestNudgeSelection() public void TestNudgeSelection()
{ {

View File

@ -23,10 +23,10 @@ namespace osu.Game.Tests.Visual.Editing
AddStep("set metadata", () => AddStep("set metadata", () =>
{ {
editorBeatmap.Metadata.Artist = "Example Artist"; editorBeatmap.Metadata.Artist = "Example Artist";
editorBeatmap.Metadata.ArtistUnicode = null; editorBeatmap.Metadata.ArtistUnicode = string.Empty;
editorBeatmap.Metadata.Title = "Example Title"; editorBeatmap.Metadata.Title = "Example Title";
editorBeatmap.Metadata.TitleUnicode = null; editorBeatmap.Metadata.TitleUnicode = string.Empty;
}); });
createSection(); createSection();
@ -44,10 +44,10 @@ namespace osu.Game.Tests.Visual.Editing
AddStep("set metadata", () => AddStep("set metadata", () =>
{ {
editorBeatmap.Metadata.ArtistUnicode = "*なみりん"; editorBeatmap.Metadata.ArtistUnicode = "*なみりん";
editorBeatmap.Metadata.Artist = null; editorBeatmap.Metadata.Artist = string.Empty;
editorBeatmap.Metadata.TitleUnicode = "コイシテイク・プラネット"; editorBeatmap.Metadata.TitleUnicode = "コイシテイク・プラネット";
editorBeatmap.Metadata.Title = null; editorBeatmap.Metadata.Title = string.Empty;
}); });
createSection(); createSection();
@ -86,10 +86,10 @@ namespace osu.Game.Tests.Visual.Editing
AddStep("set metadata", () => AddStep("set metadata", () =>
{ {
editorBeatmap.Metadata.ArtistUnicode = "*なみりん"; editorBeatmap.Metadata.ArtistUnicode = "*なみりん";
editorBeatmap.Metadata.Artist = null; editorBeatmap.Metadata.Artist = string.Empty;
editorBeatmap.Metadata.TitleUnicode = "コイシテイク・プラネット"; editorBeatmap.Metadata.TitleUnicode = "コイシテイク・プラネット";
editorBeatmap.Metadata.Title = null; editorBeatmap.Metadata.Title = string.Empty;
}); });
createSection(); createSection();

View File

@ -54,7 +54,7 @@ namespace osu.Game.Tests.Visual.Gameplay
ScoreInfo = { BeatmapInfo = gameplayState.Beatmap.BeatmapInfo } ScoreInfo = { BeatmapInfo = gameplayState.Beatmap.BeatmapInfo }
}) })
{ {
ScreenSpaceToGamefield = pos => recordingManager.ToLocalSpace(pos) ScreenSpaceToGamefield = pos => recordingManager?.ToLocalSpace(pos) ?? Vector2.Zero,
}, },
Child = new Container Child = new Container
{ {
@ -84,7 +84,7 @@ namespace osu.Game.Tests.Visual.Gameplay
{ {
ReplayInputHandler = new TestFramedReplayInputHandler(replay) ReplayInputHandler = new TestFramedReplayInputHandler(replay)
{ {
GamefieldToScreenSpace = pos => playbackManager.ToScreenSpace(pos), GamefieldToScreenSpace = pos => playbackManager?.ToScreenSpace(pos) ?? Vector2.Zero,
}, },
Child = new Container Child = new Container
{ {

View File

@ -258,10 +258,10 @@ namespace osu.Game.Beatmaps
OnlineBeatmapSetID = model.OnlineID, OnlineBeatmapSetID = model.OnlineID,
Metadata = new BeatmapMetadata Metadata = new BeatmapMetadata
{ {
Title = model.Metadata?.Title, Title = model.Metadata?.Title ?? string.Empty,
Artist = model.Metadata?.Artist, Artist = model.Metadata?.Artist ?? string.Empty,
TitleUnicode = model.Metadata?.TitleUnicode, TitleUnicode = model.Metadata?.TitleUnicode ?? string.Empty,
ArtistUnicode = model.Metadata?.ArtistUnicode, ArtistUnicode = model.Metadata?.ArtistUnicode ?? string.Empty,
Author = new User { Username = model.Metadata?.Author }, Author = new User { Username = model.Metadata?.Author },
} }
}, minimiseDownloadSize); }, minimiseDownloadSize);

View File

@ -9,6 +9,8 @@ using osu.Framework.Testing;
using osu.Game.Database; using osu.Game.Database;
using osu.Game.Users; using osu.Game.Users;
#nullable enable
namespace osu.Game.Beatmaps namespace osu.Game.Beatmaps
{ {
[ExcludeFromDynamicCompile] [ExcludeFromDynamicCompile]
@ -17,21 +19,21 @@ namespace osu.Game.Beatmaps
{ {
public int ID { get; set; } public int ID { get; set; }
public string Title { get; set; } public string Title { get; set; } = string.Empty;
[JsonProperty("title_unicode")] [JsonProperty("title_unicode")]
public string TitleUnicode { get; set; } public string TitleUnicode { get; set; } = string.Empty;
public string Artist { get; set; } public string Artist { get; set; } = string.Empty;
[JsonProperty("artist_unicode")] [JsonProperty("artist_unicode")]
public string ArtistUnicode { get; set; } public string ArtistUnicode { get; set; } = string.Empty;
[JsonIgnore] [JsonIgnore]
public List<BeatmapInfo> Beatmaps { get; set; } public List<BeatmapInfo> Beatmaps { get; set; } = new List<BeatmapInfo>();
[JsonIgnore] [JsonIgnore]
public List<BeatmapSetInfo> BeatmapSets { get; set; } public List<BeatmapSetInfo> BeatmapSets { get; set; } = new List<BeatmapSetInfo>();
/// <summary> /// <summary>
/// Helper property to deserialize a username to <see cref="User"/>. /// Helper property to deserialize a username to <see cref="User"/>.
@ -55,7 +57,7 @@ namespace osu.Game.Beatmaps
[Column("Author")] [Column("Author")]
public string AuthorString public string AuthorString
{ {
get => Author?.Username; get => Author?.Username ?? string.Empty;
set set
{ {
Author ??= new User(); Author ??= new User();
@ -67,22 +69,22 @@ namespace osu.Game.Beatmaps
/// The author of the beatmaps in this set. /// The author of the beatmaps in this set.
/// </summary> /// </summary>
[JsonIgnore] [JsonIgnore]
public User Author; public User? Author;
public string Source { get; set; } public string Source { get; set; } = string.Empty;
[JsonProperty(@"tags")] [JsonProperty(@"tags")]
public string Tags { get; set; } public string Tags { get; set; } = string.Empty;
/// <summary> /// <summary>
/// The time in milliseconds to begin playing the track for preview purposes. /// The time in milliseconds to begin playing the track for preview purposes.
/// If -1, the track should begin playing at 40% of its length. /// If -1, the track should begin playing at 40% of its length.
/// </summary> /// </summary>
public int PreviewTime { get; set; } public int PreviewTime { get; set; } = -1;
public string AudioFile { get; set; } public string AudioFile { get; set; } = string.Empty;
public string BackgroundFile { get; set; } public string BackgroundFile { get; set; } = string.Empty;
public bool Equals(BeatmapMetadata other) => ((IBeatmapMetadataInfo)this).Equals(other); public bool Equals(BeatmapMetadata other) => ((IBeatmapMetadataInfo)this).Equals(other);

View File

@ -82,7 +82,7 @@ namespace osu.Game.Beatmaps.Formats
{ {
writer.WriteLine("[General]"); writer.WriteLine("[General]");
if (beatmap.Metadata.AudioFile != null) writer.WriteLine(FormattableString.Invariant($"AudioFilename: {Path.GetFileName(beatmap.Metadata.AudioFile)}")); if (!string.IsNullOrEmpty(beatmap.Metadata.AudioFile)) writer.WriteLine(FormattableString.Invariant($"AudioFilename: {Path.GetFileName(beatmap.Metadata.AudioFile)}"));
writer.WriteLine(FormattableString.Invariant($"AudioLeadIn: {beatmap.BeatmapInfo.AudioLeadIn}")); writer.WriteLine(FormattableString.Invariant($"AudioLeadIn: {beatmap.BeatmapInfo.AudioLeadIn}"));
writer.WriteLine(FormattableString.Invariant($"PreviewTime: {beatmap.Metadata.PreviewTime}")); writer.WriteLine(FormattableString.Invariant($"PreviewTime: {beatmap.Metadata.PreviewTime}"));
writer.WriteLine(FormattableString.Invariant($"Countdown: {(int)beatmap.BeatmapInfo.Countdown}")); writer.WriteLine(FormattableString.Invariant($"Countdown: {(int)beatmap.BeatmapInfo.Countdown}"));
@ -126,13 +126,13 @@ namespace osu.Game.Beatmaps.Formats
writer.WriteLine("[Metadata]"); writer.WriteLine("[Metadata]");
writer.WriteLine(FormattableString.Invariant($"Title: {beatmap.Metadata.Title}")); writer.WriteLine(FormattableString.Invariant($"Title: {beatmap.Metadata.Title}"));
if (beatmap.Metadata.TitleUnicode != null) writer.WriteLine(FormattableString.Invariant($"TitleUnicode: {beatmap.Metadata.TitleUnicode}")); if (!string.IsNullOrEmpty(beatmap.Metadata.TitleUnicode)) writer.WriteLine(FormattableString.Invariant($"TitleUnicode: {beatmap.Metadata.TitleUnicode}"));
writer.WriteLine(FormattableString.Invariant($"Artist: {beatmap.Metadata.Artist}")); writer.WriteLine(FormattableString.Invariant($"Artist: {beatmap.Metadata.Artist}"));
if (beatmap.Metadata.ArtistUnicode != null) writer.WriteLine(FormattableString.Invariant($"ArtistUnicode: {beatmap.Metadata.ArtistUnicode}")); if (!string.IsNullOrEmpty(beatmap.Metadata.ArtistUnicode)) writer.WriteLine(FormattableString.Invariant($"ArtistUnicode: {beatmap.Metadata.ArtistUnicode}"));
writer.WriteLine(FormattableString.Invariant($"Creator: {beatmap.Metadata.AuthorString}")); writer.WriteLine(FormattableString.Invariant($"Creator: {beatmap.Metadata.AuthorString}"));
writer.WriteLine(FormattableString.Invariant($"Version: {beatmap.BeatmapInfo.Version}")); writer.WriteLine(FormattableString.Invariant($"Version: {beatmap.BeatmapInfo.Version}"));
if (beatmap.Metadata.Source != null) writer.WriteLine(FormattableString.Invariant($"Source: {beatmap.Metadata.Source}")); if (!string.IsNullOrEmpty(beatmap.Metadata.Source)) writer.WriteLine(FormattableString.Invariant($"Source: {beatmap.Metadata.Source}"));
if (beatmap.Metadata.Tags != null) writer.WriteLine(FormattableString.Invariant($"Tags: {beatmap.Metadata.Tags}")); if (!string.IsNullOrEmpty(beatmap.Metadata.Tags)) writer.WriteLine(FormattableString.Invariant($"Tags: {beatmap.Metadata.Tags}"));
if (beatmap.BeatmapInfo.OnlineBeatmapID != null) writer.WriteLine(FormattableString.Invariant($"BeatmapID: {beatmap.BeatmapInfo.OnlineBeatmapID}")); if (beatmap.BeatmapInfo.OnlineBeatmapID != null) writer.WriteLine(FormattableString.Invariant($"BeatmapID: {beatmap.BeatmapInfo.OnlineBeatmapID}"));
if (beatmap.BeatmapInfo.BeatmapSet?.OnlineBeatmapSetID != null) writer.WriteLine(FormattableString.Invariant($"BeatmapSetID: {beatmap.BeatmapInfo.BeatmapSet.OnlineBeatmapSetID}")); if (beatmap.BeatmapInfo.BeatmapSet?.OnlineBeatmapSetID != null) writer.WriteLine(FormattableString.Invariant($"BeatmapSetID: {beatmap.BeatmapInfo.BeatmapSet.OnlineBeatmapSetID}"));
} }

View File

@ -149,7 +149,7 @@ namespace osu.Game.Beatmaps
protected override Texture GetBackground() protected override Texture GetBackground()
{ {
if (Metadata?.BackgroundFile == null) if (string.IsNullOrEmpty(Metadata?.BackgroundFile))
return null; return null;
try try
@ -165,7 +165,7 @@ namespace osu.Game.Beatmaps
protected override Track GetBeatmapTrack() protected override Track GetBeatmapTrack()
{ {
if (Metadata?.AudioFile == null) if (string.IsNullOrEmpty(Metadata?.AudioFile))
return null; return null;
try try
@ -181,7 +181,7 @@ namespace osu.Game.Beatmaps
protected override Waveform GetWaveform() protected override Waveform GetWaveform()
{ {
if (Metadata?.AudioFile == null) if (string.IsNullOrEmpty(Metadata?.AudioFile))
return null; return null;
try try

View File

@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Edit.Checks
public IEnumerable<Issue> Run(BeatmapVerifierContext context) public IEnumerable<Issue> Run(BeatmapVerifierContext context)
{ {
string audioFile = context.Beatmap.Metadata?.AudioFile; string audioFile = context.Beatmap.Metadata?.AudioFile;
if (audioFile == null) if (string.IsNullOrEmpty(audioFile))
yield break; yield break;
var track = context.WorkingBeatmap.Track; var track = context.WorkingBeatmap.Track;

View File

@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Edit.Checks
{ {
string filename = GetFilename(context.Beatmap); string filename = GetFilename(context.Beatmap);
if (filename == null) if (string.IsNullOrEmpty(filename))
{ {
yield return new IssueTemplateNoneSet(this).Create(TypeOfFile); yield return new IssueTemplateNoneSet(this).Create(TypeOfFile);

View File

@ -108,11 +108,20 @@ namespace osu.Game.Screens.Edit.Compose.Components
protected override bool OnMouseDown(MouseDownEvent e) protected override bool OnMouseDown(MouseDownEvent e)
{ {
bool selectionPerformed = performMouseDownActions(e); bool selectionPerformed = performMouseDownActions(e);
// even if a selection didn't occur, a drag event may still move the selection.
bool movementPossible = prepareSelectionMovement(); bool movementPossible = prepareSelectionMovement();
return selectionPerformed || (e.Button == MouseButton.Left && movementPossible); // check if selection has occurred
if (selectionPerformed)
{
// only unmodified right click should show context menu
bool shouldShowContextMenu = e.Button == MouseButton.Right && !e.ShiftPressed && !e.AltPressed && !e.SuperPressed;
// stop propagation if not showing context menu
return !shouldShowContextMenu;
}
// even if a selection didn't occur, a drag event may still move the selection.
return e.Button == MouseButton.Left && movementPossible;
} }
protected SelectionBlueprint<T> ClickedBlueprint { get; private set; } protected SelectionBlueprint<T> ClickedBlueprint { get; private set; }

View File

@ -29,7 +29,7 @@ namespace osu.Game.Screens.Select
new PopupDialogOkButton new PopupDialogOkButton
{ {
Text = @"Yes. Totally. Delete it.", Text = @"Yes. Totally. Delete it.",
Action = () => manager.Delete(beatmap), Action = () => manager?.Delete(beatmap),
}, },
new PopupDialogCancelButton new PopupDialogCancelButton
{ {

View File

@ -69,7 +69,7 @@ namespace osu.Game.Screens.Select.Carousel
return string.Compare(BeatmapSet.Metadata.Title, otherSet.BeatmapSet.Metadata.Title, StringComparison.OrdinalIgnoreCase); return string.Compare(BeatmapSet.Metadata.Title, otherSet.BeatmapSet.Metadata.Title, StringComparison.OrdinalIgnoreCase);
case SortMode.Author: case SortMode.Author:
return string.Compare(BeatmapSet.Metadata.Author.Username, otherSet.BeatmapSet.Metadata.Author.Username, StringComparison.OrdinalIgnoreCase); return string.Compare(BeatmapSet.Metadata.Author?.Username, otherSet.BeatmapSet.Metadata.Author?.Username, StringComparison.OrdinalIgnoreCase);
case SortMode.Source: case SortMode.Source:
return string.Compare(BeatmapSet.Metadata.Source, otherSet.BeatmapSet.Metadata.Source, StringComparison.OrdinalIgnoreCase); return string.Compare(BeatmapSet.Metadata.Source, otherSet.BeatmapSet.Metadata.Source, StringComparison.OrdinalIgnoreCase);

View File

@ -142,7 +142,7 @@ namespace osu.Game.Screens.Select.Carousel
}, },
new OsuSpriteText new OsuSpriteText
{ {
Text = $"{(beatmapInfo.Metadata ?? beatmapInfo.BeatmapSet.Metadata).Author.Username}", Text = $"{(beatmapInfo.Metadata ?? beatmapInfo.BeatmapSet.Metadata).Author?.Username ?? string.Empty}",
Font = OsuFont.GetFont(italics: true), Font = OsuFont.GetFont(italics: true),
Anchor = Anchor.BottomLeft, Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft Origin = Anchor.BottomLeft

View File

@ -77,10 +77,14 @@ namespace osu.Game.Storyboards
{ {
get get
{ {
string backgroundPath = BeatmapInfo.BeatmapSet?.Metadata?.BackgroundFile?.ToLowerInvariant(); string backgroundPath = BeatmapInfo.BeatmapSet?.Metadata?.BackgroundFile;
if (backgroundPath == null)
if (string.IsNullOrEmpty(backgroundPath))
return false; return false;
// Importantly, do this after the NullOrEmpty because EF may have stored the non-nullable value as null to the database, bypassing compile-time constraints.
backgroundPath = backgroundPath.ToLowerInvariant();
return GetLayer("Background").Elements.Any(e => e.Path.ToLowerInvariant() == backgroundPath); return GetLayer("Background").Elements.Any(e => e.Path.ToLowerInvariant() == backgroundPath);
} }
} }
@ -93,7 +97,7 @@ namespace osu.Game.Storyboards
Drawable drawable = null; Drawable drawable = null;
string storyboardPath = BeatmapInfo.BeatmapSet?.Files.Find(f => f.Filename.Equals(path, StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath; string storyboardPath = BeatmapInfo.BeatmapSet?.Files.Find(f => f.Filename.Equals(path, StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath;
if (storyboardPath != null) if (!string.IsNullOrEmpty(storyboardPath))
drawable = new Sprite { Texture = textureStore.Get(storyboardPath) }; drawable = new Sprite { Texture = textureStore.Get(storyboardPath) };
// if the texture isn't available locally in the beatmap, some storyboards choose to source from the underlying skin lookup hierarchy. // if the texture isn't available locally in the beatmap, some storyboards choose to source from the underlying skin lookup hierarchy.
else if (UseSkinSprites) else if (UseSkinSprites)