mirror of
https://github.com/ppy/osu.git
synced 2024-12-14 15:33:05 +08:00
Merge branch 'master' into fix-exporting-a-skin-with-too-long-file-name
This commit is contained in:
commit
ab87f5e0c9
123
osu.Game.Benchmarks/BenchmarkCarouselFilter.cs
Normal file
123
osu.Game.Benchmarks/BenchmarkCarouselFilter.cs
Normal file
@ -0,0 +1,123 @@
|
||||
// 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 BenchmarkDotNet.Attributes;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Screens.Select;
|
||||
using osu.Game.Screens.Select.Carousel;
|
||||
|
||||
namespace osu.Game.Benchmarks
|
||||
{
|
||||
public class BenchmarkCarouselFilter : BenchmarkTest
|
||||
{
|
||||
private BeatmapInfo getExampleBeatmap() => new BeatmapInfo
|
||||
{
|
||||
Ruleset = new RulesetInfo
|
||||
{
|
||||
ShortName = "osu",
|
||||
OnlineID = 0
|
||||
},
|
||||
StarRating = 4.0d,
|
||||
Difficulty = new BeatmapDifficulty
|
||||
{
|
||||
ApproachRate = 5.0f,
|
||||
DrainRate = 3.0f,
|
||||
CircleSize = 2.0f,
|
||||
},
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Artist = "The Artist",
|
||||
ArtistUnicode = "check unicode too",
|
||||
Title = "Title goes here",
|
||||
TitleUnicode = "Title goes here",
|
||||
Author = { Username = "The Author" },
|
||||
Source = "unit tests",
|
||||
Tags = "look for tags too",
|
||||
},
|
||||
DifficultyName = "version as well",
|
||||
Length = 2500,
|
||||
BPM = 160,
|
||||
BeatDivisor = 12,
|
||||
Status = BeatmapOnlineStatus.Loved
|
||||
};
|
||||
|
||||
private CarouselBeatmap carouselBeatmap = null!;
|
||||
private FilterCriteria criteria1 = null!;
|
||||
private FilterCriteria criteria2 = null!;
|
||||
private FilterCriteria criteria3 = null!;
|
||||
private FilterCriteria criteria4 = null!;
|
||||
private FilterCriteria criteria5 = null!;
|
||||
private FilterCriteria criteria6 = null!;
|
||||
|
||||
public override void SetUp()
|
||||
{
|
||||
var beatmap = getExampleBeatmap();
|
||||
beatmap.OnlineID = 20201010;
|
||||
beatmap.BeatmapSet = new BeatmapSetInfo { OnlineID = 1535 };
|
||||
carouselBeatmap = new CarouselBeatmap(beatmap);
|
||||
criteria1 = new FilterCriteria();
|
||||
criteria2 = new FilterCriteria
|
||||
{
|
||||
Ruleset = new RulesetInfo { ShortName = "catch" }
|
||||
};
|
||||
criteria3 = new FilterCriteria
|
||||
{
|
||||
Ruleset = new RulesetInfo { OnlineID = 6 },
|
||||
AllowConvertedBeatmaps = true,
|
||||
BPM = new FilterCriteria.OptionalRange<double>
|
||||
{
|
||||
IsUpperInclusive = false,
|
||||
Max = 160d
|
||||
}
|
||||
};
|
||||
criteria4 = new FilterCriteria
|
||||
{
|
||||
Ruleset = new RulesetInfo { OnlineID = 6 },
|
||||
AllowConvertedBeatmaps = true,
|
||||
SearchText = "an artist"
|
||||
};
|
||||
criteria5 = new FilterCriteria
|
||||
{
|
||||
Creator = new FilterCriteria.OptionalTextFilter { SearchTerm = "the author AND then something else" }
|
||||
};
|
||||
criteria6 = new FilterCriteria { SearchText = "20201010" };
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void CarouselBeatmapFilter()
|
||||
{
|
||||
carouselBeatmap.Filter(criteria1);
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void CriteriaMatchingSpecificRuleset()
|
||||
{
|
||||
carouselBeatmap.Filter(criteria2);
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void CriteriaMatchingRangeMax()
|
||||
{
|
||||
carouselBeatmap.Filter(criteria3);
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void CriteriaMatchingTerms()
|
||||
{
|
||||
carouselBeatmap.Filter(criteria4);
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void CriteriaMatchingCreator()
|
||||
{
|
||||
carouselBeatmap.Filter(criteria5);
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void CriteriaMatchingBeatmapIDs()
|
||||
{
|
||||
carouselBeatmap.Filter(criteria6);
|
||||
}
|
||||
}
|
||||
}
|
@ -73,11 +73,10 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
||||
beatmap.ControlPointInfo.Add(start_time, new TimingControlPoint
|
||||
{
|
||||
BeatLength = beat_length,
|
||||
TimeSignature = new TimeSignature(time_signature_numerator)
|
||||
TimeSignature = new TimeSignature(time_signature_numerator),
|
||||
OmitFirstBarLine = true
|
||||
});
|
||||
|
||||
beatmap.ControlPointInfo.Add(start_time, new EffectControlPoint { OmitFirstBarLine = true });
|
||||
|
||||
var barlines = new BarLineGenerator<BarLine>(beatmap).BarLines;
|
||||
|
||||
AddAssert("first barline ommited", () => barlines.All(b => b.StartTime != start_time));
|
||||
|
@ -72,7 +72,6 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
||||
converted.ControlPointInfo.Add(hitObject.StartTime, new EffectControlPoint
|
||||
{
|
||||
KiaiMode = currentEffectPoint.KiaiMode,
|
||||
OmitFirstBarLine = currentEffectPoint.OmitFirstBarLine,
|
||||
ScrollSpeed = lastScrollSpeed = nextScrollSpeed,
|
||||
});
|
||||
}
|
||||
|
@ -181,16 +181,19 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
Assert.AreEqual(956, timingPoint.Time);
|
||||
Assert.AreEqual(329.67032967033, timingPoint.BeatLength);
|
||||
Assert.AreEqual(TimeSignature.SimpleQuadruple, timingPoint.TimeSignature);
|
||||
Assert.IsFalse(timingPoint.OmitFirstBarLine);
|
||||
|
||||
timingPoint = controlPoints.TimingPointAt(48428);
|
||||
Assert.AreEqual(956, timingPoint.Time);
|
||||
Assert.AreEqual(329.67032967033d, timingPoint.BeatLength);
|
||||
Assert.AreEqual(TimeSignature.SimpleQuadruple, timingPoint.TimeSignature);
|
||||
Assert.IsFalse(timingPoint.OmitFirstBarLine);
|
||||
|
||||
timingPoint = controlPoints.TimingPointAt(119637);
|
||||
Assert.AreEqual(119637, timingPoint.Time);
|
||||
Assert.AreEqual(659.340659340659, timingPoint.BeatLength);
|
||||
Assert.AreEqual(TimeSignature.SimpleQuadruple, timingPoint.TimeSignature);
|
||||
Assert.IsFalse(timingPoint.OmitFirstBarLine);
|
||||
|
||||
var difficultyPoint = controlPoints.DifficultyPointAt(0);
|
||||
Assert.AreEqual(0, difficultyPoint.Time);
|
||||
@ -222,17 +225,14 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
var effectPoint = controlPoints.EffectPointAt(0);
|
||||
Assert.AreEqual(0, effectPoint.Time);
|
||||
Assert.IsFalse(effectPoint.KiaiMode);
|
||||
Assert.IsFalse(effectPoint.OmitFirstBarLine);
|
||||
|
||||
effectPoint = controlPoints.EffectPointAt(53703);
|
||||
Assert.AreEqual(53703, effectPoint.Time);
|
||||
Assert.IsTrue(effectPoint.KiaiMode);
|
||||
Assert.IsFalse(effectPoint.OmitFirstBarLine);
|
||||
|
||||
effectPoint = controlPoints.EffectPointAt(116637);
|
||||
Assert.AreEqual(95901, effectPoint.Time);
|
||||
Assert.IsFalse(effectPoint.KiaiMode);
|
||||
Assert.IsFalse(effectPoint.OmitFirstBarLine);
|
||||
}
|
||||
}
|
||||
|
||||
@ -273,6 +273,28 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDecodeOmitBarLineEffect()
|
||||
{
|
||||
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||
|
||||
using (var resStream = TestResources.OpenResource("omit-barline-control-points.osu"))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
var controlPoints = (LegacyControlPointInfo)decoder.Decode(stream).ControlPointInfo;
|
||||
|
||||
Assert.That(controlPoints.TimingPoints.Count, Is.EqualTo(6));
|
||||
Assert.That(controlPoints.EffectPoints.Count, Is.EqualTo(0));
|
||||
|
||||
Assert.That(controlPoints.TimingPointAt(500).OmitFirstBarLine, Is.False);
|
||||
Assert.That(controlPoints.TimingPointAt(1500).OmitFirstBarLine, Is.True);
|
||||
Assert.That(controlPoints.TimingPointAt(2500).OmitFirstBarLine, Is.False);
|
||||
Assert.That(controlPoints.TimingPointAt(3500).OmitFirstBarLine, Is.False);
|
||||
Assert.That(controlPoints.TimingPointAt(4500).OmitFirstBarLine, Is.False);
|
||||
Assert.That(controlPoints.TimingPointAt(5500).OmitFirstBarLine, Is.True);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestTimingPointResetsSpeedMultiplier()
|
||||
{
|
||||
|
@ -43,6 +43,18 @@ namespace osu.Game.Tests.NonVisual
|
||||
Assert.That(cpi.Groups.Count, Is.EqualTo(2));
|
||||
Assert.That(cpi.TimingPoints.Count, Is.EqualTo(2));
|
||||
Assert.That(cpi.AllControlPoints.Count(), Is.EqualTo(2));
|
||||
|
||||
cpi.Add(1200, new TimingControlPoint { OmitFirstBarLine = true }); // is not redundant
|
||||
|
||||
Assert.That(cpi.Groups.Count, Is.EqualTo(3));
|
||||
Assert.That(cpi.TimingPoints.Count, Is.EqualTo(3));
|
||||
Assert.That(cpi.AllControlPoints.Count(), Is.EqualTo(3));
|
||||
|
||||
cpi.Add(1500, new TimingControlPoint { OmitFirstBarLine = true }); // is not redundant
|
||||
|
||||
Assert.That(cpi.Groups.Count, Is.EqualTo(4));
|
||||
Assert.That(cpi.TimingPoints.Count, Is.EqualTo(4));
|
||||
Assert.That(cpi.AllControlPoints.Count(), Is.EqualTo(4));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -95,12 +107,12 @@ namespace osu.Game.Tests.NonVisual
|
||||
Assert.That(cpi.EffectPoints.Count, Is.EqualTo(0));
|
||||
Assert.That(cpi.AllControlPoints.Count(), Is.EqualTo(0));
|
||||
|
||||
cpi.Add(1000, new EffectControlPoint { KiaiMode = true, OmitFirstBarLine = true }); // is not redundant
|
||||
cpi.Add(1400, new EffectControlPoint { KiaiMode = true, OmitFirstBarLine = true }); // same settings, but is not redundant
|
||||
cpi.Add(1000, new EffectControlPoint { KiaiMode = true }); // is not redundant
|
||||
cpi.Add(1400, new EffectControlPoint { KiaiMode = true }); // is redundant
|
||||
|
||||
Assert.That(cpi.Groups.Count, Is.EqualTo(2));
|
||||
Assert.That(cpi.EffectPoints.Count, Is.EqualTo(2));
|
||||
Assert.That(cpi.AllControlPoints.Count(), Is.EqualTo(2));
|
||||
Assert.That(cpi.Groups.Count, Is.EqualTo(1));
|
||||
Assert.That(cpi.EffectPoints.Count, Is.EqualTo(1));
|
||||
Assert.That(cpi.AllControlPoints.Count(), Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
BIN
osu.Game.Tests/Resources/Archives/modified-argon-20230305.osk
Normal file
BIN
osu.Game.Tests/Resources/Archives/modified-argon-20230305.osk
Normal file
Binary file not shown.
27
osu.Game.Tests/Resources/omit-barline-control-points.osu
Normal file
27
osu.Game.Tests/Resources/omit-barline-control-points.osu
Normal file
@ -0,0 +1,27 @@
|
||||
osu file format v14
|
||||
|
||||
[TimingPoints]
|
||||
|
||||
// Uninherited: none, inherited: none
|
||||
0,500,4,2,0,100,1,0
|
||||
0,-50,4,3,0,100,0,0
|
||||
|
||||
// Uninherited: omit, inherited: none
|
||||
1000,500,4,2,0,100,1,8
|
||||
1000,-50,4,3,0,100,0,0
|
||||
|
||||
// Uninherited: none, inherited: omit (should be ignored, inheriting cannot omit)
|
||||
2000,500,4,2,0,100,1,0
|
||||
2000,-50,4,3,0,100,0,8
|
||||
|
||||
// Inherited: none, uninherited: none
|
||||
3000,-50,4,3,0,100,0,0
|
||||
3000,500,4,2,0,100,1,0
|
||||
|
||||
// Inherited: omit, uninherited: none (should be ignored, inheriting cannot omit)
|
||||
4000,-50,4,3,0,100,0,8
|
||||
4000,500,4,2,0,100,1,0
|
||||
|
||||
// Inherited: none, uninherited: omit
|
||||
5000,-50,4,3,0,100,0,0
|
||||
5000,500,4,2,0,100,1,8
|
@ -48,7 +48,9 @@ namespace osu.Game.Tests.Skins
|
||||
// Covers BPM counter.
|
||||
"Archives/modified-default-20221205.osk",
|
||||
// Covers judgement counter.
|
||||
"Archives/modified-default-20230117.osk"
|
||||
"Archives/modified-default-20230117.osk",
|
||||
// Covers player avatar and flag.
|
||||
"Archives/modified-argon-20230305.osk",
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
|
@ -1,7 +1,7 @@
|
||||
// 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 System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Localisation;
|
||||
|
||||
namespace osu.Game.Beatmaps
|
||||
@ -29,10 +29,21 @@ namespace osu.Game.Beatmaps
|
||||
return new RomanisableString($"{metadata.GetPreferred(true)}".Trim(), $"{metadata.GetPreferred(false)}".Trim());
|
||||
}
|
||||
|
||||
public static string[] GetSearchableTerms(this IBeatmapInfo beatmapInfo) => new[]
|
||||
public static List<string> GetSearchableTerms(this IBeatmapInfo beatmapInfo)
|
||||
{
|
||||
beatmapInfo.DifficultyName
|
||||
}.Concat(beatmapInfo.Metadata.GetSearchableTerms()).Where(s => !string.IsNullOrEmpty(s)).ToArray();
|
||||
var termsList = new List<string>(BeatmapMetadataInfoExtensions.MAX_SEARCHABLE_TERM_COUNT + 1);
|
||||
|
||||
addIfNotNull(beatmapInfo.DifficultyName);
|
||||
|
||||
BeatmapMetadataInfoExtensions.CollectSearchableTerms(beatmapInfo.Metadata, termsList);
|
||||
return termsList;
|
||||
|
||||
void addIfNotNull(string? s)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(s))
|
||||
termsList.Add(s);
|
||||
}
|
||||
}
|
||||
|
||||
private static string getVersionString(IBeatmapInfo beatmapInfo) => string.IsNullOrEmpty(beatmapInfo.DifficultyName) ? string.Empty : $"[{beatmapInfo.DifficultyName}]";
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Localisation;
|
||||
|
||||
namespace osu.Game.Beatmaps
|
||||
@ -13,16 +13,31 @@ namespace osu.Game.Beatmaps
|
||||
/// <summary>
|
||||
/// An array of all searchable terms provided in contained metadata.
|
||||
/// </summary>
|
||||
public static string[] GetSearchableTerms(this IBeatmapMetadataInfo metadataInfo) => new[]
|
||||
public static string[] GetSearchableTerms(this IBeatmapMetadataInfo metadataInfo)
|
||||
{
|
||||
metadataInfo.Author.Username,
|
||||
metadataInfo.Artist,
|
||||
metadataInfo.ArtistUnicode,
|
||||
metadataInfo.Title,
|
||||
metadataInfo.TitleUnicode,
|
||||
metadataInfo.Source,
|
||||
metadataInfo.Tags
|
||||
}.Where(s => !string.IsNullOrEmpty(s)).ToArray();
|
||||
var termsList = new List<string>(MAX_SEARCHABLE_TERM_COUNT);
|
||||
CollectSearchableTerms(metadataInfo, termsList);
|
||||
return termsList.ToArray();
|
||||
}
|
||||
|
||||
internal const int MAX_SEARCHABLE_TERM_COUNT = 7;
|
||||
|
||||
internal static void CollectSearchableTerms(IBeatmapMetadataInfo metadataInfo, IList<string> termsList)
|
||||
{
|
||||
addIfNotNull(metadataInfo.Author.Username);
|
||||
addIfNotNull(metadataInfo.Artist);
|
||||
addIfNotNull(metadataInfo.ArtistUnicode);
|
||||
addIfNotNull(metadataInfo.Title);
|
||||
addIfNotNull(metadataInfo.TitleUnicode);
|
||||
addIfNotNull(metadataInfo.Source);
|
||||
addIfNotNull(metadataInfo.Tags);
|
||||
|
||||
void addIfNotNull(string s)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(s))
|
||||
termsList.Add(s);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A user-presentable display title representing this metadata.
|
||||
|
@ -13,15 +13,9 @@ namespace osu.Game.Beatmaps.ControlPoints
|
||||
public static readonly EffectControlPoint DEFAULT = new EffectControlPoint
|
||||
{
|
||||
KiaiModeBindable = { Disabled = true },
|
||||
OmitFirstBarLineBindable = { Disabled = true },
|
||||
ScrollSpeedBindable = { Disabled = true }
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Whether the first bar line of this control point is ignored.
|
||||
/// </summary>
|
||||
public readonly BindableBool OmitFirstBarLineBindable = new BindableBool();
|
||||
|
||||
/// <summary>
|
||||
/// The relative scroll speed at this control point.
|
||||
/// </summary>
|
||||
@ -43,15 +37,6 @@ namespace osu.Game.Beatmaps.ControlPoints
|
||||
|
||||
public override Color4 GetRepresentingColour(OsuColour colours) => colours.Purple;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the first bar line of this control point is ignored.
|
||||
/// </summary>
|
||||
public bool OmitFirstBarLine
|
||||
{
|
||||
get => OmitFirstBarLineBindable.Value;
|
||||
set => OmitFirstBarLineBindable.Value = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether this control point enables Kiai mode.
|
||||
/// </summary>
|
||||
@ -67,16 +52,13 @@ namespace osu.Game.Beatmaps.ControlPoints
|
||||
}
|
||||
|
||||
public override bool IsRedundant(ControlPoint? existing)
|
||||
=> !OmitFirstBarLine
|
||||
&& existing is EffectControlPoint existingEffect
|
||||
=> existing is EffectControlPoint existingEffect
|
||||
&& KiaiMode == existingEffect.KiaiMode
|
||||
&& OmitFirstBarLine == existingEffect.OmitFirstBarLine
|
||||
&& ScrollSpeed == existingEffect.ScrollSpeed;
|
||||
|
||||
public override void CopyFrom(ControlPoint other)
|
||||
{
|
||||
KiaiMode = ((EffectControlPoint)other).KiaiMode;
|
||||
OmitFirstBarLine = ((EffectControlPoint)other).OmitFirstBarLine;
|
||||
ScrollSpeed = ((EffectControlPoint)other).ScrollSpeed;
|
||||
|
||||
base.CopyFrom(other);
|
||||
@ -88,10 +70,9 @@ namespace osu.Game.Beatmaps.ControlPoints
|
||||
|
||||
public bool Equals(EffectControlPoint? other)
|
||||
=> base.Equals(other)
|
||||
&& OmitFirstBarLine == other.OmitFirstBarLine
|
||||
&& ScrollSpeed == other.ScrollSpeed
|
||||
&& KiaiMode == other.KiaiMode;
|
||||
|
||||
public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), OmitFirstBarLine, ScrollSpeed, KiaiMode);
|
||||
public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), ScrollSpeed, KiaiMode);
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,11 @@ namespace osu.Game.Beatmaps.ControlPoints
|
||||
/// </summary>
|
||||
public readonly Bindable<TimeSignature> TimeSignatureBindable = new Bindable<TimeSignature>(TimeSignature.SimpleQuadruple);
|
||||
|
||||
/// <summary>
|
||||
/// Whether the first bar line of this control point is ignored.
|
||||
/// </summary>
|
||||
public readonly BindableBool OmitFirstBarLineBindable = new BindableBool();
|
||||
|
||||
/// <summary>
|
||||
/// Default length of a beat in milliseconds. Used whenever there is no beatmap or track playing.
|
||||
/// </summary>
|
||||
@ -30,6 +35,7 @@ namespace osu.Game.Beatmaps.ControlPoints
|
||||
Value = default_beat_length,
|
||||
Disabled = true
|
||||
},
|
||||
OmitFirstBarLineBindable = { Disabled = true },
|
||||
TimeSignatureBindable = { Disabled = true }
|
||||
};
|
||||
|
||||
@ -42,6 +48,15 @@ namespace osu.Game.Beatmaps.ControlPoints
|
||||
set => TimeSignatureBindable.Value = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the first bar line of this control point is ignored.
|
||||
/// </summary>
|
||||
public bool OmitFirstBarLine
|
||||
{
|
||||
get => OmitFirstBarLineBindable.Value;
|
||||
set => OmitFirstBarLineBindable.Value = value;
|
||||
}
|
||||
|
||||
public const double DEFAULT_BEAT_LENGTH = 1000;
|
||||
|
||||
/// <summary>
|
||||
@ -73,6 +88,7 @@ namespace osu.Game.Beatmaps.ControlPoints
|
||||
public override void CopyFrom(ControlPoint other)
|
||||
{
|
||||
TimeSignature = ((TimingControlPoint)other).TimeSignature;
|
||||
OmitFirstBarLine = ((TimingControlPoint)other).OmitFirstBarLine;
|
||||
BeatLength = ((TimingControlPoint)other).BeatLength;
|
||||
|
||||
base.CopyFrom(other);
|
||||
@ -85,8 +101,9 @@ namespace osu.Game.Beatmaps.ControlPoints
|
||||
public bool Equals(TimingControlPoint? other)
|
||||
=> base.Equals(other)
|
||||
&& TimeSignature.Equals(other.TimeSignature)
|
||||
&& OmitFirstBarLine == other.OmitFirstBarLine
|
||||
&& BeatLength.Equals(other.BeatLength);
|
||||
|
||||
public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), TimeSignature, BeatLength);
|
||||
public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), TimeSignature, BeatLength, OmitFirstBarLine);
|
||||
}
|
||||
}
|
||||
|
@ -431,6 +431,7 @@ namespace osu.Game.Beatmaps.Formats
|
||||
|
||||
controlPoint.BeatLength = beatLength;
|
||||
controlPoint.TimeSignature = timeSignature;
|
||||
controlPoint.OmitFirstBarLine = omitFirstBarSignature;
|
||||
|
||||
addControlPoint(time, controlPoint, true);
|
||||
}
|
||||
@ -447,7 +448,6 @@ namespace osu.Game.Beatmaps.Formats
|
||||
var effectPoint = new EffectControlPoint
|
||||
{
|
||||
KiaiMode = kiaiMode,
|
||||
OmitFirstBarLine = omitFirstBarSignature,
|
||||
};
|
||||
|
||||
// osu!taiko and osu!mania use effect points rather than difficulty points for scroll speed adjustments.
|
||||
|
@ -222,6 +222,7 @@ namespace osu.Game.Beatmaps.Formats
|
||||
{
|
||||
var samplePoint = legacyControlPoints.SamplePointAt(time);
|
||||
var effectPoint = legacyControlPoints.EffectPointAt(time);
|
||||
var timingPoint = legacyControlPoints.TimingPointAt(time);
|
||||
|
||||
// Apply the control point to a hit sample to uncover legacy properties (e.g. suffix)
|
||||
HitSampleInfo tempHitSample = samplePoint.ApplyTo(new ConvertHitObjectParser.LegacyHitSampleInfo(string.Empty));
|
||||
@ -230,10 +231,10 @@ namespace osu.Game.Beatmaps.Formats
|
||||
LegacyEffectFlags effectFlags = LegacyEffectFlags.None;
|
||||
if (effectPoint.KiaiMode)
|
||||
effectFlags |= LegacyEffectFlags.Kiai;
|
||||
if (effectPoint.OmitFirstBarLine)
|
||||
if (timingPoint.OmitFirstBarLine)
|
||||
effectFlags |= LegacyEffectFlags.OmitFirstBarLine;
|
||||
|
||||
writer.Write(FormattableString.Invariant($"{legacyControlPoints.TimingPointAt(time).TimeSignature.Numerator},"));
|
||||
writer.Write(FormattableString.Invariant($"{timingPoint.TimeSignature.Numerator},"));
|
||||
writer.Write(FormattableString.Invariant($"{(int)toLegacySampleBank(tempHitSample.Bank)},"));
|
||||
writer.Write(FormattableString.Invariant($"{toLegacyCustomSampleBank(tempHitSample)},"));
|
||||
writer.Write(FormattableString.Invariant($"{tempHitSample.Volume},"));
|
||||
|
@ -8,12 +8,12 @@ using osu.Game.Overlays.Dialog;
|
||||
|
||||
namespace osu.Game.Collections
|
||||
{
|
||||
public partial class DeleteCollectionDialog : DeleteConfirmationDialog
|
||||
public partial class DeleteCollectionDialog : DangerousActionDialog
|
||||
{
|
||||
public DeleteCollectionDialog(Live<BeatmapCollection> collection, Action deleteAction)
|
||||
{
|
||||
BodyText = collection.PerformRead(c => $"{c.Name} ({"beatmap".ToQuantity(c.BeatmapMD5Hashes.Count)})");
|
||||
DeleteAction = deleteAction;
|
||||
DangerousAction = deleteAction;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -114,7 +114,7 @@ namespace osu.Game.Graphics.Containers
|
||||
while (beatLength < MinimumBeatLength)
|
||||
beatLength *= 2;
|
||||
|
||||
int beatIndex = (int)((currentTrackTime - timingPoint.Time) / beatLength) - (effectPoint.OmitFirstBarLine ? 1 : 0);
|
||||
int beatIndex = (int)((currentTrackTime - timingPoint.Time) / beatLength) - (timingPoint.OmitFirstBarLine ? 1 : 0);
|
||||
|
||||
// The beats before the start of the first control point are off by 1, this should do the trick
|
||||
if (currentTrackTime < timingPoint.Time)
|
||||
|
@ -39,6 +39,16 @@ namespace osu.Game.Localisation.SkinComponents
|
||||
/// </summary>
|
||||
public static LocalisableString TextElementTextDescription => new TranslatableString(getKey(@"text_element_text_description"), "The text to be displayed.");
|
||||
|
||||
/// <summary>
|
||||
/// "Corner radius"
|
||||
/// </summary>
|
||||
public static LocalisableString CornerRadius => new TranslatableString(getKey(@"corner_radius"), "Corner radius");
|
||||
|
||||
/// <summary>
|
||||
/// "How rounded the corners should be."
|
||||
/// </summary>
|
||||
public static LocalisableString CornerRadiusDescription => new TranslatableString(getKey(@"corner_radius_description"), "How rounded the corners should be.");
|
||||
|
||||
private static string getKey(string key) => $"{prefix}:{key}";
|
||||
}
|
||||
}
|
||||
|
@ -42,7 +42,12 @@ namespace osu.Game.Localisation
|
||||
/// <summary>
|
||||
/// "Currently editing"
|
||||
/// </summary>
|
||||
public static LocalisableString CurrentlyEditing => new TranslatableString(getKey(@"currently_editing"), "Currently editing");
|
||||
public static LocalisableString CurrentlyEditing => new TranslatableString(getKey(@"currently_editing"), @"Currently editing");
|
||||
|
||||
/// <summary>
|
||||
/// "All layout elements for layers in the current screen will be reset to defaults."
|
||||
/// </summary>
|
||||
public static LocalisableString RevertToDefaultDescription => new TranslatableString(getKey(@"revert_to_default_description"), @"All layout elements for layers in the current screen will be reset to defaults.");
|
||||
|
||||
private static string getKey(string key) => $@"{prefix}:{key}";
|
||||
}
|
||||
|
@ -8,18 +8,22 @@ using osu.Game.Localisation;
|
||||
namespace osu.Game.Overlays.Dialog
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for various confirmation dialogs that concern deletion actions.
|
||||
/// A dialog which provides confirmation for actions which result in permanent consequences.
|
||||
/// Differs from <see cref="ConfirmDialog"/> in that the confirmation button is a "dangerous" one
|
||||
/// (requires the confirm button to be held).
|
||||
/// </summary>
|
||||
public abstract partial class DeleteConfirmationDialog : PopupDialog
|
||||
/// <remarks>
|
||||
/// The default implementation comes with text for a generic deletion operation.
|
||||
/// This can be further customised by specifying custom <see cref="PopupDialog.HeaderText"/>.
|
||||
/// </remarks>
|
||||
public abstract partial class DangerousActionDialog : PopupDialog
|
||||
{
|
||||
/// <summary>
|
||||
/// The action which performs the deletion.
|
||||
/// </summary>
|
||||
protected Action? DeleteAction { get; set; }
|
||||
protected Action? DangerousAction { get; set; }
|
||||
|
||||
protected DeleteConfirmationDialog()
|
||||
protected DangerousActionDialog()
|
||||
{
|
||||
HeaderText = DeleteConfirmationDialogStrings.HeaderText;
|
||||
|
||||
@ -30,7 +34,7 @@ namespace osu.Game.Overlays.Dialog
|
||||
new PopupDialogDangerousButton
|
||||
{
|
||||
Text = DeleteConfirmationDialogStrings.Confirm,
|
||||
Action = () => DeleteAction?.Invoke()
|
||||
Action = () => DangerousAction?.Invoke()
|
||||
},
|
||||
new PopupDialogCancelButton
|
||||
{
|
@ -7,12 +7,12 @@ using osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Overlays.Mods
|
||||
{
|
||||
public partial class DeleteModPresetDialog : DeleteConfirmationDialog
|
||||
public partial class DeleteModPresetDialog : DangerousActionDialog
|
||||
{
|
||||
public DeleteModPresetDialog(Live<ModPreset> modPreset)
|
||||
{
|
||||
BodyText = modPreset.PerformRead(preset => preset.Name);
|
||||
DeleteAction = () => modPreset.PerformWrite(preset => preset.DeletePending = true);
|
||||
DangerousAction = () => modPreset.PerformWrite(preset => preset.DeletePending = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,12 +6,12 @@ using osu.Game.Overlays.Dialog;
|
||||
|
||||
namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
||||
{
|
||||
public partial class MassDeleteConfirmationDialog : DeleteConfirmationDialog
|
||||
public partial class MassDeleteConfirmationDialog : DangerousActionDialog
|
||||
{
|
||||
public MassDeleteConfirmationDialog(Action deleteAction)
|
||||
{
|
||||
BodyText = "Everything?";
|
||||
DeleteAction = deleteAction;
|
||||
DangerousAction = deleteAction;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
20
osu.Game/Overlays/Settings/SettingsPercentageSlider.cs
Normal file
20
osu.Game/Overlays/Settings/SettingsPercentageSlider.cs
Normal file
@ -0,0 +1,20 @@
|
||||
// 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 System;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
|
||||
namespace osu.Game.Overlays.Settings
|
||||
{
|
||||
/// <summary>
|
||||
/// A <see cref="SettingsSlider{TValue,TSlider}"/> that displays its value as a percentage by default.
|
||||
/// Mostly provided for convenience of use with <see cref="SettingSourceAttribute"/>.
|
||||
/// </summary>
|
||||
public partial class SettingsPercentageSlider<TValue> : SettingsSlider<TValue>
|
||||
where TValue : struct, IEquatable<TValue>, IComparable<TValue>, IConvertible
|
||||
{
|
||||
protected override Drawable CreateControl() => ((RoundedSliderBar<TValue>)base.CreateControl()).With(sliderBar => sliderBar.DisplayAsPercentage = true);
|
||||
}
|
||||
}
|
@ -17,6 +17,7 @@ using osu.Framework.Input;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Localisation;
|
||||
using Web = osu.Game.Resources.Localisation.Web;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Graphics;
|
||||
@ -24,6 +25,7 @@ using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Cursor;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Localisation;
|
||||
using osu.Game.Overlays.Dialog;
|
||||
using osu.Game.Overlays.OSD;
|
||||
using osu.Game.Overlays.Settings;
|
||||
using osu.Game.Screens.Edit;
|
||||
@ -97,6 +99,9 @@ namespace osu.Game.Overlays.SkinEditor
|
||||
[Resolved]
|
||||
private OnScreenDisplay? onScreenDisplay { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private IDialogOverlay? dialogOverlay { get; set; }
|
||||
|
||||
public SkinEditor()
|
||||
{
|
||||
}
|
||||
@ -147,8 +152,8 @@ namespace osu.Game.Overlays.SkinEditor
|
||||
{
|
||||
Items = new[]
|
||||
{
|
||||
new EditorMenuItem(Resources.Localisation.Web.CommonStrings.ButtonsSave, MenuItemType.Standard, () => Save()),
|
||||
new EditorMenuItem(CommonStrings.RevertToDefault, MenuItemType.Destructive, revert),
|
||||
new EditorMenuItem(Web.CommonStrings.ButtonsSave, MenuItemType.Standard, () => Save()),
|
||||
new EditorMenuItem(CommonStrings.RevertToDefault, MenuItemType.Destructive, () => dialogOverlay?.Push(new RevertConfirmDialog(revert))),
|
||||
new EditorMenuItemSpacer(),
|
||||
new EditorMenuItem(CommonStrings.Exit, MenuItemType.Standard, () => skinEditorOverlay?.Hide()),
|
||||
},
|
||||
@ -670,6 +675,16 @@ namespace osu.Game.Overlays.SkinEditor
|
||||
}
|
||||
}
|
||||
|
||||
public partial class RevertConfirmDialog : DangerousActionDialog
|
||||
{
|
||||
public RevertConfirmDialog(Action revert)
|
||||
{
|
||||
HeaderText = CommonStrings.RevertToDefault;
|
||||
BodyText = SkinEditorStrings.RevertToDefaultDescription;
|
||||
DangerousAction = revert;
|
||||
}
|
||||
}
|
||||
|
||||
#region Delegation of IEditorChangeHandler
|
||||
|
||||
public event Action? OnStateChange
|
||||
|
@ -7,7 +7,6 @@ using System.Linq;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Overlays.Settings;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
@ -33,7 +32,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
|
||||
public override string SettingDescription => base.SettingDescription.Replace(MinimumAccuracy.ToString(), MinimumAccuracy.Value.ToString("##%", NumberFormatInfo.InvariantInfo));
|
||||
|
||||
[SettingSource("Minimum accuracy", "Trigger a failure if your accuracy goes below this value.", SettingControlType = typeof(SettingsSlider<double, PercentSlider>))]
|
||||
[SettingSource("Minimum accuracy", "Trigger a failure if your accuracy goes below this value.", SettingControlType = typeof(SettingsPercentageSlider<double>))]
|
||||
public BindableNumber<double> MinimumAccuracy { get; } = new BindableDouble
|
||||
{
|
||||
MinValue = 0.60,
|
||||
@ -69,12 +68,4 @@ namespace osu.Game.Rulesets.Mods
|
||||
return scoreProcessor.ComputeAccuracy(score);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class PercentSlider : RoundedSliderBar<double>
|
||||
{
|
||||
public PercentSlider()
|
||||
{
|
||||
DisplayAsPercentage = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,6 @@ namespace osu.Game.Rulesets.Objects
|
||||
for (int i = 0; i < timingPoints.Count; i++)
|
||||
{
|
||||
TimingControlPoint currentTimingPoint = timingPoints[i];
|
||||
EffectControlPoint currentEffectPoint = beatmap.ControlPointInfo.EffectPointAt(currentTimingPoint.Time);
|
||||
int currentBeat = 0;
|
||||
|
||||
// Don't generate barlines before the hit object or t=0 (whichever is earliest). Some beatmaps use very unrealistic values here (although none are ranked).
|
||||
@ -66,7 +65,7 @@ namespace osu.Game.Rulesets.Objects
|
||||
startTime = currentTimingPoint.Time + barCount * barLength;
|
||||
}
|
||||
|
||||
if (currentEffectPoint.OmitFirstBarLine)
|
||||
if (currentTimingPoint.OmitFirstBarLine)
|
||||
{
|
||||
startTime += barLength;
|
||||
}
|
||||
|
@ -7,12 +7,12 @@ using osu.Game.Overlays.Dialog;
|
||||
|
||||
namespace osu.Game.Screens.Edit
|
||||
{
|
||||
public partial class DeleteDifficultyConfirmationDialog : DeleteConfirmationDialog
|
||||
public partial class DeleteDifficultyConfirmationDialog : DangerousActionDialog
|
||||
{
|
||||
public DeleteDifficultyConfirmationDialog(BeatmapInfo beatmapInfo, Action deleteAction)
|
||||
{
|
||||
BodyText = $"\"{beatmapInfo.DifficultyName}\" difficulty";
|
||||
DeleteAction = deleteAction;
|
||||
DangerousAction = deleteAction;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ namespace osu.Game.Screens.Edit.Timing
|
||||
[Resolved]
|
||||
private EditorClock clock { get; set; } = null!;
|
||||
|
||||
public const float TIMING_COLUMN_WIDTH = 230;
|
||||
public const float TIMING_COLUMN_WIDTH = 300;
|
||||
|
||||
public IEnumerable<ControlPointGroup> ControlGroups
|
||||
{
|
||||
|
@ -14,7 +14,6 @@ namespace osu.Game.Screens.Edit.Timing
|
||||
internal partial class EffectSection : Section<EffectControlPoint>
|
||||
{
|
||||
private LabelledSwitchButton kiai = null!;
|
||||
private LabelledSwitchButton omitBarLine = null!;
|
||||
|
||||
private SliderWithTextBoxInput<double> scrollSpeedSlider = null!;
|
||||
|
||||
@ -24,7 +23,6 @@ namespace osu.Game.Screens.Edit.Timing
|
||||
Flow.AddRange(new Drawable[]
|
||||
{
|
||||
kiai = new LabelledSwitchButton { Label = "Kiai Time" },
|
||||
omitBarLine = new LabelledSwitchButton { Label = "Skip Bar Line" },
|
||||
scrollSpeedSlider = new SliderWithTextBoxInput<double>("Scroll Speed")
|
||||
{
|
||||
Current = new EffectControlPoint().ScrollSpeedBindable,
|
||||
@ -38,7 +36,6 @@ namespace osu.Game.Screens.Edit.Timing
|
||||
base.LoadComplete();
|
||||
|
||||
kiai.Current.BindValueChanged(_ => saveChanges());
|
||||
omitBarLine.Current.BindValueChanged(_ => saveChanges());
|
||||
scrollSpeedSlider.Current.BindValueChanged(_ => saveChanges());
|
||||
|
||||
var drawableRuleset = Beatmap.BeatmapInfo.Ruleset.CreateInstance().CreateDrawableRulesetWith(Beatmap.PlayableBeatmap);
|
||||
@ -60,7 +57,6 @@ namespace osu.Game.Screens.Edit.Timing
|
||||
isRebinding = true;
|
||||
|
||||
kiai.Current = point.NewValue.KiaiModeBindable;
|
||||
omitBarLine.Current = point.NewValue.OmitFirstBarLineBindable;
|
||||
scrollSpeedSlider.Current = point.NewValue.ScrollSpeedBindable;
|
||||
|
||||
isRebinding = false;
|
||||
@ -74,7 +70,6 @@ namespace osu.Game.Screens.Edit.Timing
|
||||
return new EffectControlPoint
|
||||
{
|
||||
KiaiMode = reference.KiaiMode,
|
||||
OmitFirstBarLine = reference.OmitFirstBarLine,
|
||||
ScrollSpeed = reference.ScrollSpeed,
|
||||
};
|
||||
}
|
||||
|
@ -11,18 +11,15 @@ namespace osu.Game.Screens.Edit.Timing.RowAttributes
|
||||
public partial class EffectRowAttribute : RowAttribute
|
||||
{
|
||||
private readonly Bindable<bool> kiaiMode;
|
||||
private readonly Bindable<bool> omitBarLine;
|
||||
private readonly BindableNumber<double> scrollSpeed;
|
||||
|
||||
private AttributeText kiaiModeBubble = null!;
|
||||
private AttributeText omitBarLineBubble = null!;
|
||||
private AttributeText text = null!;
|
||||
|
||||
public EffectRowAttribute(EffectControlPoint effect)
|
||||
: base(effect, "effect")
|
||||
{
|
||||
kiaiMode = effect.KiaiModeBindable.GetBoundCopy();
|
||||
omitBarLine = effect.OmitFirstBarLineBindable.GetBoundCopy();
|
||||
scrollSpeed = effect.ScrollSpeedBindable.GetBoundCopy();
|
||||
}
|
||||
|
||||
@ -37,11 +34,9 @@ namespace osu.Game.Screens.Edit.Timing.RowAttributes
|
||||
},
|
||||
text = new AttributeText(Point) { Width = 45 },
|
||||
kiaiModeBubble = new AttributeText(Point) { Text = "kiai" },
|
||||
omitBarLineBubble = new AttributeText(Point) { Text = "no barline" },
|
||||
});
|
||||
|
||||
kiaiMode.BindValueChanged(enabled => kiaiModeBubble.FadeTo(enabled.NewValue ? 1 : 0), true);
|
||||
omitBarLine.BindValueChanged(enabled => omitBarLineBubble.FadeTo(enabled.NewValue ? 1 : 0), true);
|
||||
scrollSpeed.BindValueChanged(_ => updateText(), true);
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Beatmaps.Timing;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
@ -14,24 +15,32 @@ namespace osu.Game.Screens.Edit.Timing.RowAttributes
|
||||
public partial class TimingRowAttribute : RowAttribute
|
||||
{
|
||||
private readonly BindableNumber<double> beatLength;
|
||||
private readonly Bindable<bool> omitBarLine;
|
||||
private readonly Bindable<TimeSignature> timeSignature;
|
||||
private AttributeText omitBarLineBubble = null!;
|
||||
private OsuSpriteText text = null!;
|
||||
|
||||
public TimingRowAttribute(TimingControlPoint timing)
|
||||
: base(timing, "timing")
|
||||
{
|
||||
timeSignature = timing.TimeSignatureBindable.GetBoundCopy();
|
||||
omitBarLine = timing.OmitFirstBarLineBindable.GetBoundCopy();
|
||||
beatLength = timing.BeatLengthBindable.GetBoundCopy();
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
Content.Add(text = new AttributeText(Point));
|
||||
Content.AddRange(new[]
|
||||
{
|
||||
text = new AttributeText(Point),
|
||||
omitBarLineBubble = new AttributeText(Point) { Text = "no barline" },
|
||||
});
|
||||
|
||||
Background.Colour = colourProvider.Background4;
|
||||
|
||||
timeSignature.BindValueChanged(_ => updateText());
|
||||
omitBarLine.BindValueChanged(enabled => omitBarLineBubble.FadeTo(enabled.NewValue ? 1 : 0), true);
|
||||
beatLength.BindValueChanged(_ => updateText(), true);
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@ namespace osu.Game.Screens.Edit.Timing
|
||||
internal partial class TimingSection : Section<TimingControlPoint>
|
||||
{
|
||||
private LabelledTimeSignature timeSignature = null!;
|
||||
private LabelledSwitchButton omitBarLine = null!;
|
||||
private BPMTextBox bpmTextEntry = null!;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
@ -24,7 +25,8 @@ namespace osu.Game.Screens.Edit.Timing
|
||||
timeSignature = new LabelledTimeSignature
|
||||
{
|
||||
Label = "Time Signature"
|
||||
}
|
||||
},
|
||||
omitBarLine = new LabelledSwitchButton { Label = "Skip Bar Line" },
|
||||
});
|
||||
}
|
||||
|
||||
@ -33,6 +35,7 @@ namespace osu.Game.Screens.Edit.Timing
|
||||
base.LoadComplete();
|
||||
|
||||
bpmTextEntry.Current.BindValueChanged(_ => saveChanges());
|
||||
omitBarLine.Current.BindValueChanged(_ => saveChanges());
|
||||
timeSignature.Current.BindValueChanged(_ => saveChanges());
|
||||
|
||||
void saveChanges()
|
||||
@ -51,6 +54,7 @@ namespace osu.Game.Screens.Edit.Timing
|
||||
|
||||
bpmTextEntry.Bindable = point.NewValue.BeatLengthBindable;
|
||||
timeSignature.Current = point.NewValue.TimeSignatureBindable;
|
||||
omitBarLine.Current = point.NewValue.OmitFirstBarLineBindable;
|
||||
|
||||
isRebinding = false;
|
||||
}
|
||||
@ -63,7 +67,8 @@ namespace osu.Game.Screens.Edit.Timing
|
||||
return new TimingControlPoint
|
||||
{
|
||||
BeatLength = reference.BeatLength,
|
||||
TimeSignature = reference.TimeSignature
|
||||
TimeSignature = reference.TimeSignature,
|
||||
OmitFirstBarLine = reference.OmitFirstBarLine,
|
||||
};
|
||||
}
|
||||
|
||||
|
58
osu.Game/Screens/Play/HUD/PlayerAvatar.cs
Normal file
58
osu.Game/Screens/Play/HUD/PlayerAvatar.cs
Normal file
@ -0,0 +1,58 @@
|
||||
// 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.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Localisation.SkinComponents;
|
||||
using osu.Game.Overlays.Settings;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Game.Users.Drawables;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Screens.Play.HUD
|
||||
{
|
||||
public partial class PlayerAvatar : CompositeDrawable, ISerialisableDrawable
|
||||
{
|
||||
[SettingSource(typeof(SkinnableComponentStrings), nameof(SkinnableComponentStrings.CornerRadius), nameof(SkinnableComponentStrings.CornerRadiusDescription),
|
||||
SettingControlType = typeof(SettingsPercentageSlider<float>))]
|
||||
public new BindableFloat CornerRadius { get; set; } = new BindableFloat(0.25f)
|
||||
{
|
||||
MinValue = 0,
|
||||
MaxValue = 0.5f,
|
||||
Precision = 0.01f
|
||||
};
|
||||
|
||||
private readonly UpdateableAvatar avatar;
|
||||
|
||||
private const float default_size = 80f;
|
||||
|
||||
public PlayerAvatar()
|
||||
{
|
||||
Size = new Vector2(default_size);
|
||||
|
||||
InternalChild = avatar = new UpdateableAvatar(isInteractive: false)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Masking = true
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(GameplayState gameplayState)
|
||||
{
|
||||
avatar.User = gameplayState.Score.ScoreInfo.User;
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
CornerRadius.BindValueChanged(e => avatar.CornerRadius = e.NewValue * default_size, true);
|
||||
}
|
||||
|
||||
public bool UsesFixedAnchor { get; set; }
|
||||
}
|
||||
}
|
36
osu.Game/Screens/Play/HUD/PlayerFlag.cs
Normal file
36
osu.Game/Screens/Play/HUD/PlayerFlag.cs
Normal file
@ -0,0 +1,36 @@
|
||||
// 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.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Game.Users.Drawables;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Screens.Play.HUD
|
||||
{
|
||||
public partial class PlayerFlag : CompositeDrawable, ISerialisableDrawable
|
||||
{
|
||||
private readonly UpdateableFlag flag;
|
||||
|
||||
private const float default_size = 40f;
|
||||
|
||||
public PlayerFlag()
|
||||
{
|
||||
Size = new Vector2(default_size, default_size / 1.4f);
|
||||
InternalChild = flag = new UpdateableFlag
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(GameplayState gameplayState)
|
||||
{
|
||||
flag.CountryCode = gameplayState.Score.ScoreInfo.User.CountryCode;
|
||||
}
|
||||
|
||||
public bool UsesFixedAnchor { get; set; }
|
||||
}
|
||||
}
|
@ -10,7 +10,7 @@ using osu.Game.Scoring;
|
||||
|
||||
namespace osu.Game.Screens.Select
|
||||
{
|
||||
public partial class BeatmapClearScoresDialog : DeleteConfirmationDialog
|
||||
public partial class BeatmapClearScoresDialog : DangerousActionDialog
|
||||
{
|
||||
[Resolved]
|
||||
private ScoreManager scoreManager { get; set; } = null!;
|
||||
@ -18,7 +18,7 @@ namespace osu.Game.Screens.Select
|
||||
public BeatmapClearScoresDialog(BeatmapInfo beatmapInfo, Action onCompletion)
|
||||
{
|
||||
BodyText = $"All local scores on {beatmapInfo.GetDisplayTitle()}";
|
||||
DeleteAction = () =>
|
||||
DangerousAction = () =>
|
||||
{
|
||||
Task.Run(() => scoreManager.Delete(beatmapInfo))
|
||||
.ContinueWith(_ => onCompletion);
|
||||
|
@ -7,7 +7,7 @@ using osu.Game.Overlays.Dialog;
|
||||
|
||||
namespace osu.Game.Screens.Select
|
||||
{
|
||||
public partial class BeatmapDeleteDialog : DeleteConfirmationDialog
|
||||
public partial class BeatmapDeleteDialog : DangerousActionDialog
|
||||
{
|
||||
private readonly BeatmapSetInfo beatmapSet;
|
||||
|
||||
@ -20,7 +20,7 @@ namespace osu.Game.Screens.Select
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(BeatmapManager beatmapManager)
|
||||
{
|
||||
DeleteAction = () => beatmapManager.Delete(beatmapSet);
|
||||
DangerousAction = () => beatmapManager.Delete(beatmapSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,11 @@ namespace osu.Game.Screens.Select.Carousel
|
||||
{
|
||||
base.Filter(criteria);
|
||||
|
||||
Filtered.Value = !checkMatch(criteria);
|
||||
}
|
||||
|
||||
private bool checkMatch(FilterCriteria criteria)
|
||||
{
|
||||
bool match =
|
||||
criteria.Ruleset == null ||
|
||||
BeatmapInfo.Ruleset.ShortName == criteria.Ruleset.ShortName ||
|
||||
@ -34,8 +39,7 @@ namespace osu.Game.Screens.Select.Carousel
|
||||
if (BeatmapInfo.BeatmapSet?.Equals(criteria.SelectedBeatmapSet) == true)
|
||||
{
|
||||
// only check ruleset equality or convertability for selected beatmap
|
||||
Filtered.Value = !match;
|
||||
return;
|
||||
return match;
|
||||
}
|
||||
|
||||
match &= !criteria.StarDifficulty.HasFilter || criteria.StarDifficulty.IsInRange(BeatmapInfo.StarRating);
|
||||
@ -49,18 +53,38 @@ namespace osu.Game.Screens.Select.Carousel
|
||||
match &= !criteria.BeatDivisor.HasFilter || criteria.BeatDivisor.IsInRange(BeatmapInfo.BeatDivisor);
|
||||
match &= !criteria.OnlineStatus.HasFilter || criteria.OnlineStatus.IsInRange(BeatmapInfo.Status);
|
||||
|
||||
if (!match) return false;
|
||||
|
||||
match &= !criteria.Creator.HasFilter || criteria.Creator.Matches(BeatmapInfo.Metadata.Author.Username);
|
||||
match &= !criteria.Artist.HasFilter || criteria.Artist.Matches(BeatmapInfo.Metadata.Artist) ||
|
||||
criteria.Artist.Matches(BeatmapInfo.Metadata.ArtistUnicode);
|
||||
|
||||
match &= !criteria.UserStarDifficulty.HasFilter || criteria.UserStarDifficulty.IsInRange(BeatmapInfo.StarRating);
|
||||
|
||||
if (match && criteria.SearchTerms.Length > 0)
|
||||
if (!match) return false;
|
||||
|
||||
if (criteria.SearchTerms.Length > 0)
|
||||
{
|
||||
string[] terms = BeatmapInfo.GetSearchableTerms();
|
||||
var terms = BeatmapInfo.GetSearchableTerms();
|
||||
|
||||
foreach (string criteriaTerm in criteria.SearchTerms)
|
||||
match &= terms.Any(term => term.Contains(criteriaTerm, StringComparison.InvariantCultureIgnoreCase));
|
||||
{
|
||||
bool any = false;
|
||||
|
||||
// ReSharper disable once ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator
|
||||
foreach (string term in terms)
|
||||
{
|
||||
if (!term.Contains(criteriaTerm, StringComparison.InvariantCultureIgnoreCase)) continue;
|
||||
|
||||
any = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (any) continue;
|
||||
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// if a match wasn't found via text matching of terms, do a second catch-all check matching against online IDs.
|
||||
// this should be done after text matching so we can prioritise matching numbers in metadata.
|
||||
@ -71,13 +95,14 @@ namespace osu.Game.Screens.Select.Carousel
|
||||
}
|
||||
}
|
||||
|
||||
if (match)
|
||||
match &= criteria.CollectionBeatmapMD5Hashes?.Contains(BeatmapInfo.MD5Hash) ?? true;
|
||||
if (!match) return false;
|
||||
|
||||
match &= criteria.CollectionBeatmapMD5Hashes?.Contains(BeatmapInfo.MD5Hash) ?? true;
|
||||
|
||||
if (match && criteria.RulesetCriteria != null)
|
||||
match &= criteria.RulesetCriteria.Matches(BeatmapInfo);
|
||||
|
||||
Filtered.Value = !match;
|
||||
return match;
|
||||
}
|
||||
|
||||
public override int CompareTo(FilterCriteria criteria, CarouselItem other)
|
||||
|
@ -8,14 +8,14 @@ using osu.Game.Localisation;
|
||||
|
||||
namespace osu.Game.Screens.Select.Carousel
|
||||
{
|
||||
public partial class UpdateLocalConfirmationDialog : DeleteConfirmationDialog
|
||||
public partial class UpdateLocalConfirmationDialog : DangerousActionDialog
|
||||
{
|
||||
public UpdateLocalConfirmationDialog(Action onConfirm)
|
||||
{
|
||||
HeaderText = PopupDialogStrings.UpdateLocallyModifiedText;
|
||||
BodyText = PopupDialogStrings.UpdateLocallyModifiedDescription;
|
||||
Icon = FontAwesome.Solid.ExclamationTriangle;
|
||||
DeleteAction = onConfirm;
|
||||
DangerousAction = onConfirm;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ using osu.Game.Beatmaps;
|
||||
|
||||
namespace osu.Game.Screens.Select
|
||||
{
|
||||
public partial class LocalScoreDeleteDialog : DeleteConfirmationDialog
|
||||
public partial class LocalScoreDeleteDialog : DangerousActionDialog
|
||||
{
|
||||
private readonly ScoreInfo score;
|
||||
|
||||
@ -28,7 +28,7 @@ namespace osu.Game.Screens.Select
|
||||
BodyText = $"{score.User} ({score.DisplayAccuracy}, {score.Rank})";
|
||||
|
||||
Icon = FontAwesome.Regular.TrashAlt;
|
||||
DeleteAction = () => scoreManager.Delete(score);
|
||||
DangerousAction = () => scoreManager.Delete(score);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ using osu.Game.Overlays.Dialog;
|
||||
|
||||
namespace osu.Game.Screens.Select
|
||||
{
|
||||
public partial class SkinDeleteDialog : DeleteConfirmationDialog
|
||||
public partial class SkinDeleteDialog : DangerousActionDialog
|
||||
{
|
||||
private readonly Skin skin;
|
||||
|
||||
@ -20,7 +20,7 @@ namespace osu.Game.Screens.Select
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(SkinManager manager)
|
||||
{
|
||||
DeleteAction = () =>
|
||||
DangerousAction = () =>
|
||||
{
|
||||
manager.Delete(skin.SkinInfo.Value);
|
||||
manager.CurrentSkinInfo.SetDefault();
|
||||
|
@ -58,7 +58,11 @@ namespace osu.Game.Storyboards.Drawables
|
||||
using (drawableVideo.BeginAbsoluteSequence(Video.StartTime))
|
||||
{
|
||||
Schedule(() => drawableVideo.PlaybackPosition = Time.Current - Video.StartTime);
|
||||
|
||||
drawableVideo.FadeIn(500);
|
||||
|
||||
using (drawableVideo.BeginDelayedSequence(drawableVideo.Duration - 500))
|
||||
drawableVideo.FadeOut(500);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,6 @@
|
||||
// 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.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
@ -30,14 +28,14 @@ namespace osu.Game.Users.Drawables
|
||||
/// Perform an action in addition to showing the country ranking.
|
||||
/// This should be used to perform auxiliary tasks and not as a primary action for clicking a flag (to maintain a consistent UX).
|
||||
/// </summary>
|
||||
public Action Action;
|
||||
public Action? Action;
|
||||
|
||||
public UpdateableFlag(CountryCode countryCode = CountryCode.Unknown)
|
||||
{
|
||||
CountryCode = countryCode;
|
||||
}
|
||||
|
||||
protected override Drawable CreateDrawable(CountryCode countryCode)
|
||||
protected override Drawable? CreateDrawable(CountryCode countryCode)
|
||||
{
|
||||
if (countryCode == CountryCode.Unknown && !ShowPlaceholderOnUnknown)
|
||||
return null;
|
||||
@ -56,8 +54,8 @@ namespace osu.Game.Users.Drawables
|
||||
};
|
||||
}
|
||||
|
||||
[Resolved(canBeNull: true)]
|
||||
private RankingsOverlay rankingsOverlay { get; set; }
|
||||
[Resolved]
|
||||
private RankingsOverlay? rankingsOverlay { get; set; }
|
||||
|
||||
protected override bool OnClick(ClickEvent e)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user