Merge branch 'master' into song-select-scroll-position-during-delete

This commit is contained in:
Bartłomiej Dach
2022-01-27 20:46:19 +01:00
committed by GitHub
42 changed files with 216 additions and 118 deletions

View File

@ -155,7 +155,6 @@ namespace osu.Game.Beatmaps
[Ignored]
public int RulesetID
{
get => Ruleset.OnlineID;
set
{
if (!string.IsNullOrEmpty(Ruleset.InstantiationInfo))

View File

@ -30,7 +30,7 @@ namespace osu.Game.Beatmaps
{
this.beatmap = beatmap;
beatmap.BeatmapInfo.Ruleset = rulesetProvider(beatmap.BeatmapInfo.RulesetID).RulesetInfo;
beatmap.BeatmapInfo.Ruleset = rulesetProvider(beatmap.BeatmapInfo.Ruleset.OnlineID).RulesetInfo;
if (beatmapId.HasValue)
beatmap.BeatmapInfo.OnlineID = beatmapId.Value;

View File

@ -141,9 +141,11 @@ namespace osu.Game.Beatmaps.Formats
break;
case @"Mode":
beatmap.BeatmapInfo.RulesetID = Parsing.ParseInt(pair.Value);
int rulesetID = Parsing.ParseInt(pair.Value);
switch (beatmap.BeatmapInfo.RulesetID)
beatmap.BeatmapInfo.RulesetID = rulesetID;
switch (rulesetID)
{
case 0:
parser = new Rulesets.Objects.Legacy.Osu.ConvertHitObjectParser(getOffsetTime(), FormatVersion);
@ -397,7 +399,7 @@ namespace osu.Game.Beatmaps.Formats
OmitFirstBarLine = omitFirstBarSignature,
};
bool isOsuRuleset = beatmap.BeatmapInfo.RulesetID == 0;
bool isOsuRuleset = beatmap.BeatmapInfo.Ruleset.OnlineID == 0;
// scrolling rulesets use effect points rather than difficulty points for scroll speed adjustments.
if (!isOsuRuleset)
effectPoint.ScrollSpeed = speedMultiplier;

View File

@ -35,6 +35,8 @@ namespace osu.Game.Beatmaps.Formats
[CanBeNull]
private readonly ISkin skin;
private readonly int onlineRulesetID;
/// <summary>
/// Creates a new <see cref="LegacyBeatmapEncoder"/>.
/// </summary>
@ -45,7 +47,9 @@ namespace osu.Game.Beatmaps.Formats
this.beatmap = beatmap;
this.skin = skin;
if (beatmap.BeatmapInfo.RulesetID < 0 || beatmap.BeatmapInfo.RulesetID > 3)
onlineRulesetID = beatmap.BeatmapInfo.Ruleset.OnlineID;
if (onlineRulesetID < 0 || onlineRulesetID > 3)
throw new ArgumentException("Only beatmaps in the osu, taiko, catch, or mania rulesets can be encoded to the legacy beatmap format.", nameof(beatmap));
}
@ -88,7 +92,7 @@ namespace osu.Game.Beatmaps.Formats
writer.WriteLine(FormattableString.Invariant($"Countdown: {(int)beatmap.BeatmapInfo.Countdown}"));
writer.WriteLine(FormattableString.Invariant($"SampleSet: {toLegacySampleBank((beatmap.HitObjects.FirstOrDefault()?.SampleControlPoint ?? SampleControlPoint.DEFAULT).SampleBank)}"));
writer.WriteLine(FormattableString.Invariant($"StackLeniency: {beatmap.BeatmapInfo.StackLeniency}"));
writer.WriteLine(FormattableString.Invariant($"Mode: {beatmap.BeatmapInfo.RulesetID}"));
writer.WriteLine(FormattableString.Invariant($"Mode: {onlineRulesetID}"));
writer.WriteLine(FormattableString.Invariant($"LetterboxInBreaks: {(beatmap.BeatmapInfo.LetterboxInBreaks ? '1' : '0')}"));
// if (beatmap.BeatmapInfo.UseSkinSprites)
// writer.WriteLine(@"UseSkinSprites: 1");
@ -102,7 +106,7 @@ namespace osu.Game.Beatmaps.Formats
writer.WriteLine(@"EpilepsyWarning: 1");
if (beatmap.BeatmapInfo.CountdownOffset > 0)
writer.WriteLine(FormattableString.Invariant($@"CountdownOffset: {beatmap.BeatmapInfo.CountdownOffset}"));
if (beatmap.BeatmapInfo.RulesetID == 3)
if (onlineRulesetID == 3)
writer.WriteLine(FormattableString.Invariant($"SpecialStyle: {(beatmap.BeatmapInfo.SpecialStyle ? '1' : '0')}"));
writer.WriteLine(FormattableString.Invariant($"WidescreenStoryboard: {(beatmap.BeatmapInfo.WidescreenStoryboard ? '1' : '0')}"));
if (beatmap.BeatmapInfo.SamplesMatchPlaybackRate)
@ -147,7 +151,7 @@ namespace osu.Game.Beatmaps.Formats
writer.WriteLine(FormattableString.Invariant($"ApproachRate: {beatmap.Difficulty.ApproachRate}"));
// Taiko adjusts the slider multiplier (see: LEGACY_TAIKO_VELOCITY_MULTIPLIER)
writer.WriteLine(beatmap.BeatmapInfo.RulesetID == 1
writer.WriteLine(onlineRulesetID == 1
? FormattableString.Invariant($"SliderMultiplier: {beatmap.Difficulty.SliderMultiplier / LEGACY_TAIKO_VELOCITY_MULTIPLIER}")
: FormattableString.Invariant($"SliderMultiplier: {beatmap.Difficulty.SliderMultiplier}"));
@ -179,7 +183,7 @@ namespace osu.Game.Beatmaps.Formats
SampleControlPoint lastRelevantSamplePoint = null;
DifficultyControlPoint lastRelevantDifficultyPoint = null;
bool isOsuRuleset = beatmap.BeatmapInfo.RulesetID == 0;
bool isOsuRuleset = onlineRulesetID == 0;
// iterate over hitobjects and pull out all required sample and difficulty changes
extractDifficultyControlPoints(beatmap.HitObjects);
@ -318,7 +322,7 @@ namespace osu.Game.Beatmaps.Formats
{
Vector2 position = new Vector2(256, 192);
switch (beatmap.BeatmapInfo.RulesetID)
switch (onlineRulesetID)
{
case 0:
case 2:
@ -372,7 +376,7 @@ namespace osu.Game.Beatmaps.Formats
break;
case IHasDuration _:
if (beatmap.BeatmapInfo.RulesetID == 3)
if (onlineRulesetID == 3)
type |= LegacyHitObjectType.Hold;
else
type |= LegacyHitObjectType.Spinner;

View File

@ -232,6 +232,7 @@ namespace osu.Game.Database
var transaction = r.BeginWrite();
int written = 0;
int missing = 0;
try
{
@ -261,6 +262,12 @@ namespace osu.Game.Database
var ruleset = r.Find<RulesetInfo>(beatmap.RulesetInfo.ShortName);
var metadata = getBestMetadata(beatmap.Metadata, beatmapSet.Metadata);
if (ruleset == null)
{
log($"Skipping {++missing} beatmaps with missing ruleset");
continue;
}
var realmBeatmap = new BeatmapInfo(ruleset, new BeatmapDifficulty(beatmap.BaseDifficulty), metadata)
{
DifficultyName = beatmap.DifficultyName,
@ -367,12 +374,12 @@ namespace osu.Game.Database
log($"Migrated {written}/{count} scores...");
}
var beatmap = r.All<BeatmapInfo>().First(b => b.Hash == score.BeatmapInfo.Hash);
var beatmap = r.All<BeatmapInfo>().FirstOrDefault(b => b.Hash == score.BeatmapInfo.Hash);
var ruleset = r.Find<RulesetInfo>(score.Ruleset.ShortName);
if (ruleset == null)
if (beatmap == null || ruleset == null)
{
log($"Skipping {++missing} scores with missing ruleset");
log($"Skipping {++missing} scores with missing ruleset or beatmap");
continue;
}

View File

@ -42,6 +42,8 @@ namespace osu.Game.Rulesets
public bool Equals(EFRulesetInfo other) => other != null && ID == other.ID && Available == other.Available && Name == other.Name && InstantiationInfo == other.InstantiationInfo;
public int CompareTo(RulesetInfo other) => OnlineID.CompareTo(other.OnlineID);
public override bool Equals(object obj) => obj is EFRulesetInfo rulesetInfo && Equals(rulesetInfo);
public bool Equals(IRulesetInfo other) => other is RulesetInfo b && Equals(b);

View File

@ -11,7 +11,7 @@ namespace osu.Game.Rulesets
/// <summary>
/// A representation of a ruleset's metadata.
/// </summary>
public interface IRulesetInfo : IHasOnlineID<int>, IEquatable<IRulesetInfo>
public interface IRulesetInfo : IHasOnlineID<int>, IEquatable<IRulesetInfo>, IComparable<RulesetInfo>
{
/// <summary>
/// The user-exposed name of this ruleset.

View File

@ -49,6 +49,20 @@ namespace osu.Game.Rulesets
public bool Equals(IRulesetInfo? other) => other is RulesetInfo b && Equals(b);
public int CompareTo(RulesetInfo other)
{
if (OnlineID >= 0 && other.OnlineID >= 0)
return OnlineID.CompareTo(other.OnlineID);
// Official rulesets are always given precedence for the time being.
if (OnlineID >= 0)
return -1;
if (other.OnlineID >= 0)
return 1;
return string.Compare(ShortName, other.ShortName, StringComparison.Ordinal);
}
public override int GetHashCode()
{
// Importantly, ignore the underlying realm hash code, as it will usually not match.
@ -90,11 +104,5 @@ namespace osu.Game.Rulesets
return ruleset;
}
#region Compatibility properties
public int ID => OnlineID;
#endregion
}
}

View File

@ -163,10 +163,7 @@ namespace osu.Game.Rulesets
}
}
// add known official rulesets first..
availableRulesets.AddRange(detachedRulesets.Where(r => r.OnlineID >= 0).OrderBy(r => r.OnlineID));
// .. then add any customs
availableRulesets.AddRange(detachedRulesets.Where(r => r.OnlineID < 0).OrderBy(r => r.ShortName));
availableRulesets.AddRange(detachedRulesets.OrderBy(r => r));
});
}

