1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-08 13:57:29 +08:00

Merge branch 'ppy:master' into improve_retry_behaviour

This commit is contained in:
BlauFx 2022-08-05 23:16:35 +02:00 committed by GitHub
commit 0b886a79f1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 146 additions and 33 deletions

View File

@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
{
InternalChildren = new Drawable[]
{
connectionPool = new DrawablePool<FollowPointConnection>(1, 200),
connectionPool = new DrawablePool<FollowPointConnection>(10, 200),
pointPool = new DrawablePool<FollowPoint>(50, 1000)
};
}

View File

@ -11,9 +11,11 @@ using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Pooling;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Beatmaps;
using osu.Game.Rulesets.Osu.Configuration;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
@ -112,21 +114,36 @@ namespace osu.Game.Rulesets.Osu.UI
}
[BackgroundDependencyLoader(true)]
private void load(OsuRulesetConfigManager config)
private void load(OsuRulesetConfigManager config, IBeatmap beatmap)
{
config?.BindWith(OsuRulesetSetting.PlayfieldBorderStyle, playfieldBorder.PlayfieldBorderStyle);
RegisterPool<HitCircle, DrawableHitCircle>(10, 100);
var osuBeatmap = (OsuBeatmap)beatmap;
RegisterPool<Slider, DrawableSlider>(10, 100);
RegisterPool<SliderHeadCircle, DrawableSliderHead>(10, 100);
RegisterPool<SliderTailCircle, DrawableSliderTail>(10, 100);
RegisterPool<SliderTick, DrawableSliderTick>(10, 100);
RegisterPool<SliderRepeat, DrawableSliderRepeat>(5, 50);
RegisterPool<HitCircle, DrawableHitCircle>(20, 100);
// handle edge cases where a beatmap has a slider with many repeats.
int maxRepeatsOnOneSlider = 0;
int maxTicksOnOneSlider = 0;
if (osuBeatmap != null)
{
foreach (var slider in osuBeatmap.HitObjects.OfType<Slider>())
{
maxRepeatsOnOneSlider = Math.Max(maxRepeatsOnOneSlider, slider.RepeatCount);
maxTicksOnOneSlider = Math.Max(maxTicksOnOneSlider, slider.NestedHitObjects.OfType<SliderTick>().Count());
}
}
RegisterPool<Slider, DrawableSlider>(20, 100);
RegisterPool<SliderHeadCircle, DrawableSliderHead>(20, 100);
RegisterPool<SliderTailCircle, DrawableSliderTail>(20, 100);
RegisterPool<SliderTick, DrawableSliderTick>(Math.Max(maxTicksOnOneSlider, 20), Math.Max(maxTicksOnOneSlider, 200));
RegisterPool<SliderRepeat, DrawableSliderRepeat>(Math.Max(maxRepeatsOnOneSlider, 20), Math.Max(maxRepeatsOnOneSlider, 200));
RegisterPool<Spinner, DrawableSpinner>(2, 20);
RegisterPool<SpinnerTick, DrawableSpinnerTick>(10, 100);
RegisterPool<SpinnerBonusTick, DrawableSpinnerBonusTick>(10, 100);
RegisterPool<SpinnerTick, DrawableSpinnerTick>(10, 200);
RegisterPool<SpinnerBonusTick, DrawableSpinnerBonusTick>(10, 200);
}
protected override HitObjectLifetimeEntry CreateLifetimeEntry(HitObject hitObject) => new OsuHitObjectLifetimeEntry(hitObject);
@ -173,7 +190,7 @@ namespace osu.Game.Rulesets.Osu.UI
private readonly Action<DrawableOsuJudgement> onLoaded;
public DrawableJudgementPool(HitResult result, Action<DrawableOsuJudgement> onLoaded)
: base(10)
: base(20)
{
this.result = result;
this.onLoaded = onLoaded;

View File

@ -56,8 +56,10 @@ namespace osu.Game.Tests.Visual.Editing
[Test]
public void TestCreateNewBeatmap()
{
AddAssert("status is none", () => EditorBeatmap.BeatmapInfo.Status == BeatmapOnlineStatus.None);
AddStep("save beatmap", () => Editor.Save());
AddAssert("new beatmap in database", () => beatmapManager.QueryBeatmapSet(s => s.ID == currentBeatmapSetID)?.Value.DeletePending == false);
AddAssert("status is modified", () => EditorBeatmap.BeatmapInfo.Status == BeatmapOnlineStatus.LocallyModified);
}
[Test]
@ -208,6 +210,8 @@ namespace osu.Game.Tests.Visual.Editing
});
AddAssert("created difficulty has no objects", () => EditorBeatmap.HitObjects.Count == 0);
AddAssert("status is modified", () => EditorBeatmap.BeatmapInfo.Status == BeatmapOnlineStatus.LocallyModified);
AddStep("set unique difficulty name", () => EditorBeatmap.BeatmapInfo.DifficultyName = secondDifficultyName);
AddStep("save beatmap", () => Editor.Save());
AddAssert("new beatmap persisted", () =>
@ -218,7 +222,7 @@ namespace osu.Game.Tests.Visual.Editing
return beatmap != null
&& beatmap.DifficultyName == secondDifficultyName
&& set != null
&& set.PerformRead(s => s.Beatmaps.Count == 2 && s.Beatmaps.Any(b => b.DifficultyName == secondDifficultyName));
&& set.PerformRead(s => s.Beatmaps.Count == 2 && s.Beatmaps.Any(b => b.DifficultyName == secondDifficultyName) && s.Beatmaps.All(b => s.Status == BeatmapOnlineStatus.LocallyModified));
});
}
@ -294,7 +298,7 @@ namespace osu.Game.Tests.Visual.Editing
AddAssert("approach rate correctly copied", () => EditorBeatmap.Difficulty.ApproachRate == 4);
AddAssert("combo colours correctly copied", () => EditorBeatmap.BeatmapSkin.AsNonNull().ComboColours.Count == 2);
AddAssert("status not copied", () => EditorBeatmap.BeatmapInfo.Status == BeatmapOnlineStatus.None);
AddAssert("status is modified", () => EditorBeatmap.BeatmapInfo.Status == BeatmapOnlineStatus.LocallyModified);
AddAssert("online ID not copied", () => EditorBeatmap.BeatmapInfo.OnlineID == -1);
AddStep("save beatmap", () => Editor.Save());

View File

@ -105,5 +105,11 @@ namespace osu.Game.Audio
/// Retrieves the audio track.
/// </summary>
protected abstract Track? GetTrack();
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
Track?.Dispose();
}
}
}

View File

@ -121,7 +121,8 @@ namespace osu.Game.Beatmaps
OnlineID = -1;
LastOnlineUpdate = null;
OnlineMD5Hash = string.Empty;
Status = BeatmapOnlineStatus.None;
if (Status != BeatmapOnlineStatus.LocallyModified)
Status = BeatmapOnlineStatus.None;
}
#region Properties we may not want persisted (but also maybe no harm?)

View File

@ -313,9 +313,12 @@ namespace osu.Game.Beatmaps
beatmapInfo.MD5Hash = stream.ComputeMD5Hash();
beatmapInfo.Hash = stream.ComputeSHA2Hash();
beatmapInfo.Status = BeatmapOnlineStatus.LocallyModified;
AddFile(setInfo, stream, createBeatmapFilenameFromMetadata(beatmapInfo));
setInfo.Hash = beatmapImporter.ComputeHash(setInfo);
setInfo.Status = BeatmapOnlineStatus.LocallyModified;
Realm.Write(r =>
{

View File

@ -3,13 +3,23 @@
#nullable disable
using System.ComponentModel;
using osu.Framework.Localisation;
using osu.Game.Localisation;
using osu.Game.Resources.Localisation.Web;
namespace osu.Game.Beatmaps
{
public enum BeatmapOnlineStatus
{
/// <summary>
/// This is a special status given when local changes are made via the editor.
/// Once in this state, online status changes should be ignored unless the beatmap is reverted or submitted.
/// </summary>
[Description("Local")]
[LocalisableDescription(typeof(SongSelectStrings), nameof(SongSelectStrings.LocallyModified))]
LocallyModified = -4,
None = -3,
[LocalisableDescription(typeof(BeatmapsetsStrings), nameof(BeatmapsetsStrings.ShowStatusGraveyard))]

View File

@ -6,6 +6,7 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Data.Sqlite;
using osu.Framework.Development;
@ -51,6 +52,9 @@ namespace osu.Game.Beatmaps
/// <summary>
/// Queue an update for a beatmap set.
/// </summary>
/// <remarks>
/// This may happen during initial import, or at a later stage in response to a user action or server event.
/// </remarks>
/// <param name="beatmapSet">The beatmap set to update. Updates will be applied directly (so a transaction should be started if this instance is managed).</param>
/// <param name="preferOnlineFetch">Whether metadata from an online source should be preferred. If <c>true</c>, the local cache will be skipped to ensure the freshest data state possible.</param>
public void Update(BeatmapSetInfo beatmapSet, bool preferOnlineFetch)
@ -89,21 +93,26 @@ namespace osu.Game.Beatmaps
if (res != null)
{
beatmapInfo.Status = res.Status;
Debug.Assert(beatmapInfo.BeatmapSet != null);
beatmapInfo.BeatmapSet.Status = res.BeatmapSet?.Status ?? BeatmapOnlineStatus.None;
beatmapInfo.BeatmapSet.OnlineID = res.OnlineBeatmapSetID;
beatmapInfo.BeatmapSet.DateRanked = res.BeatmapSet?.Ranked;
beatmapInfo.BeatmapSet.DateSubmitted = res.BeatmapSet?.Submitted;
beatmapInfo.OnlineID = res.OnlineID;
beatmapInfo.OnlineMD5Hash = res.MD5Hash;
beatmapInfo.LastOnlineUpdate = res.LastUpdated;
beatmapInfo.OnlineID = res.OnlineID;
Debug.Assert(beatmapInfo.BeatmapSet != null);
beatmapInfo.BeatmapSet.OnlineID = res.OnlineBeatmapSetID;
beatmapInfo.Metadata.Author.OnlineID = res.AuthorID;
// Some metadata should only be applied if there's no local changes.
if (shouldSaveOnlineMetadata(beatmapInfo))
{
beatmapInfo.Status = res.Status;
beatmapInfo.Metadata.Author.OnlineID = res.AuthorID;
}
if (beatmapInfo.BeatmapSet.Beatmaps.All(shouldSaveOnlineMetadata))
{
beatmapInfo.BeatmapSet.Status = res.BeatmapSet?.Status ?? BeatmapOnlineStatus.None;
beatmapInfo.BeatmapSet.DateRanked = res.BeatmapSet?.Ranked;
beatmapInfo.BeatmapSet.DateSubmitted = res.BeatmapSet?.Submitted;
}
logForModel(set, $"Online retrieval mapped {beatmapInfo} to {res.OnlineBeatmapSetID} / {res.OnlineID}.");
}
@ -202,19 +211,26 @@ namespace osu.Game.Beatmaps
{
var status = (BeatmapOnlineStatus)reader.GetByte(2);
beatmapInfo.Status = status;
// Some metadata should only be applied if there's no local changes.
if (shouldSaveOnlineMetadata(beatmapInfo))
{
beatmapInfo.Status = status;
beatmapInfo.Metadata.Author.OnlineID = reader.GetInt32(3);
}
Debug.Assert(beatmapInfo.BeatmapSet != null);
beatmapInfo.BeatmapSet.Status = status;
beatmapInfo.BeatmapSet.OnlineID = reader.GetInt32(0);
// TODO: DateSubmitted and DateRanked are not provided by local cache.
beatmapInfo.OnlineID = reader.GetInt32(1);
beatmapInfo.Metadata.Author.OnlineID = reader.GetInt32(3);
beatmapInfo.OnlineMD5Hash = reader.GetString(4);
beatmapInfo.LastOnlineUpdate = reader.GetDateTimeOffset(5);
Debug.Assert(beatmapInfo.BeatmapSet != null);
beatmapInfo.BeatmapSet.OnlineID = reader.GetInt32(0);
if (beatmapInfo.BeatmapSet.Beatmaps.All(shouldSaveOnlineMetadata))
{
beatmapInfo.BeatmapSet.Status = status;
}
logForModel(set, $"Cached local retrieval for {beatmapInfo}.");
return true;
}
@ -233,6 +249,12 @@ namespace osu.Game.Beatmaps
private void logForModel(BeatmapSetInfo set, string message) =>
RealmArchiveModelImporter<BeatmapSetInfo>.LogForModel(set, $"[{nameof(BeatmapUpdaterMetadataLookup)}] {message}");
/// <summary>
/// Check whether the provided beatmap is in a state where online "ranked" status metadata should be saved against it.
/// Handles the case where a user may have locally modified a beatmap in the editor and expects the local status to stick.
/// </summary>
private static bool shouldSaveOnlineMetadata(BeatmapInfo beatmapInfo) => beatmapInfo.MatchesOnlineVersion || beatmapInfo.Status != BeatmapOnlineStatus.LocallyModified;
public void Dispose()
{
cacheDownloadRequest?.Dispose();

View File

@ -6,15 +6,18 @@ using osu.Framework.Extensions;
using osu.Framework.Extensions.LocalisationExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Localisation;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Localisation;
using osu.Game.Overlays;
using osuTK.Graphics;
namespace osu.Game.Beatmaps.Drawables
{
public class BeatmapSetOnlineStatusPill : CircularContainer
public class BeatmapSetOnlineStatusPill : CircularContainer, IHasTooltip
{
private BeatmapOnlineStatus status;
@ -96,5 +99,19 @@ namespace osu.Game.Beatmaps.Drawables
background.Colour = OsuColour.ForBeatmapSetOnlineStatus(Status) ?? colourProvider?.Light1 ?? colours.GreySeaFoamLighter;
}
public LocalisableString TooltipText
{
get
{
switch (Status)
{
case BeatmapOnlineStatus.LocallyModified:
return SongSelectStrings.LocallyModifiedTooltip;
}
return string.Empty;
}
}
}
}

View File

@ -118,7 +118,10 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons
// another async load might have completed before this one.
// if so, do not make any changes.
if (loadedPreview != previewTrack)
{
loadedPreview.Dispose();
return;
}
AddInternal(loadedPreview);
toggleLoading(false);

View File

@ -137,6 +137,9 @@ namespace osu.Game.Graphics
{
switch (status)
{
case BeatmapOnlineStatus.LocallyModified:
return Color4.OrangeRed;
case BeatmapOnlineStatus.Ranked:
case BeatmapOnlineStatus.Approved:
return Color4Extensions.FromHex(@"b3ff66");

View File

@ -0,0 +1,24 @@
// 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.Localisation;
namespace osu.Game.Localisation
{
public static class SongSelectStrings
{
private const string prefix = @"osu.Game.Resources.Localisation.SongSelect";
/// <summary>
/// "Local"
/// </summary>
public static LocalisableString LocallyModified => new TranslatableString(getKey(@"locally_modified"), @"Local");
/// <summary>
/// "Has been locally modified"
/// </summary>
public static LocalisableString LocallyModifiedTooltip => new TranslatableString(getKey(@"locally_modified_tooltip"), @"Has been locally modified");
private static string getKey(string key) => $@"{prefix}:{key}";
}
}

View File

@ -147,7 +147,10 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
{
// beatmapset may have changed.
if (Preview != preview)
{
preview?.Dispose();
return;
}
AddInternal(preview);
loading = false;