View File

@ -34,7 +34,7 @@ namespace osu.Game.Scoring.Legacy
this.score = score;
this.beatmap = beatmap;
if (score.ScoreInfo.BeatmapInfo.RulesetID < 0 || score.ScoreInfo.BeatmapInfo.RulesetID > 3)
if (score.ScoreInfo.BeatmapInfo.Ruleset.OnlineID < 0 || score.ScoreInfo.BeatmapInfo.Ruleset.OnlineID > 3)
throw new ArgumentException("Only scores in the osu, taiko, catch, or mania rulesets can be encoded to the legacy score format.", nameof(score));
}

View File

@ -338,7 +338,7 @@ namespace osu.Game.Screens.Edit
public EditorState GetState([CanBeNull] BeatmapInfo nextBeatmap = null) => new EditorState
{
Time = clock.CurrentTimeAccurate,
ClipboardContent = nextBeatmap == null || editorBeatmap.BeatmapInfo.RulesetID == nextBeatmap.RulesetID ? Clipboard.Content.Value : string.Empty
ClipboardContent = nextBeatmap == null || editorBeatmap.BeatmapInfo.Ruleset.ShortName == nextBeatmap.Ruleset.ShortName ? Clipboard.Content.Value : string.Empty
};
/// <summary>
@ -574,7 +574,9 @@ namespace osu.Game.Screens.Edit
// To update the game-wide beatmap with any changes, perform a re-fetch on exit/suspend.
// This is required as the editor makes its local changes via EditorBeatmap
// (which are not propagated outwards to a potentially cached WorkingBeatmap).
var refetchedBeatmap = beatmapManager.GetWorkingBeatmap(Beatmap.Value.BeatmapInfo);
((IWorkingBeatmapCache)beatmapManager).Invalidate(Beatmap.Value.BeatmapInfo);
var refetchedBeatmapInfo = beatmapManager.QueryBeatmap(b => b.ID == Beatmap.Value.BeatmapInfo.ID);
var refetchedBeatmap = beatmapManager.GetWorkingBeatmap(refetchedBeatmapInfo);
if (!(refetchedBeatmap is DummyWorkingBeatmap))
{
@ -780,7 +782,7 @@ namespace osu.Game.Screens.Edit
var difficultyItems = new List<MenuItem>();
foreach (var rulesetBeatmaps in beatmapSet.Beatmaps.GroupBy(b => b.RulesetID).OrderBy(group => group.Key))
foreach (var rulesetBeatmaps in beatmapSet.Beatmaps.GroupBy(b => b.Ruleset.ShortName).OrderBy(group => group.Key))
{
if (difficultyItems.Count > 0)
difficultyItems.Add(new EditorMenuItemSpacer());

View File

@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using osu.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
@ -49,6 +50,7 @@ namespace osu.Game.Screens.Menu
public const float BUTTON_WIDTH = 140f;
public const float WEDGE_WIDTH = 20;
[CanBeNull]
private OsuLogo logo;
/// <summary>
@ -328,9 +330,9 @@ namespace osu.Game.Screens.Menu
game?.Toolbar.Hide();
logo.ClearTransforms(targetMember: nameof(Position));
logo.MoveTo(new Vector2(0.5f), 800, Easing.OutExpo);
logo.ScaleTo(1, 800, Easing.OutExpo);
logo?.ClearTransforms(targetMember: nameof(Position));
logo?.MoveTo(new Vector2(0.5f), 800, Easing.OutExpo);
logo?.ScaleTo(1, 800, Easing.OutExpo);
}, buttonArea.Alpha * 150);
break;
@ -354,7 +356,7 @@ namespace osu.Game.Screens.Menu
logoDelayedAction = Scheduler.AddDelayed(() =>
{
if (impact)
logo.Impact();
logo?.Impact();
game?.Toolbar.Show();
}, 200);

View File

@ -29,7 +29,7 @@ namespace osu.Game.Screens.Select.Carousel
bool match =
criteria.Ruleset == null ||
BeatmapInfo.Ruleset.ShortName == criteria.Ruleset.ShortName ||
(BeatmapInfo.RulesetID == 0 && criteria.Ruleset.OnlineID != 0 && criteria.AllowConvertedBeatmaps);
(BeatmapInfo.Ruleset.OnlineID == 0 && criteria.Ruleset.OnlineID != 0 && criteria.AllowConvertedBeatmaps);
if (BeatmapInfo.BeatmapSet?.Equals(criteria.SelectedBeatmapSet) == true)
{
@ -89,7 +89,8 @@ namespace osu.Game.Screens.Select.Carousel
{
default:
case SortMode.Difficulty:
int ruleset = BeatmapInfo.RulesetID.CompareTo(otherBeatmap.BeatmapInfo.RulesetID);
int ruleset = BeatmapInfo.Ruleset.CompareTo(otherBeatmap.BeatmapInfo.Ruleset);
if (ruleset != 0) return ruleset;
return BeatmapInfo.StarRating.CompareTo(otherBeatmap.BeatmapInfo.StarRating);

View File

@ -39,7 +39,7 @@ namespace osu.Game.Screens.Select.Carousel
beatmapSet.Beatmaps
.Where(b => !b.Hidden)
.OrderBy(b => b.RulesetID)
.OrderBy(b => b.Ruleset)
.ThenBy(b => b.StarRating)
.Select(b => new CarouselBeatmap(b))
.ForEach(AddChild);

View File

@ -155,7 +155,7 @@ namespace osu.Game.Screens.Select.Leaderboards
var scores = r.All<ScoreInfo>()
.AsEnumerable()
// TODO: update to use a realm filter directly (or at least figure out the beatmap part to reduce scope).
.Where(s => !s.DeletePending && s.BeatmapInfo.ID == fetchBeatmapInfo.ID && s.Ruleset.OnlineID == ruleset.Value.ID);
.Where(s => !s.DeletePending && s.BeatmapInfo.ID == fetchBeatmapInfo.ID && s.Ruleset.ShortName == ruleset.Value.ShortName);
if (filterMods && !mods.Value.Any())
{

View File

@ -502,7 +502,7 @@ namespace osu.Game.Screens.Select
// clear pending task immediately to track any potential nested debounce operation.
selectionChangedDebounce = null;
Logger.Log($"updating selection with beatmap:{beatmap?.ID.ToString() ?? "null"} ruleset:{ruleset?.ID.ToString() ?? "null"}");
Logger.Log($"updating selection with beatmap:{beatmap?.ID.ToString() ?? "null"} ruleset:{ruleset?.ShortName ?? "null"}");
if (transferRulesetValue())
{

View File

@ -219,11 +219,11 @@ namespace osu.Game.Stores
var decodedInfo = decoded.BeatmapInfo;
var decodedDifficulty = decodedInfo.Difficulty;
var ruleset = realm.All<RulesetInfo>().FirstOrDefault(r => r.OnlineID == decodedInfo.RulesetID);
var ruleset = realm.All<RulesetInfo>().FirstOrDefault(r => r.OnlineID == decodedInfo.Ruleset.OnlineID);
if (ruleset?.Available != true)
{
Logger.Log($"Skipping import of {file.Filename} due to missing local ruleset {decodedInfo.RulesetID}.", LoggingTarget.Database);
Logger.Log($"Skipping import of {file.Filename} due to missing local ruleset {decodedInfo.Ruleset.OnlineID}.", LoggingTarget.Database);
continue;
}

View File

@ -175,7 +175,7 @@ namespace osu.Game.Tests.Beatmaps
var beatmap = decoder.Decode(stream);
var rulesetInstance = CreateRuleset();
beatmap.BeatmapInfo.Ruleset = beatmap.BeatmapInfo.RulesetID == rulesetInstance.RulesetInfo.ID ? rulesetInstance.RulesetInfo : new RulesetInfo();
beatmap.BeatmapInfo.Ruleset = beatmap.BeatmapInfo.Ruleset.OnlineID == rulesetInstance.RulesetInfo.OnlineID ? rulesetInstance.RulesetInfo : new RulesetInfo();
return beatmap;
}

View File

@ -79,7 +79,7 @@ namespace osu.Game.Tests.Beatmaps
currentTestBeatmap = Decoder.GetDecoder<Beatmap>(reader).Decode(reader);
// populate ruleset for beatmap converters that require it to be present.
var ruleset = rulesetStore.GetRuleset(currentTestBeatmap.BeatmapInfo.RulesetID);
var ruleset = rulesetStore.GetRuleset(currentTestBeatmap.BeatmapInfo.Ruleset.OnlineID);
Debug.Assert(ruleset != null);

View File

@ -282,7 +282,7 @@ namespace osu.Game.Tests.Visual
Status = beatmap.Status,
Checksum = beatmap.MD5Hash,
AuthorID = beatmap.Metadata.Author.OnlineID,
RulesetID = beatmap.RulesetID,
RulesetID = beatmap.Ruleset.OnlineID,
StarRating = beatmap.StarRating,
DifficultyName = beatmap.DifficultyName,
}