From dc75d55f72af11bdf81b081dad8f5e84be3ed2e2 Mon Sep 17 00:00:00 2001
From: Gabe Livengood <47010459+ggliv@users.noreply.github.com>
Date: Wed, 8 Jun 2022 14:02:15 -0400
Subject: [PATCH 0001/1400] allow modfailcondition to arbitrarily trigger fail
---
osu.Game/Rulesets/Mods/ModFailCondition.cs | 19 +++++++++++++++++++
osu.Game/Rulesets/Scoring/HealthProcessor.cs | 14 ++++++++++----
2 files changed, 29 insertions(+), 4 deletions(-)
diff --git a/osu.Game/Rulesets/Mods/ModFailCondition.cs b/osu.Game/Rulesets/Mods/ModFailCondition.cs
index 4425ece513..1aab0ab880 100644
--- a/osu.Game/Rulesets/Mods/ModFailCondition.cs
+++ b/osu.Game/Rulesets/Mods/ModFailCondition.cs
@@ -19,12 +19,31 @@ namespace osu.Game.Rulesets.Mods
public virtual bool PerformFail() => true;
public virtual bool RestartOnFail => Restart.Value;
+ private HealthProcessor healthProcessorInternal;
public void ApplyToHealthProcessor(HealthProcessor healthProcessor)
{
+ healthProcessorInternal = healthProcessor;
healthProcessor.FailConditions += FailCondition;
}
+ ///
+ /// Immediately triggers a failure on the loaded .
+ ///
+ protected void TriggerArbitraryFailure() => healthProcessorInternal.TriggerFailure();
+
+ ///
+ /// Determines whether should trigger a failure. Called every time a
+ /// judgement is applied to .
+ ///
+ /// The loaded .
+ /// The latest .
+ /// Whether the fail condition has been met.
+ ///
+ /// This method should only be used to trigger failures based on .
+ /// Using outside values to evaluate failure may introduce event ordering discrepancies, use
+ /// an with instead.
+ ///
protected abstract bool FailCondition(HealthProcessor healthProcessor, JudgementResult result);
}
}
diff --git a/osu.Game/Rulesets/Scoring/HealthProcessor.cs b/osu.Game/Rulesets/Scoring/HealthProcessor.cs
index 0f51560476..4f5ff95477 100644
--- a/osu.Game/Rulesets/Scoring/HealthProcessor.cs
+++ b/osu.Game/Rulesets/Scoring/HealthProcessor.cs
@@ -33,6 +33,15 @@ namespace osu.Game.Rulesets.Scoring
///
public bool HasFailed { get; private set; }
+ ///
+ /// Immediately triggers a failure for this HealthProcessor.
+ ///
+ public void TriggerFailure()
+ {
+ if (Failed?.Invoke() != false)
+ HasFailed = true;
+ }
+
protected override void ApplyResultInternal(JudgementResult result)
{
result.HealthAtJudgement = Health.Value;
@@ -44,10 +53,7 @@ namespace osu.Game.Rulesets.Scoring
Health.Value += GetHealthIncreaseFor(result);
if (meetsAnyFailCondition(result))
- {
- if (Failed?.Invoke() != false)
- HasFailed = true;
- }
+ TriggerFailure();
}
protected override void RevertResultInternal(JudgementResult result)
From 21c5499da16eb88f12d6f5bee8d28b1557559b2f Mon Sep 17 00:00:00 2001
From: Gabe Livengood <47010459+ggliv@users.noreply.github.com>
Date: Fri, 10 Jun 2022 13:11:17 -0400
Subject: [PATCH 0002/1400] remove arbitrary from method name
---
osu.Game/Rulesets/Mods/ModFailCondition.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/osu.Game/Rulesets/Mods/ModFailCondition.cs b/osu.Game/Rulesets/Mods/ModFailCondition.cs
index 1aab0ab880..9500734408 100644
--- a/osu.Game/Rulesets/Mods/ModFailCondition.cs
+++ b/osu.Game/Rulesets/Mods/ModFailCondition.cs
@@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Mods
///
/// Immediately triggers a failure on the loaded .
///
- protected void TriggerArbitraryFailure() => healthProcessorInternal.TriggerFailure();
+ protected void TriggerFailure() => healthProcessorInternal.TriggerFailure();
///
/// Determines whether should trigger a failure. Called every time a
@@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Mods
///
/// This method should only be used to trigger failures based on .
/// Using outside values to evaluate failure may introduce event ordering discrepancies, use
- /// an with instead.
+ /// an with instead.
///
protected abstract bool FailCondition(HealthProcessor healthProcessor, JudgementResult result);
}
From 6e64a8f55ef5838a5d58625668138fb3c85e34db Mon Sep 17 00:00:00 2001
From: Gabe Livengood <47010459+ggliv@users.noreply.github.com>
Date: Fri, 10 Jun 2022 13:13:35 -0400
Subject: [PATCH 0003/1400] use event to trigger failure
---
osu.Game/Rulesets/Mods/ModFailCondition.cs | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/osu.Game/Rulesets/Mods/ModFailCondition.cs b/osu.Game/Rulesets/Mods/ModFailCondition.cs
index 9500734408..63cebc9747 100644
--- a/osu.Game/Rulesets/Mods/ModFailCondition.cs
+++ b/osu.Game/Rulesets/Mods/ModFailCondition.cs
@@ -19,18 +19,18 @@ namespace osu.Game.Rulesets.Mods
public virtual bool PerformFail() => true;
public virtual bool RestartOnFail => Restart.Value;
- private HealthProcessor healthProcessorInternal;
+ private event Action failureTriggered;
public void ApplyToHealthProcessor(HealthProcessor healthProcessor)
{
- healthProcessorInternal = healthProcessor;
+ failureTriggered = healthProcessor.TriggerFailure;
healthProcessor.FailConditions += FailCondition;
}
///
/// Immediately triggers a failure on the loaded .
///
- protected void TriggerFailure() => healthProcessorInternal.TriggerFailure();
+ protected void TriggerFailure() => failureTriggered?.Invoke();
///
/// Determines whether should trigger a failure. Called every time a
From c1077d909ca5e41270522714e8457733a36043f2 Mon Sep 17 00:00:00 2001
From: Ryuki
Date: Sat, 17 Sep 2022 21:09:34 +0200
Subject: [PATCH 0004/1400] Basic avatar HUD implementation
---
osu.Game/Screens/Play/HUD/SkinnableAvatar.cs | 50 ++++++++++++++++++++
1 file changed, 50 insertions(+)
create mode 100644 osu.Game/Screens/Play/HUD/SkinnableAvatar.cs
diff --git a/osu.Game/Screens/Play/HUD/SkinnableAvatar.cs b/osu.Game/Screens/Play/HUD/SkinnableAvatar.cs
new file mode 100644
index 0000000000..abec4402a7
--- /dev/null
+++ b/osu.Game/Screens/Play/HUD/SkinnableAvatar.cs
@@ -0,0 +1,50 @@
+// Copyright (c) ppy Pty Ltd . 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.Skinning;
+using osu.Game.Users.Drawables;
+using osuTK;
+
+namespace osu.Game.Screens.Play.HUD
+{
+ public class SkinnableAvatar : CompositeDrawable, ISkinnableDrawable
+ {
+ [SettingSource("Corner radius", "How much the edges should be rounded.")]
+ public new BindableFloat CornerRadius { get; set; } = new BindableFloat(0)
+ {
+ MinValue = 0,
+ MaxValue = 100,
+ Precision = 0.01f
+ };
+
+ [Resolved]
+ private GameplayState gameplayState { get; set; } = null!;
+
+ private readonly UpdateableAvatar avatar;
+
+ public SkinnableAvatar()
+ {
+ Size = new Vector2(128f);
+ InternalChild = avatar = new UpdateableAvatar(isInteractive: false)
+ {
+ RelativeSizeAxes = Axes.Both,
+ Masking = true
+ };
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ avatar.User = gameplayState.Score.ScoreInfo.User;
+ CornerRadius.BindValueChanged(e => avatar.CornerRadius = e.NewValue);
+ }
+
+ public bool UsesFixedAnchor { get; set; }
+ }
+}
From ecf71df8a23bfca5cbe5a78daef23908135d92c2 Mon Sep 17 00:00:00 2001
From: Ryuki
Date: Sun, 18 Sep 2022 00:04:56 +0200
Subject: [PATCH 0005/1400] Change CornerRadius Max Value
---
osu.Game/Screens/Play/HUD/SkinnableAvatar.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/osu.Game/Screens/Play/HUD/SkinnableAvatar.cs b/osu.Game/Screens/Play/HUD/SkinnableAvatar.cs
index abec4402a7..d675176a0a 100644
--- a/osu.Game/Screens/Play/HUD/SkinnableAvatar.cs
+++ b/osu.Game/Screens/Play/HUD/SkinnableAvatar.cs
@@ -15,10 +15,10 @@ namespace osu.Game.Screens.Play.HUD
public class SkinnableAvatar : CompositeDrawable, ISkinnableDrawable
{
[SettingSource("Corner radius", "How much the edges should be rounded.")]
- public new BindableFloat CornerRadius { get; set; } = new BindableFloat(0)
+ public new BindableFloat CornerRadius { get; set; } = new BindableFloat
{
MinValue = 0,
- MaxValue = 100,
+ MaxValue = 63,
Precision = 0.01f
};
From 579d5b51eb25e90e7bc28f284b28c5edc14fc249 Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Wed, 19 Oct 2022 20:34:41 +0900
Subject: [PATCH 0006/1400] Add and consume sample bank constants
---
.../TestSceneAutoJuiceStream.cs | 2 +-
.../Editor/TestSceneSliderSplitting.cs | 4 +-
.../Formats/LegacyBeatmapDecoderTest.cs | 14 +++---
...estSceneHitObjectSamplePointAdjustments.cs | 45 ++++++++++---------
.../TestSceneGameplaySampleTriggerSource.cs | 4 +-
osu.Game/Audio/HitSampleInfo.cs | 9 ++++
.../ControlPoints/SampleControlPoint.cs | 4 +-
.../Beatmaps/Formats/LegacyBeatmapDecoder.cs | 3 +-
.../Beatmaps/Formats/LegacyBeatmapEncoder.cs | 6 +--
9 files changed, 51 insertions(+), 40 deletions(-)
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneAutoJuiceStream.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneAutoJuiceStream.cs
index 202228c9e7..e47a687f24 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestSceneAutoJuiceStream.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneAutoJuiceStream.cs
@@ -45,7 +45,7 @@ namespace osu.Game.Rulesets.Catch.Tests
NewCombo = i % 8 == 0,
Samples = new List(new[]
{
- new HitSampleInfo(HitSampleInfo.HIT_NORMAL, "normal", volume: 100)
+ new HitSampleInfo(HitSampleInfo.HIT_NORMAL, HitSampleInfo.BANK_NORMAL, volume: 100)
})
});
}
diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSplitting.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSplitting.cs
index 015952c59a..d642d6a5ed 100644
--- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSplitting.cs
+++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSplitting.cs
@@ -181,7 +181,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
{
if (slider is null) return;
- slider.SampleControlPoint.SampleBank = "soft";
+ slider.SampleControlPoint.SampleBank = HitSampleInfo.BANK_SOFT;
slider.SampleControlPoint.SampleVolume = 70;
sample = new HitSampleInfo("hitwhistle");
slider.Samples.Add(sample);
@@ -207,7 +207,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
AddAssert("sliders have hitsounds", hasHitsounds);
bool hasHitsounds() => sample is not null &&
- EditorBeatmap.HitObjects.All(o => o.SampleControlPoint.SampleBank == "soft" &&
+ EditorBeatmap.HitObjects.All(o => o.SampleControlPoint.SampleBank == HitSampleInfo.BANK_SOFT &&
o.SampleControlPoint.SampleVolume == 70 &&
o.Samples.Contains(sample));
}
diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs
index fdd0167ed3..d9817802f3 100644
--- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs
+++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs
@@ -206,17 +206,17 @@ namespace osu.Game.Tests.Beatmaps.Formats
var soundPoint = controlPoints.SamplePointAt(0);
Assert.AreEqual(956, soundPoint.Time);
- Assert.AreEqual("soft", soundPoint.SampleBank);
+ Assert.AreEqual(HitSampleInfo.BANK_SOFT, soundPoint.SampleBank);
Assert.AreEqual(60, soundPoint.SampleVolume);
soundPoint = controlPoints.SamplePointAt(53373);
Assert.AreEqual(53373, soundPoint.Time);
- Assert.AreEqual("soft", soundPoint.SampleBank);
+ Assert.AreEqual(HitSampleInfo.BANK_SOFT, soundPoint.SampleBank);
Assert.AreEqual(60, soundPoint.SampleVolume);
soundPoint = controlPoints.SamplePointAt(119637);
Assert.AreEqual(119637, soundPoint.Time);
- Assert.AreEqual("soft", soundPoint.SampleBank);
+ Assert.AreEqual(HitSampleInfo.BANK_SOFT, soundPoint.SampleBank);
Assert.AreEqual(80, soundPoint.SampleVolume);
var effectPoint = controlPoints.EffectPointAt(0);
@@ -261,10 +261,10 @@ namespace osu.Game.Tests.Beatmaps.Formats
Assert.That(controlPoints.EffectPointAt(2500).KiaiMode, Is.False);
Assert.That(controlPoints.EffectPointAt(3500).KiaiMode, Is.True);
- Assert.That(controlPoints.SamplePointAt(500).SampleBank, Is.EqualTo("drum"));
- Assert.That(controlPoints.SamplePointAt(1500).SampleBank, Is.EqualTo("drum"));
- Assert.That(controlPoints.SamplePointAt(2500).SampleBank, Is.EqualTo("normal"));
- Assert.That(controlPoints.SamplePointAt(3500).SampleBank, Is.EqualTo("drum"));
+ Assert.That(controlPoints.SamplePointAt(500).SampleBank, Is.EqualTo(HitSampleInfo.BANK_DRUM));
+ Assert.That(controlPoints.SamplePointAt(1500).SampleBank, Is.EqualTo(HitSampleInfo.BANK_DRUM));
+ Assert.That(controlPoints.SamplePointAt(2500).SampleBank, Is.EqualTo(HitSampleInfo.BANK_NORMAL));
+ Assert.That(controlPoints.SamplePointAt(3500).SampleBank, Is.EqualTo(HitSampleInfo.BANK_DRUM));
Assert.That(controlPoints.TimingPointAt(500).BeatLength, Is.EqualTo(500).Within(0.1));
Assert.That(controlPoints.TimingPointAt(1500).BeatLength, Is.EqualTo(500).Within(0.1));
diff --git a/osu.Game.Tests/Visual/Editing/TestSceneHitObjectSamplePointAdjustments.cs b/osu.Game.Tests/Visual/Editing/TestSceneHitObjectSamplePointAdjustments.cs
index 6313842dfd..31939f6971 100644
--- a/osu.Game.Tests/Visual/Editing/TestSceneHitObjectSamplePointAdjustments.cs
+++ b/osu.Game.Tests/Visual/Editing/TestSceneHitObjectSamplePointAdjustments.cs
@@ -7,6 +7,7 @@ using System.Linq;
using Humanizer;
using NUnit.Framework;
using osu.Framework.Testing;
+using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Graphics.UserInterface;
@@ -41,7 +42,7 @@ namespace osu.Game.Tests.Visual.Editing
Position = (OsuPlayfield.BASE_SIZE - new Vector2(100, 0)) / 2,
SampleControlPoint = new SampleControlPoint
{
- SampleBank = "normal",
+ SampleBank = HitSampleInfo.BANK_NORMAL,
SampleVolume = 80
}
});
@@ -52,7 +53,7 @@ namespace osu.Game.Tests.Visual.Editing
Position = (OsuPlayfield.BASE_SIZE + new Vector2(100, 0)) / 2,
SampleControlPoint = new SampleControlPoint
{
- SampleBank = "soft",
+ SampleBank = HitSampleInfo.BANK_SOFT,
SampleVolume = 60
}
});
@@ -70,7 +71,7 @@ namespace osu.Game.Tests.Visual.Editing
public void TestSingleSelection()
{
clickSamplePiece(0);
- samplePopoverHasSingleBank("normal");
+ samplePopoverHasSingleBank(HitSampleInfo.BANK_NORMAL);
samplePopoverHasSingleVolume(80);
dismissPopover();
@@ -80,14 +81,14 @@ namespace osu.Game.Tests.Visual.Editing
AddStep("select first object", () => EditorBeatmap.SelectedHitObjects.Add(EditorBeatmap.HitObjects.First()));
clickSamplePiece(1);
- samplePopoverHasSingleBank("soft");
+ samplePopoverHasSingleBank(HitSampleInfo.BANK_SOFT);
samplePopoverHasSingleVolume(60);
setVolumeViaPopover(90);
hitObjectHasSampleVolume(1, 90);
- setBankViaPopover("drum");
- hitObjectHasSampleBank(1, "drum");
+ setBankViaPopover(HitSampleInfo.BANK_DRUM);
+ hitObjectHasSampleBank(1, HitSampleInfo.BANK_DRUM);
}
[Test]
@@ -136,27 +137,27 @@ namespace osu.Game.Tests.Visual.Editing
AddStep("unify sample bank", () =>
{
foreach (var h in EditorBeatmap.HitObjects)
- h.SampleControlPoint.SampleBank = "soft";
+ h.SampleControlPoint.SampleBank = HitSampleInfo.BANK_SOFT;
});
AddStep("select both objects", () => EditorBeatmap.SelectedHitObjects.AddRange(EditorBeatmap.HitObjects));
clickSamplePiece(0);
- samplePopoverHasSingleBank("soft");
+ samplePopoverHasSingleBank(HitSampleInfo.BANK_SOFT);
dismissPopover();
clickSamplePiece(1);
- samplePopoverHasSingleBank("soft");
+ samplePopoverHasSingleBank(HitSampleInfo.BANK_SOFT);
setBankViaPopover(string.Empty);
- hitObjectHasSampleBank(0, "soft");
- hitObjectHasSampleBank(1, "soft");
- samplePopoverHasSingleBank("soft");
+ hitObjectHasSampleBank(0, HitSampleInfo.BANK_SOFT);
+ hitObjectHasSampleBank(1, HitSampleInfo.BANK_SOFT);
+ samplePopoverHasSingleBank(HitSampleInfo.BANK_SOFT);
- setBankViaPopover("drum");
- hitObjectHasSampleBank(0, "drum");
- hitObjectHasSampleBank(1, "drum");
- samplePopoverHasSingleBank("drum");
+ setBankViaPopover(HitSampleInfo.BANK_DRUM);
+ hitObjectHasSampleBank(0, HitSampleInfo.BANK_DRUM);
+ hitObjectHasSampleBank(1, HitSampleInfo.BANK_DRUM);
+ samplePopoverHasSingleBank(HitSampleInfo.BANK_DRUM);
}
[Test]
@@ -172,14 +173,14 @@ namespace osu.Game.Tests.Visual.Editing
samplePopoverHasIndeterminateBank();
setBankViaPopover(string.Empty);
- hitObjectHasSampleBank(0, "normal");
- hitObjectHasSampleBank(1, "soft");
+ hitObjectHasSampleBank(0, HitSampleInfo.BANK_NORMAL);
+ hitObjectHasSampleBank(1, HitSampleInfo.BANK_SOFT);
samplePopoverHasIndeterminateBank();
- setBankViaPopover("normal");
- hitObjectHasSampleBank(0, "normal");
- hitObjectHasSampleBank(1, "normal");
- samplePopoverHasSingleBank("normal");
+ setBankViaPopover(HitSampleInfo.BANK_NORMAL);
+ hitObjectHasSampleBank(0, HitSampleInfo.BANK_NORMAL);
+ hitObjectHasSampleBank(1, HitSampleInfo.BANK_NORMAL);
+ samplePopoverHasSingleBank(HitSampleInfo.BANK_NORMAL);
}
private void clickSamplePiece(int objectIndex) => AddStep($"click {objectIndex.ToOrdinalWords()} sample piece", () =>
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs
index b6da562bd0..6e53302624 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs
@@ -57,13 +57,13 @@ namespace osu.Game.Tests.Visual.Gameplay
{
StartTime = t += spacing,
Samples = new[] { new HitSampleInfo(HitSampleInfo.HIT_NORMAL) },
- SampleControlPoint = new SampleControlPoint { SampleBank = "soft" },
+ SampleControlPoint = new SampleControlPoint { SampleBank = HitSampleInfo.BANK_SOFT },
},
new HitCircle
{
StartTime = t + spacing,
Samples = new[] { new HitSampleInfo(HitSampleInfo.HIT_WHISTLE) },
- SampleControlPoint = new SampleControlPoint { SampleBank = "soft" },
+ SampleControlPoint = new SampleControlPoint { SampleBank = HitSampleInfo.BANK_SOFT },
},
});
diff --git a/osu.Game/Audio/HitSampleInfo.cs b/osu.Game/Audio/HitSampleInfo.cs
index efa5562cb8..81cfed23f5 100644
--- a/osu.Game/Audio/HitSampleInfo.cs
+++ b/osu.Game/Audio/HitSampleInfo.cs
@@ -19,11 +19,20 @@ namespace osu.Game.Audio
public const string HIT_FINISH = @"hitfinish";
public const string HIT_CLAP = @"hitclap";
+ public const string BANK_NORMAL = @"normal";
+ public const string BANK_SOFT = @"soft";
+ public const string BANK_DRUM = @"drum";
+
///
/// All valid sample addition constants.
///
public static IEnumerable AllAdditions => new[] { HIT_WHISTLE, HIT_FINISH, HIT_CLAP };
+ ///
+ /// All valid bank constants.
+ ///
+ public static IEnumerable AllBanks => new[] { BANK_NORMAL, BANK_SOFT, BANK_DRUM };
+
///
/// The name of the sample to load.
///
diff --git a/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs
index c454439c5c..e7b869cfa7 100644
--- a/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs
+++ b/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs
@@ -14,7 +14,7 @@ namespace osu.Game.Beatmaps.ControlPoints
///
public class SampleControlPoint : ControlPoint, IEquatable
{
- public const string DEFAULT_BANK = "normal";
+ public const string DEFAULT_BANK = HitSampleInfo.BANK_NORMAL;
public static readonly SampleControlPoint DEFAULT = new SampleControlPoint
{
@@ -30,7 +30,7 @@ namespace osu.Game.Beatmaps.ControlPoints
public readonly Bindable SampleBankBindable = new Bindable(DEFAULT_BANK) { Default = DEFAULT_BANK };
///
- /// The speed multiplier at this control point.
+ /// The sample bank at this control point.
///
public string SampleBank
{
diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs
index 75500fbc4e..b3e6f50366 100644
--- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs
+++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs
@@ -10,6 +10,7 @@ using System.Linq;
using osu.Framework.Extensions;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Logging;
+using osu.Game.Audio;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Beatmaps.Legacy;
using osu.Game.Beatmaps.Timing;
@@ -412,7 +413,7 @@ namespace osu.Game.Beatmaps.Formats
string stringSampleSet = sampleSet.ToString().ToLowerInvariant();
if (stringSampleSet == @"none")
- stringSampleSet = @"normal";
+ stringSampleSet = HitSampleInfo.HIT_NORMAL;
if (timingChange)
{
diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs
index 03c63ff4f2..52d1ea60a5 100644
--- a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs
+++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs
@@ -547,13 +547,13 @@ namespace osu.Game.Beatmaps.Formats
{
switch (sampleBank?.ToLowerInvariant())
{
- case "normal":
+ case HitSampleInfo.BANK_NORMAL:
return LegacySampleBank.Normal;
- case "soft":
+ case HitSampleInfo.BANK_SOFT:
return LegacySampleBank.Soft;
- case "drum":
+ case HitSampleInfo.BANK_DRUM:
return LegacySampleBank.Drum;
default:
From 9222cb379f7c5cdb1ad7a25f73df28242e5b1406 Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Wed, 19 Oct 2022 20:53:18 +0900
Subject: [PATCH 0007/1400] Add sample bank suport to editor selection handler
---
.../Components/EditorSelectionHandler.cs | 73 ++++++++++++++++++-
1 file changed, 72 insertions(+), 1 deletion(-)
diff --git a/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs
index 0bdfc5b0a0..1670328e58 100644
--- a/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs
+++ b/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs
@@ -48,11 +48,40 @@ namespace osu.Game.Screens.Edit.Compose.Components
///
public readonly Dictionary> SelectionSampleStates = new Dictionary>();
+ ///
+ /// The state of each sample bank type for all selected hitobjects.
+ ///
+ public readonly Dictionary> SelectionBankStates = new Dictionary>();
+
///
/// Set up ternary state bindables and bind them to selection/hitobject changes (in both directions)
///
private void createStateBindables()
{
+ foreach (string bankName in HitSampleInfo.AllBanks)
+ {
+ var bindable = new Bindable
+ {
+ Description = bankName.Titleize()
+ };
+
+ bindable.ValueChanged += state =>
+ {
+ switch (state.NewValue)
+ {
+ case TernaryState.False:
+ RemoveSampleBank(bankName);
+ break;
+
+ case TernaryState.True:
+ AddSampleBank(bankName);
+ break;
+ }
+ };
+
+ SelectionBankStates[bankName] = bindable;
+ }
+
foreach (string sampleName in HitSampleInfo.AllAdditions)
{
var bindable = new Bindable
@@ -104,12 +133,48 @@ namespace osu.Game.Screens.Edit.Compose.Components
{
bindable.Value = GetStateFromSelection(SelectedItems, h => h.Samples.Any(s => s.Name == sampleName));
}
+
+ foreach ((string bankName, var bindable) in SelectionBankStates)
+ {
+ bindable.Value = GetStateFromSelection(SelectedItems, h => h.SampleControlPoint.SampleBank == bankName);
+ }
}
#endregion
#region Ternary state changes
+ ///
+ /// Adds a sample bank to all selected s.
+ ///
+ /// The name of the sample bank.
+ public void AddSampleBank(string bankName)
+ {
+ EditorBeatmap.PerformOnSelection(h =>
+ {
+ if (h.SampleControlPoint.SampleBank == bankName)
+ return;
+
+ h.SampleControlPoint.SampleBank = bankName;
+ EditorBeatmap.Update(h);
+ });
+ }
+
+ ///
+ /// Removes a sample bank from all selected s.
+ ///
+ /// The name of the sample bank.
+ public void RemoveSampleBank(string bankName)
+ {
+ EditorBeatmap.PerformOnSelection(h =>
+ {
+ if (h.SampleControlPoint.SampleBank == bankName)
+ h.SampleControlPoint.SampleBankBindable.SetDefault();
+
+ EditorBeatmap.Update(h);
+ });
+ }
+
///
/// Adds a hit sample to all selected s.
///
@@ -174,11 +239,17 @@ namespace osu.Game.Screens.Edit.Compose.Components
yield return new TernaryStateToggleMenuItem("New combo") { State = { BindTarget = SelectionNewComboState } };
}
- yield return new OsuMenuItem("Sound")
+ yield return new OsuMenuItem("Sample")
{
Items = SelectionSampleStates.Select(kvp =>
new TernaryStateToggleMenuItem(kvp.Value.Description) { State = { BindTarget = kvp.Value } }).ToArray()
};
+
+ yield return new OsuMenuItem("Bank")
+ {
+ Items = SelectionBankStates.Select(kvp =>
+ new TernaryStateToggleMenuItem(kvp.Value.Description) { State = { BindTarget = kvp.Value } }).ToArray()
+ };
}
#endregion
From 50e24ddd872bcd8e6c5c543d8fa6fcecac0f7b3b Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Wed, 19 Oct 2022 21:35:08 +0900
Subject: [PATCH 0008/1400] Add icon and radio button logic
---
osu.Game/Rulesets/Edit/HitObjectComposer.cs | 20 ++++++++-
.../Components/ComposeBlueprintContainer.cs | 42 ++++++++++++++++++-
.../Components/EditorSelectionHandler.cs | 35 +++++++++++++++-
3 files changed, 91 insertions(+), 6 deletions(-)
diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs
index 3bed835854..8857bb2dae 100644
--- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs
+++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs
@@ -71,6 +71,8 @@ namespace osu.Game.Rulesets.Edit
private FillFlowContainer togglesCollection;
+ private FillFlowContainer sampleBankTogglesCollection;
+
private IBindable hasTiming;
protected HitObjectComposer(Ruleset ruleset)
@@ -146,6 +148,16 @@ namespace osu.Game.Rulesets.Edit
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 5),
},
+ },
+ new EditorToolboxGroup("bank (Shift-Q~R)")
+ {
+ Child = sampleBankTogglesCollection = new FillFlowContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Direction = FillDirection.Vertical,
+ Spacing = new Vector2(0, 5),
+ },
}
}
},
@@ -161,6 +173,8 @@ namespace osu.Game.Rulesets.Edit
TernaryStates = CreateTernaryButtons().ToArray();
togglesCollection.AddRange(TernaryStates.Select(b => new DrawableTernaryButton(b)));
+ sampleBankTogglesCollection.AddRange(BlueprintContainer.SampleBankTernaryStates.Select(b => new DrawableTernaryButton(b)));
+
setSelectTool();
EditorBeatmap.SelectedHitObjects.CollectionChanged += selectionChanged;
@@ -213,7 +227,7 @@ namespace osu.Game.Rulesets.Edit
///
/// Create all ternary states required to be displayed to the user.
///
- protected virtual IEnumerable CreateTernaryButtons() => BlueprintContainer.TernaryStates;
+ protected virtual IEnumerable CreateTernaryButtons() => BlueprintContainer.MainTernaryStates;
///
/// Construct a relevant blueprint container. This will manage hitobject selection/placement input handling and display logic.
@@ -255,7 +269,9 @@ namespace osu.Game.Rulesets.Edit
if (checkRightToggleFromKey(e.Key, out int rightIndex))
{
- var item = togglesCollection.ElementAtOrDefault(rightIndex);
+ var item = e.ShiftPressed
+ ? sampleBankTogglesCollection.ElementAtOrDefault(rightIndex)
+ : togglesCollection.ElementAtOrDefault(rightIndex);
if (item is DrawableTernaryButton button)
{
diff --git a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs
index ec07da43a0..5adc60f6a7 100644
--- a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs
+++ b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs
@@ -14,6 +14,8 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Events;
using osu.Game.Audio;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Edit.Tools;
@@ -55,7 +57,8 @@ namespace osu.Game.Screens.Edit.Compose.Components
[BackgroundDependencyLoader]
private void load()
{
- TernaryStates = CreateTernaryButtons().ToArray();
+ MainTernaryStates = CreateTernaryButtons().ToArray();
+ SampleBankTernaryStates = createSampleBankTernaryButtons().ToArray();
AddInternal(placementBlueprintContainer);
}
@@ -172,7 +175,9 @@ namespace osu.Game.Screens.Edit.Compose.Components
///
/// A collection of states which will be displayed to the user in the toolbox.
///
- public TernaryButton[] TernaryStates { get; private set; }
+ public TernaryButton[] MainTernaryStates { get; private set; }
+
+ public TernaryButton[] SampleBankTernaryStates { get; private set; }
///
/// Create all ternary states required to be displayed to the user.
@@ -186,6 +191,39 @@ namespace osu.Game.Screens.Edit.Compose.Components
yield return new TernaryButton(kvp.Value, kvp.Key.Replace("hit", string.Empty).Titleize(), () => getIconForSample(kvp.Key));
}
+ private IEnumerable createSampleBankTernaryButtons()
+ {
+ foreach (var kvp in SelectionHandler.SelectionBankStates)
+ yield return new TernaryButton(kvp.Value, kvp.Key.Titleize(), () => getIconForBank(kvp.Key));
+ }
+
+ private Drawable getIconForBank(string sampleName)
+ {
+ return new Container
+ {
+ Size = new Vector2(30, 20),
+ Children = new Drawable[]
+ {
+ new SpriteIcon
+ {
+ Size = new Vector2(8),
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.CentreLeft,
+ Icon = FontAwesome.Solid.VolumeOff
+ },
+ new OsuSpriteText
+ {
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.CentreLeft,
+ X = 10,
+ Y = -1,
+ Font = OsuFont.Default.With(weight: FontWeight.Bold, size: 20),
+ Text = $"{char.ToUpper(sampleName.First())}"
+ }
+ }
+ };
+ }
+
private Drawable getIconForSample(string sampleName)
{
switch (sampleName)
diff --git a/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs
index 1670328e58..750dedac20 100644
--- a/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs
+++ b/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs
@@ -11,6 +11,7 @@ using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Audio;
+using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Graphics.UserInterface;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Objects;
@@ -70,11 +71,38 @@ namespace osu.Game.Screens.Edit.Compose.Components
switch (state.NewValue)
{
case TernaryState.False:
- RemoveSampleBank(bankName);
+ if (SelectedItems.Count == 0)
+ {
+ // Ensure that if this is the last selected bank, it should remain selected.
+ if (SelectionBankStates.Values.All(b => b.Value == TernaryState.False))
+ bindable.Value = TernaryState.True;
+ }
+ else
+ {
+ // Never remove a sample bank.
+ // These are basically radio buttons, not toggles.
+ if (SelectedItems.All(h => h.SampleControlPoint.SampleBank == bankName))
+ bindable.Value = TernaryState.True;
+ }
+
break;
case TernaryState.True:
- AddSampleBank(bankName);
+ if (SelectedItems.Count == 0)
+ {
+ // Ensure the user can't stack multiple bank selections when there's no hitobject selection.
+ // Note that in normal scenarios this is sorted out by the feedback from applying the bank to the selected objects.
+ foreach (var other in SelectionBankStates.Values)
+ {
+ if (other != bindable)
+ other.Value = TernaryState.False;
+ }
+ }
+ else
+ {
+ AddSampleBank(bankName);
+ }
+
break;
}
};
@@ -82,6 +110,9 @@ namespace osu.Game.Screens.Edit.Compose.Components
SelectionBankStates[bankName] = bindable;
}
+ // start with normal selected.
+ SelectionBankStates[SampleControlPoint.DEFAULT_BANK].Value = TernaryState.True;
+
foreach (string sampleName in HitSampleInfo.AllAdditions)
{
var bindable = new Bindable
From 372a655be1637d8823d89532d24a28f283798906 Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Wed, 19 Oct 2022 21:39:51 +0900
Subject: [PATCH 0009/1400] Ensure placement uses currently selected bank
---
.../Components/ComposeBlueprintContainer.cs | 20 +++++++++++++++++--
1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs
index 5adc60f6a7..1c9ac83630 100644
--- a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs
+++ b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs
@@ -77,9 +77,10 @@ namespace osu.Game.Screens.Edit.Compose.Components
// we own SelectionHandler so don't need to worry about making bindable copies (for simplicity)
foreach (var kvp in SelectionHandler.SelectionSampleStates)
- {
kvp.Value.BindValueChanged(_ => updatePlacementSamples());
- }
+
+ foreach (var kvp in SelectionHandler.SelectionBankStates)
+ kvp.Value.BindValueChanged(_ => updatePlacementSamples());
}
protected override void TransferBlueprintFor(HitObject hitObject, DrawableHitObject drawableObject)
@@ -146,6 +147,9 @@ namespace osu.Game.Screens.Edit.Compose.Components
foreach (var kvp in SelectionHandler.SelectionSampleStates)
sampleChanged(kvp.Key, kvp.Value.Value);
+
+ foreach (var kvp in SelectionHandler.SelectionBankStates)
+ bankChanged(kvp.Key, kvp.Value.Value);
}
private void sampleChanged(string sampleName, TernaryState state)
@@ -170,6 +174,18 @@ namespace osu.Game.Screens.Edit.Compose.Components
}
}
+ private void bankChanged(string bankName, TernaryState state)
+ {
+ if (currentPlacement == null) return;
+
+ switch (state)
+ {
+ case TernaryState.True:
+ currentPlacement.HitObject.SampleControlPoint.SampleBank = bankName;
+ break;
+ }
+ }
+
public readonly Bindable NewCombo = new Bindable { Description = "New Combo" };
///
From b9f41611a7777951b8eebbb83ab5c9a6b27e1e12 Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Wed, 19 Oct 2022 21:48:18 +0900
Subject: [PATCH 0010/1400] Fix bank potentially being overwritten during
placement
---
osu.Game/Rulesets/Edit/PlacementBlueprint.cs | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/osu.Game/Rulesets/Edit/PlacementBlueprint.cs b/osu.Game/Rulesets/Edit/PlacementBlueprint.cs
index c8196b6865..132214a0bd 100644
--- a/osu.Game/Rulesets/Edit/PlacementBlueprint.cs
+++ b/osu.Game/Rulesets/Edit/PlacementBlueprint.cs
@@ -74,9 +74,13 @@ namespace osu.Game.Rulesets.Edit
/// Whether this call is committing a value for HitObject.StartTime and continuing with further adjustments.
protected void BeginPlacement(bool commitStart = false)
{
+ // Store and copy the bank, since it is managed by the editor UI.
+ string bank = HitObject.SampleControlPoint.SampleBank;
+
var nearestSampleControlPoint = beatmap.HitObjects.LastOrDefault(h => h.GetEndTime() < HitObject.StartTime)?.SampleControlPoint?.DeepClone() as SampleControlPoint;
HitObject.SampleControlPoint = nearestSampleControlPoint ?? new SampleControlPoint();
+ HitObject.SampleControlPoint.SampleBank = bank;
placementHandler.BeginPlacement(HitObject);
if (commitStart)
From 677b8d09f8773626b36f0e686520fb871b53220d Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Wed, 19 Oct 2022 23:54:12 +0900
Subject: [PATCH 0011/1400] Fix huge oversight causing test failures
---
osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs
index b3e6f50366..ae57ee6f5a 100644
--- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs
+++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs
@@ -413,7 +413,7 @@ namespace osu.Game.Beatmaps.Formats
string stringSampleSet = sampleSet.ToString().ToLowerInvariant();
if (stringSampleSet == @"none")
- stringSampleSet = HitSampleInfo.HIT_NORMAL;
+ stringSampleSet = HitSampleInfo.BANK_NORMAL;
if (timingChange)
{
From 849b50a38fe821720944fff0b560f33dceb25286 Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Fri, 21 Oct 2022 00:16:33 +0900
Subject: [PATCH 0012/1400] Use `ToUpperInvariant` for added safety
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Bartłomiej Dach
---
.../Edit/Compose/Components/ComposeBlueprintContainer.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs
index 1c9ac83630..eebc4c8e0e 100644
--- a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs
+++ b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs
@@ -234,7 +234,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
X = 10,
Y = -1,
Font = OsuFont.Default.With(weight: FontWeight.Bold, size: 20),
- Text = $"{char.ToUpper(sampleName.First())}"
+ Text = $"{char.ToUpperInvariant(sampleName.First())}"
}
}
};
From e1a21e0cf96df3c7deb4b4fbaf8636ef2ad7611d Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Thu, 17 Nov 2022 00:01:29 +0900
Subject: [PATCH 0013/1400] create a task to export to avoid block main thread
Code quality and remove some #nullable disable
---
osu.Game.Tests/Skins/IO/ImportSkinTest.cs | 7 +--
osu.Game/Database/LegacyBeatmapExporter.cs | 7 ++-
osu.Game/Database/LegacyExporter.cs | 54 ++++++++++++++++---
osu.Game/Database/LegacyScoreExporter.cs | 11 ++--
osu.Game/Database/LegacyScoreImporter.cs | 2 -
osu.Game/Database/LegacySkinExporter.cs | 7 ++-
osu.Game/Database/LegacySkinImporter.cs | 2 -
osu.Game/Database/RealmAccess.cs | 5 --
.../Online/Leaderboards/LeaderboardScore.cs | 5 +-
.../Overlays/Settings/Sections/SkinSection.cs | 9 +++-
osu.Game/Screens/Edit/Editor.cs | 5 +-
11 files changed, 78 insertions(+), 36 deletions(-)
diff --git a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs
index 5c20f46787..7a5f6dbd7c 100644
--- a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs
+++ b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs
@@ -15,6 +15,7 @@ using osu.Framework.Platform;
using osu.Game.Database;
using osu.Game.Extensions;
using osu.Game.IO;
+using osu.Game.Overlays;
using osu.Game.Skinning;
using SharpCompress.Archives.Zip;
@@ -122,7 +123,7 @@ namespace osu.Game.Tests.Skins.IO
import1.PerformRead(s =>
{
- new LegacySkinExporter(osu.Dependencies.Get()).ExportModelTo(s, exportStream);
+ new LegacySkinExporter(osu.Dependencies.Get(), osu.Dependencies.Get()).ExportModelTo(s, exportStream);
});
string exportFilename = import1.GetDisplayString();
@@ -204,7 +205,7 @@ namespace osu.Game.Tests.Skins.IO
Assert.IsFalse(s.Protected);
Assert.AreEqual(typeof(ArgonSkin), s.CreateInstance(skinManager).GetType());
- new LegacySkinExporter(osu.Dependencies.Get()).ExportModelTo(s, exportStream);
+ new LegacySkinExporter(osu.Dependencies.Get(), osu.Dependencies.Get()).ExportModelTo(s, exportStream);
Assert.Greater(exportStream.Length, 0);
});
@@ -239,7 +240,7 @@ namespace osu.Game.Tests.Skins.IO
Assert.IsFalse(s.Protected);
Assert.AreEqual(typeof(DefaultLegacySkin), s.CreateInstance(skinManager).GetType());
- new LegacySkinExporter(osu.Dependencies.Get()).ExportModelTo(s, exportStream);
+ new LegacySkinExporter(osu.Dependencies.Get(), osu.Dependencies.Get()).ExportModelTo(s, exportStream);
Assert.Greater(exportStream.Length, 0);
});
diff --git a/osu.Game/Database/LegacyBeatmapExporter.cs b/osu.Game/Database/LegacyBeatmapExporter.cs
index d064b9ed58..3e11e898f3 100644
--- a/osu.Game/Database/LegacyBeatmapExporter.cs
+++ b/osu.Game/Database/LegacyBeatmapExporter.cs
@@ -1,10 +1,9 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Framework.Platform;
using osu.Game.Beatmaps;
+using osu.Game.Overlays;
namespace osu.Game.Database
{
@@ -12,8 +11,8 @@ namespace osu.Game.Database
{
protected override string FileExtension => ".osz";
- public LegacyBeatmapExporter(Storage storage)
- : base(storage)
+ public LegacyBeatmapExporter(Storage storage, INotificationOverlay? notificationOverlay)
+ : base(storage, notificationOverlay)
{
}
}
diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs
index 16d7441dde..ed16e4bc80 100644
--- a/osu.Game/Database/LegacyExporter.cs
+++ b/osu.Game/Database/LegacyExporter.cs
@@ -1,11 +1,12 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.IO;
+using System.Threading.Tasks;
using osu.Framework.Platform;
using osu.Game.Extensions;
+using osu.Game.Overlays;
+using osu.Game.Overlays.Notifications;
using SharpCompress.Archives.Zip;
namespace osu.Game.Database
@@ -25,10 +26,17 @@ namespace osu.Game.Database
private readonly Storage exportStorage;
- protected LegacyExporter(Storage storage)
+ private readonly INotificationOverlay? notificationOverlay;
+
+ protected ProgressNotification Notification = null!;
+
+ private string filename = null!;
+
+ protected LegacyExporter(Storage storage, INotificationOverlay? notificationOverlay)
{
exportStorage = storage.GetStorageForDirectory(@"exports");
UserFileStorage = storage.GetStorageForDirectory(@"files");
+ this.notificationOverlay = notificationOverlay;
}
///
@@ -37,12 +45,25 @@ namespace osu.Game.Database
/// The item to export.
public void Export(TModel item)
{
- string filename = $"{item.GetDisplayString().GetValidFilename()}{FileExtension}";
+ filename = $"{item.GetDisplayString().GetValidFilename()}{FileExtension}";
- using (var stream = exportStorage.CreateFileSafely(filename))
- ExportModelTo(item, stream);
+ Stream stream = exportStorage.CreateFileSafely(filename);
- exportStorage.PresentFileExternally(filename);
+ Notification = new ProgressNotification
+ {
+ State = ProgressNotificationState.Active,
+ Text = "Exporting...",
+ CompletionText = "Export completed"
+ };
+ Notification.CompletionClickAction += () => exportStorage.PresentFileExternally(filename);
+ Notification.CancelRequested += () =>
+ {
+ stream.Dispose();
+ return true;
+ };
+
+ ExportModelTo(item, stream);
+ notificationOverlay?.Post(Notification);
}
///
@@ -57,7 +78,24 @@ namespace osu.Game.Database
foreach (var file in model.Files)
archive.AddEntry(file.Filename, UserFileStorage.GetStream(file.File.GetStoragePath()));
- archive.SaveTo(outputStream);
+ Task.Factory.StartNew(() =>
+ {
+ archive.SaveTo(outputStream);
+ }, Notification.CancellationToken).ContinueWith(t =>
+ {
+ if (t.IsCompletedSuccessfully)
+ {
+ outputStream.Dispose();
+ Notification.State = ProgressNotificationState.Completed;
+ }
+ else
+ {
+ if (Notification.State == ProgressNotificationState.Cancelled) return;
+
+ Notification.State = ProgressNotificationState.Cancelled;
+ Notification.Text = "Export Failed";
+ }
+ });
}
}
}
diff --git a/osu.Game/Database/LegacyScoreExporter.cs b/osu.Game/Database/LegacyScoreExporter.cs
index 6fa02b957d..1564c7b077 100644
--- a/osu.Game/Database/LegacyScoreExporter.cs
+++ b/osu.Game/Database/LegacyScoreExporter.cs
@@ -1,12 +1,12 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.IO;
using System.Linq;
using osu.Framework.Platform;
using osu.Game.Extensions;
+using osu.Game.Overlays;
+using osu.Game.Overlays.Notifications;
using osu.Game.Scoring;
namespace osu.Game.Database
@@ -15,8 +15,8 @@ namespace osu.Game.Database
{
protected override string FileExtension => ".osr";
- public LegacyScoreExporter(Storage storage)
- : base(storage)
+ public LegacyScoreExporter(Storage storage, INotificationOverlay? notificationOverlay)
+ : base(storage, notificationOverlay)
{
}
@@ -28,6 +28,9 @@ namespace osu.Game.Database
using (var inputStream = UserFileStorage.GetStream(file.File.GetStoragePath()))
inputStream.CopyTo(outputStream);
+
+ Notification.State = ProgressNotificationState.Completed;
+ outputStream.Dispose();
}
}
}
diff --git a/osu.Game/Database/LegacyScoreImporter.cs b/osu.Game/Database/LegacyScoreImporter.cs
index f61241141e..131b4ffb0e 100644
--- a/osu.Game/Database/LegacyScoreImporter.cs
+++ b/osu.Game/Database/LegacyScoreImporter.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Collections.Generic;
using System.IO;
diff --git a/osu.Game/Database/LegacySkinExporter.cs b/osu.Game/Database/LegacySkinExporter.cs
index 1d5364fb8d..a78d69e7b9 100644
--- a/osu.Game/Database/LegacySkinExporter.cs
+++ b/osu.Game/Database/LegacySkinExporter.cs
@@ -1,9 +1,8 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Framework.Platform;
+using osu.Game.Overlays;
using osu.Game.Skinning;
namespace osu.Game.Database
@@ -12,8 +11,8 @@ namespace osu.Game.Database
{
protected override string FileExtension => ".osk";
- public LegacySkinExporter(Storage storage)
- : base(storage)
+ public LegacySkinExporter(Storage storage, INotificationOverlay? notificationOverlay)
+ : base(storage, notificationOverlay)
{
}
}
diff --git a/osu.Game/Database/LegacySkinImporter.cs b/osu.Game/Database/LegacySkinImporter.cs
index 42b2f2e1d8..2f05ccae45 100644
--- a/osu.Game/Database/LegacySkinImporter.cs
+++ b/osu.Game/Database/LegacySkinImporter.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Game.Skinning;
namespace osu.Game.Database
diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs
index 1a938c12e5..5a7ead1c59 100644
--- a/osu.Game/Database/RealmAccess.cs
+++ b/osu.Game/Database/RealmAccess.cs
@@ -173,11 +173,6 @@ namespace osu.Game.Database
if (!Filename.EndsWith(realm_extension, StringComparison.Ordinal))
Filename += realm_extension;
-#if DEBUG
- if (!DebugUtils.IsNUnitRunning)
- applyFilenameSchemaSuffix(ref Filename);
-#endif
-
string newerVersionFilename = $"{Filename.Replace(realm_extension, string.Empty)}_newer_version{realm_extension}";
// Attempt to recover a newer database version if available.
diff --git a/osu.Game/Online/Leaderboards/LeaderboardScore.cs b/osu.Game/Online/Leaderboards/LeaderboardScore.cs
index a7b6bd044d..72f1a94ec8 100644
--- a/osu.Game/Online/Leaderboards/LeaderboardScore.cs
+++ b/osu.Game/Online/Leaderboards/LeaderboardScore.cs
@@ -75,6 +75,9 @@ namespace osu.Game.Online.Leaderboards
[Resolved]
private Storage storage { get; set; }
+ [Resolved]
+ private INotificationOverlay notificationOverlay { get; set; }
+
public ITooltip GetCustomTooltip() => new LeaderboardScoreTooltip();
public virtual ScoreInfo TooltipContent => Score;
@@ -427,7 +430,7 @@ namespace osu.Game.Online.Leaderboards
if (Score.Files.Count > 0)
{
- items.Add(new OsuMenuItem("Export", MenuItemType.Standard, () => new LegacyScoreExporter(storage).Export(Score)));
+ items.Add(new OsuMenuItem("Export", MenuItemType.Standard, () => new LegacyScoreExporter(storage, notificationOverlay).Export(Score)));
items.Add(new OsuMenuItem(CommonStrings.ButtonsDelete, MenuItemType.Destructive, () => dialogOverlay?.Push(new LocalScoreDeleteDialog(Score))));
}
diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs
index f602b73065..df6f719b1e 100644
--- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs
+++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs
@@ -141,11 +141,16 @@ namespace osu.Game.Overlays.Settings.Sections
[Resolved]
private Storage storage { get; set; }
+ [CanBeNull]
+ private INotificationOverlay notificationOverlay;
+
private Bindable currentSkin;
[BackgroundDependencyLoader]
- private void load()
+ private void load(INotificationOverlay notificationOverlay)
{
+ this.notificationOverlay = notificationOverlay;
+
Text = SkinSettingsStrings.ExportSkinButton;
Action = export;
}
@@ -162,7 +167,7 @@ namespace osu.Game.Overlays.Settings.Sections
{
try
{
- currentSkin.Value.SkinInfo.PerformRead(s => new LegacySkinExporter(storage).Export(s));
+ currentSkin.Value.SkinInfo.PerformRead(s => new LegacySkinExporter(storage, notificationOverlay).Export(s));
}
catch (Exception e)
{
diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs
index bb390dfbf3..03bdd69f34 100644
--- a/osu.Game/Screens/Edit/Editor.cs
+++ b/osu.Game/Screens/Edit/Editor.cs
@@ -93,6 +93,9 @@ namespace osu.Game.Screens.Edit
[Resolved]
private Storage storage { get; set; }
+ [Resolved]
+ private INotificationOverlay notificationOverlay { get; set; }
+
[Resolved(canBeNull: true)]
private IDialogOverlay dialogOverlay { get; set; }
@@ -938,7 +941,7 @@ namespace osu.Game.Screens.Edit
private void exportBeatmap()
{
Save();
- new LegacyBeatmapExporter(storage).Export(Beatmap.Value.BeatmapSetInfo);
+ new LegacyBeatmapExporter(storage, notificationOverlay).Export(Beatmap.Value.BeatmapSetInfo);
}
///
From 4b29941b4705a38ea26ce4ca617caf75c3be4f1a Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Thu, 17 Nov 2022 23:38:24 +0900
Subject: [PATCH 0014/1400] add `LegacyExportManager`
---
osu.Game.Tests/Skins/IO/ImportSkinTest.cs | 4 +-
osu.Game/Database/LegacyBeatmapExporter.cs | 8 +-
osu.Game/Database/LegacyExportManager.cs | 55 +++++++++
osu.Game/Database/LegacyExporter.cs | 102 ----------------
osu.Game/Database/LegacyModelExporter.cs | 113 ++++++++++++++++++
osu.Game/Database/LegacyScoreExporter.cs | 34 +++---
osu.Game/Database/LegacySkinExporter.cs | 8 +-
.../Online/Leaderboards/LeaderboardScore.cs | 5 +-
osu.Game/OsuGame.cs | 4 +
.../Overlays/Settings/Sections/SkinSection.cs | 10 +-
osu.Game/Screens/Edit/Editor.cs | 9 +-
11 files changed, 209 insertions(+), 143 deletions(-)
create mode 100644 osu.Game/Database/LegacyExportManager.cs
delete mode 100644 osu.Game/Database/LegacyExporter.cs
create mode 100644 osu.Game/Database/LegacyModelExporter.cs
diff --git a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs
index 7a5f6dbd7c..ef68b06476 100644
--- a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs
+++ b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs
@@ -121,9 +121,9 @@ namespace osu.Game.Tests.Skins.IO
var import1 = await loadSkinIntoOsu(osu, new ImportTask(createOskWithIni("name 1", "author 1"), "custom.osk"));
assertCorrectMetadata(import1, "name 1 [custom]", "author 1", osu);
- import1.PerformRead(s =>
+ import1.PerformRead(async s =>
{
- new LegacySkinExporter(osu.Dependencies.Get(), osu.Dependencies.Get()).ExportModelTo(s, exportStream);
+ await new LegacyExportManager().ExportAsync(s, exportStream);
});
string exportFilename = import1.GetDisplayString();
diff --git a/osu.Game/Database/LegacyBeatmapExporter.cs b/osu.Game/Database/LegacyBeatmapExporter.cs
index 3e11e898f3..140ce43fbd 100644
--- a/osu.Game/Database/LegacyBeatmapExporter.cs
+++ b/osu.Game/Database/LegacyBeatmapExporter.cs
@@ -3,16 +3,16 @@
using osu.Framework.Platform;
using osu.Game.Beatmaps;
-using osu.Game.Overlays;
+using osu.Game.Overlays.Notifications;
namespace osu.Game.Database
{
- public class LegacyBeatmapExporter : LegacyExporter
+ public class LegacyBeatmapExporter : LegacyModelExporter
{
protected override string FileExtension => ".osz";
- public LegacyBeatmapExporter(Storage storage, INotificationOverlay? notificationOverlay)
- : base(storage, notificationOverlay)
+ public LegacyBeatmapExporter(Storage storage, RealmAccess realm, ProgressNotification notification)
+ : base(storage, realm, notification)
{
}
}
diff --git a/osu.Game/Database/LegacyExportManager.cs b/osu.Game/Database/LegacyExportManager.cs
new file mode 100644
index 0000000000..18cd93ea35
--- /dev/null
+++ b/osu.Game/Database/LegacyExportManager.cs
@@ -0,0 +1,55 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Threading.Tasks;
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Platform;
+using osu.Framework.Testing;
+using osu.Game.Beatmaps;
+using osu.Game.Overlays;
+using osu.Game.Overlays.Notifications;
+using osu.Game.Scoring;
+using osu.Game.Skinning;
+
+namespace osu.Game.Database
+{
+ [ExcludeFromDynamicCompile]
+ public class LegacyExportManager : Component
+ {
+ [Resolved]
+ private RealmAccess realmAccess { get; set; } = null!;
+
+ [Resolved]
+ private Storage exportStorage { get; set; } = null!;
+
+ [Resolved]
+ private INotificationOverlay? notifications { get; set; }
+
+ public async Task ExportAsync(IHasGuidPrimaryKey item)
+ {
+ var notification = new ProgressNotification
+ {
+ State = ProgressNotificationState.Active,
+ Text = "Exporting...",
+ CompletionText = "Export completed"
+ };
+ notifications?.Post(notification);
+
+ switch (item)
+ {
+ case SkinInfo:
+ await new LegacySkinExporter(exportStorage, realmAccess, notification).ExportASync(item);
+ break;
+
+ case ScoreInfo:
+ await new LegacyScoreExporter(exportStorage, realmAccess, notification).ExportASync(item, false);
+ break;
+
+ case BeatmapSetInfo:
+ await new LegacyBeatmapExporter(exportStorage, realmAccess, notification).ExportASync(item);
+ break;
+ }
+ }
+ }
+}
diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs
deleted file mode 100644
index ed16e4bc80..0000000000
--- a/osu.Game/Database/LegacyExporter.cs
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-using System.IO;
-using System.Threading.Tasks;
-using osu.Framework.Platform;
-using osu.Game.Extensions;
-using osu.Game.Overlays;
-using osu.Game.Overlays.Notifications;
-using SharpCompress.Archives.Zip;
-
-namespace osu.Game.Database
-{
- ///
- /// A class which handles exporting legacy user data of a single type from osu-stable.
- ///
- public abstract class LegacyExporter
- where TModel : class, IHasNamedFiles
- {
- ///
- /// The file extension for exports (including the leading '.').
- ///
- protected abstract string FileExtension { get; }
-
- protected readonly Storage UserFileStorage;
-
- private readonly Storage exportStorage;
-
- private readonly INotificationOverlay? notificationOverlay;
-
- protected ProgressNotification Notification = null!;
-
- private string filename = null!;
-
- protected LegacyExporter(Storage storage, INotificationOverlay? notificationOverlay)
- {
- exportStorage = storage.GetStorageForDirectory(@"exports");
- UserFileStorage = storage.GetStorageForDirectory(@"files");
- this.notificationOverlay = notificationOverlay;
- }
-
- ///
- /// Exports an item to a legacy (.zip based) package.
- ///
- /// The item to export.
- public void Export(TModel item)
- {
- filename = $"{item.GetDisplayString().GetValidFilename()}{FileExtension}";
-
- Stream stream = exportStorage.CreateFileSafely(filename);
-
- Notification = new ProgressNotification
- {
- State = ProgressNotificationState.Active,
- Text = "Exporting...",
- CompletionText = "Export completed"
- };
- Notification.CompletionClickAction += () => exportStorage.PresentFileExternally(filename);
- Notification.CancelRequested += () =>
- {
- stream.Dispose();
- return true;
- };
-
- ExportModelTo(item, stream);
- notificationOverlay?.Post(Notification);
- }
-
- ///
- /// Exports an item to the given output stream.
- ///
- /// The item to export.
- /// The output stream to export to.
- public virtual void ExportModelTo(TModel model, Stream outputStream)
- {
- using (var archive = ZipArchive.Create())
- {
- foreach (var file in model.Files)
- archive.AddEntry(file.Filename, UserFileStorage.GetStream(file.File.GetStoragePath()));
-
- Task.Factory.StartNew(() =>
- {
- archive.SaveTo(outputStream);
- }, Notification.CancellationToken).ContinueWith(t =>
- {
- if (t.IsCompletedSuccessfully)
- {
- outputStream.Dispose();
- Notification.State = ProgressNotificationState.Completed;
- }
- else
- {
- if (Notification.State == ProgressNotificationState.Cancelled) return;
-
- Notification.State = ProgressNotificationState.Cancelled;
- Notification.Text = "Export Failed";
- }
- });
- }
- }
- }
-}
diff --git a/osu.Game/Database/LegacyModelExporter.cs b/osu.Game/Database/LegacyModelExporter.cs
new file mode 100644
index 0000000000..d181226803
--- /dev/null
+++ b/osu.Game/Database/LegacyModelExporter.cs
@@ -0,0 +1,113 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Linq;
+using System.Threading.Tasks;
+using osu.Framework.Platform;
+using osu.Game.Extensions;
+using osu.Game.Overlays.Notifications;
+using Realms;
+using SharpCompress.Archives.Zip;
+
+namespace osu.Game.Database
+{
+ ///
+ /// A class which handles exporting legacy user data of a single type from osu-stable.
+ ///
+ public abstract class LegacyModelExporter
+ where TModel : RealmObject
+ {
+ ///
+ /// The file extension for exports (including the leading '.').
+ ///
+ protected abstract string FileExtension { get; }
+
+ protected readonly Storage UserFileStorage;
+
+ private readonly Storage exportStorage;
+
+ private readonly RealmAccess realmAccess;
+
+ private readonly ProgressNotification notification;
+
+ protected ProgressNotification Notification = null!;
+
+ private string filename = null!;
+
+ protected LegacyModelExporter(Storage storage, RealmAccess realm, ProgressNotification notification)
+ {
+ exportStorage = storage.GetStorageForDirectory(@"exports");
+ UserFileStorage = storage.GetStorageForDirectory(@"files");
+ this.notification = notification;
+ realmAccess = realm;
+ }
+
+ public async Task ExportASync(IHasGuidPrimaryKey uuid, bool needZipArchive = true)
+ {
+ Guid id = uuid.ID;
+ await Task.Run(() =>
+ {
+ realmAccess.Run(r =>
+ {
+ if (r.Find(id) is IHasNamedFiles model)
+ {
+ filename = $"{model.GetDisplayString().GetValidFilename()}{FileExtension}";
+ }
+ else
+ {
+ return;
+ }
+
+ using (var outputStream = exportStorage.CreateFileSafely(filename))
+ {
+ if (needZipArchive)
+ {
+ using (var archive = ZipArchive.Create())
+ {
+ float i = 0;
+
+ foreach (var file in model.Files)
+ {
+ if (notification.CancellationToken.IsCancellationRequested) return;
+ archive.AddEntry(file.Filename, UserFileStorage.GetStream(file.File.GetStoragePath()));
+ i++;
+ notification.Progress = i / model.Files.Count();
+ notification.Text = $"Exporting... ({i}/{model.Files.Count()})";
+ }
+
+ notification.Text = "Saving Zip Archive...";
+ archive.SaveTo(outputStream);
+ }
+ }
+ else
+ {
+ var file = model.Files.SingleOrDefault();
+ if (file == null)
+ return;
+
+ using (var inputStream = UserFileStorage.GetStream(file.File.GetStoragePath()))
+ inputStream.CopyTo(outputStream);
+ }
+ }
+ });
+ }).ContinueWith(t =>
+ {
+ if (t.IsFaulted)
+ {
+ notification.State = ProgressNotificationState.Cancelled;
+ return;
+ }
+
+ if (notification.CancellationToken.IsCancellationRequested)
+ {
+ return;
+ }
+
+ notification.CompletionText = "Export Complete, Click to open the folder";
+ notification.CompletionClickAction += () => exportStorage.PresentFileExternally(filename);
+ notification.State = ProgressNotificationState.Completed;
+ });
+ }
+ }
+}
diff --git a/osu.Game/Database/LegacyScoreExporter.cs b/osu.Game/Database/LegacyScoreExporter.cs
index 1564c7b077..ffbec0530b 100644
--- a/osu.Game/Database/LegacyScoreExporter.cs
+++ b/osu.Game/Database/LegacyScoreExporter.cs
@@ -1,36 +1,32 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using System.IO;
-using System.Linq;
using osu.Framework.Platform;
-using osu.Game.Extensions;
-using osu.Game.Overlays;
using osu.Game.Overlays.Notifications;
using osu.Game.Scoring;
namespace osu.Game.Database
{
- public class LegacyScoreExporter : LegacyExporter
+ public class LegacyScoreExporter : LegacyModelExporter
{
protected override string FileExtension => ".osr";
- public LegacyScoreExporter(Storage storage, INotificationOverlay? notificationOverlay)
- : base(storage, notificationOverlay)
+ public LegacyScoreExporter(Storage storage, RealmAccess realm, ProgressNotification notification)
+ : base(storage, realm, notification)
{
}
- public override void ExportModelTo(ScoreInfo model, Stream outputStream)
- {
- var file = model.Files.SingleOrDefault();
- if (file == null)
- return;
-
- using (var inputStream = UserFileStorage.GetStream(file.File.GetStoragePath()))
- inputStream.CopyTo(outputStream);
-
- Notification.State = ProgressNotificationState.Completed;
- outputStream.Dispose();
- }
+ //public override void ExportModelTo(ScoreInfo model, Stream outputStream)
+ //{
+ // var file = model.Files.SingleOrDefault();
+ // if (file == null)
+ // return;
+ //
+ // using (var inputStream = UserFileStorage.GetStream(file.File.GetStoragePath()))
+ // inputStream.CopyTo(outputStream);
+ //
+ // Notification.State = ProgressNotificationState.Completed;
+ // outputStream.Dispose();
+ //}
}
}
diff --git a/osu.Game/Database/LegacySkinExporter.cs b/osu.Game/Database/LegacySkinExporter.cs
index a78d69e7b9..a35636c248 100644
--- a/osu.Game/Database/LegacySkinExporter.cs
+++ b/osu.Game/Database/LegacySkinExporter.cs
@@ -2,17 +2,17 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Platform;
-using osu.Game.Overlays;
+using osu.Game.Overlays.Notifications;
using osu.Game.Skinning;
namespace osu.Game.Database
{
- public class LegacySkinExporter : LegacyExporter
+ public class LegacySkinExporter : LegacyModelExporter
{
protected override string FileExtension => ".osk";
- public LegacySkinExporter(Storage storage, INotificationOverlay? notificationOverlay)
- : base(storage, notificationOverlay)
+ public LegacySkinExporter(Storage storage, RealmAccess realm, ProgressNotification notification)
+ : base(storage, realm, notification)
{
}
}
diff --git a/osu.Game/Online/Leaderboards/LeaderboardScore.cs b/osu.Game/Online/Leaderboards/LeaderboardScore.cs
index 72f1a94ec8..e2f640a44c 100644
--- a/osu.Game/Online/Leaderboards/LeaderboardScore.cs
+++ b/osu.Game/Online/Leaderboards/LeaderboardScore.cs
@@ -6,6 +6,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Threading.Tasks;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
@@ -76,7 +77,7 @@ namespace osu.Game.Online.Leaderboards
private Storage storage { get; set; }
[Resolved]
- private INotificationOverlay notificationOverlay { get; set; }
+ private LegacyExportManager exporter { get; set; }
public ITooltip GetCustomTooltip() => new LeaderboardScoreTooltip();
public virtual ScoreInfo TooltipContent => Score;
@@ -430,7 +431,7 @@ namespace osu.Game.Online.Leaderboards
if (Score.Files.Count > 0)
{
- items.Add(new OsuMenuItem("Export", MenuItemType.Standard, () => new LegacyScoreExporter(storage, notificationOverlay).Export(Score)));
+ items.Add(new OsuMenuItem("Export", MenuItemType.Standard, () => Task.Run(() => exporter.ExportAsync(Score))));
items.Add(new OsuMenuItem(CommonStrings.ButtonsDelete, MenuItemType.Destructive, () => dialogOverlay?.Push(new LocalScoreDeleteDialog(Score))));
}
diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs
index a93c187e53..09647f9d1e 100644
--- a/osu.Game/OsuGame.cs
+++ b/osu.Game/OsuGame.cs
@@ -126,6 +126,9 @@ namespace osu.Game
[Cached]
private readonly LegacyImportManager legacyImportManager = new LegacyImportManager();
+ [Cached]
+ private readonly LegacyExportManager legacyExportManager = new LegacyExportManager();
+
[Cached]
private readonly ScreenshotManager screenshotManager = new ScreenshotManager();
@@ -868,6 +871,7 @@ namespace osu.Game
}), rightFloatingOverlayContent.Add, true);
loadComponentSingleFile(legacyImportManager, Add);
+ loadComponentSingleFile(legacyExportManager, Add);
loadComponentSingleFile(screenshotManager, Add);
diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs
index df6f719b1e..6cd9e591e1 100644
--- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs
+++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs
@@ -141,16 +141,14 @@ namespace osu.Game.Overlays.Settings.Sections
[Resolved]
private Storage storage { get; set; }
- [CanBeNull]
- private INotificationOverlay notificationOverlay;
+ [Resolved]
+ private LegacyExportManager exporter { get; set; }
private Bindable currentSkin;
[BackgroundDependencyLoader]
- private void load(INotificationOverlay notificationOverlay)
+ private void load()
{
- this.notificationOverlay = notificationOverlay;
-
Text = SkinSettingsStrings.ExportSkinButton;
Action = export;
}
@@ -167,7 +165,7 @@ namespace osu.Game.Overlays.Settings.Sections
{
try
{
- currentSkin.Value.SkinInfo.PerformRead(s => new LegacySkinExporter(storage, notificationOverlay).Export(s));
+ currentSkin.Value.SkinInfo.PerformRead(s => exporter.ExportAsync(s));
}
catch (Exception e)
{
diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs
index 03bdd69f34..e266239f34 100644
--- a/osu.Game/Screens/Edit/Editor.cs
+++ b/osu.Game/Screens/Edit/Editor.cs
@@ -6,6 +6,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Threading.Tasks;
using JetBrains.Annotations;
using osu.Framework;
using osu.Framework.Allocation;
@@ -93,9 +94,6 @@ namespace osu.Game.Screens.Edit
[Resolved]
private Storage storage { get; set; }
- [Resolved]
- private INotificationOverlay notificationOverlay { get; set; }
-
[Resolved(canBeNull: true)]
private IDialogOverlay dialogOverlay { get; set; }
@@ -185,6 +183,9 @@ namespace osu.Game.Screens.Edit
private Bindable editorBackgroundDim;
private Bindable editorHitMarkers;
+ [Resolved]
+ private LegacyExportManager exporter { get; set; }
+
public Editor(EditorLoader loader = null)
{
this.loader = loader;
@@ -941,7 +942,7 @@ namespace osu.Game.Screens.Edit
private void exportBeatmap()
{
Save();
- new LegacyBeatmapExporter(storage, notificationOverlay).Export(Beatmap.Value.BeatmapSetInfo);
+ Task.Run(() => exporter.ExportAsync(Beatmap.Value.BeatmapSetInfo));
}
///
From fc4a6cb125c50668765d8b43f5bcf88cb242f28c Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Sat, 19 Nov 2022 01:02:35 +0900
Subject: [PATCH 0015/1400] working with test
---
osu.Game.Tests/Skins/IO/ImportSkinTest.cs | 31 +++---
osu.Game/Database/LegacyBeatmapExporter.cs | 5 +-
osu.Game/Database/LegacyExportManager.cs | 2 +-
osu.Game/Database/LegacyModelExporter.cs | 106 +++++++++++----------
osu.Game/Database/LegacyScoreExporter.cs | 52 +++++++---
osu.Game/Database/LegacySkinExporter.cs | 5 +-
6 files changed, 113 insertions(+), 88 deletions(-)
diff --git a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs
index ef68b06476..0c3c459e87 100644
--- a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs
+++ b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs
@@ -10,12 +10,11 @@ using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using NUnit.Framework;
using osu.Framework.Allocation;
-using osu.Framework.Extensions;
using osu.Framework.Platform;
using osu.Game.Database;
using osu.Game.Extensions;
using osu.Game.IO;
-using osu.Game.Overlays;
+using osu.Game.Overlays.Notifications;
using osu.Game.Skinning;
using SharpCompress.Archives.Zip;
@@ -121,9 +120,9 @@ namespace osu.Game.Tests.Skins.IO
var import1 = await loadSkinIntoOsu(osu, new ImportTask(createOskWithIni("name 1", "author 1"), "custom.osk"));
assertCorrectMetadata(import1, "name 1 [custom]", "author 1", osu);
- import1.PerformRead(async s =>
+ await import1.PerformRead(async s =>
{
- await new LegacyExportManager().ExportAsync(s, exportStream);
+ await new LegacySkinExporter(osu.Dependencies.Get(), osu.Dependencies.Get(), new ProgressNotification(), exportStream).ExportASync(s);
});
string exportFilename = import1.GetDisplayString();
@@ -190,7 +189,7 @@ namespace osu.Game.Tests.Skins.IO
});
[Test]
- public Task TestExportThenImportDefaultSkin() => runSkinTest(osu =>
+ public Task TestExportThenImportDefaultSkin() => runSkinTest(async osu =>
{
var skinManager = osu.Dependencies.Get();
@@ -200,30 +199,28 @@ namespace osu.Game.Tests.Skins.IO
Guid originalSkinId = skinManager.CurrentSkinInfo.Value.ID;
- skinManager.CurrentSkinInfo.Value.PerformRead(s =>
+ await skinManager.CurrentSkinInfo.Value.PerformRead(async s =>
{
Assert.IsFalse(s.Protected);
Assert.AreEqual(typeof(ArgonSkin), s.CreateInstance(skinManager).GetType());
- new LegacySkinExporter(osu.Dependencies.Get(), osu.Dependencies.Get()).ExportModelTo(s, exportStream);
+ await new LegacySkinExporter(osu.Dependencies.Get(), osu.Dependencies.Get(), new ProgressNotification(), exportStream).ExportASync(s);
Assert.Greater(exportStream.Length, 0);
});
- var imported = skinManager.Import(new ImportTask(exportStream, "exported.osk"));
+ var imported = await skinManager.Import(new ImportTask(exportStream, "exported.osk"));
- imported.GetResultSafely().PerformRead(s =>
+ imported.PerformRead(s =>
{
Assert.IsFalse(s.Protected);
Assert.AreNotEqual(originalSkinId, s.ID);
Assert.AreEqual(typeof(ArgonSkin), s.CreateInstance(skinManager).GetType());
});
-
- return Task.CompletedTask;
});
[Test]
- public Task TestExportThenImportClassicSkin() => runSkinTest(osu =>
+ public Task TestExportThenImportClassicSkin() => runSkinTest(async osu =>
{
var skinManager = osu.Dependencies.Get();
@@ -235,26 +232,24 @@ namespace osu.Game.Tests.Skins.IO
Guid originalSkinId = skinManager.CurrentSkinInfo.Value.ID;
- skinManager.CurrentSkinInfo.Value.PerformRead(s =>
+ await skinManager.CurrentSkinInfo.Value.PerformRead(async s =>
{
Assert.IsFalse(s.Protected);
Assert.AreEqual(typeof(DefaultLegacySkin), s.CreateInstance(skinManager).GetType());
- new LegacySkinExporter(osu.Dependencies.Get(), osu.Dependencies.Get()).ExportModelTo(s, exportStream);
+ await new LegacySkinExporter(osu.Dependencies.Get(), osu.Dependencies.Get(), new ProgressNotification(), exportStream).ExportASync(s);
Assert.Greater(exportStream.Length, 0);
});
- var imported = skinManager.Import(new ImportTask(exportStream, "exported.osk"));
+ var imported = await skinManager.Import(new ImportTask(exportStream, "exported.osk"));
- imported.GetResultSafely().PerformRead(s =>
+ imported.PerformRead(s =>
{
Assert.IsFalse(s.Protected);
Assert.AreNotEqual(originalSkinId, s.ID);
Assert.AreEqual(typeof(DefaultLegacySkin), s.CreateInstance(skinManager).GetType());
});
-
- return Task.CompletedTask;
});
#endregion
diff --git a/osu.Game/Database/LegacyBeatmapExporter.cs b/osu.Game/Database/LegacyBeatmapExporter.cs
index 140ce43fbd..5505d141ee 100644
--- a/osu.Game/Database/LegacyBeatmapExporter.cs
+++ b/osu.Game/Database/LegacyBeatmapExporter.cs
@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System.IO;
using osu.Framework.Platform;
using osu.Game.Beatmaps;
using osu.Game.Overlays.Notifications;
@@ -11,8 +12,8 @@ namespace osu.Game.Database
{
protected override string FileExtension => ".osz";
- public LegacyBeatmapExporter(Storage storage, RealmAccess realm, ProgressNotification notification)
- : base(storage, realm, notification)
+ public LegacyBeatmapExporter(Storage storage, RealmAccess realm, ProgressNotification notification, Stream? stream = null)
+ : base(storage, realm, notification, stream)
{
}
}
diff --git a/osu.Game/Database/LegacyExportManager.cs b/osu.Game/Database/LegacyExportManager.cs
index 18cd93ea35..08594ab020 100644
--- a/osu.Game/Database/LegacyExportManager.cs
+++ b/osu.Game/Database/LegacyExportManager.cs
@@ -43,7 +43,7 @@ namespace osu.Game.Database
break;
case ScoreInfo:
- await new LegacyScoreExporter(exportStorage, realmAccess, notification).ExportASync(item, false);
+ await new LegacyScoreExporter(exportStorage, realmAccess, notification).ExportASync(item);
break;
case BeatmapSetInfo:
diff --git a/osu.Game/Database/LegacyModelExporter.cs b/osu.Game/Database/LegacyModelExporter.cs
index d181226803..a4b0f7ba9d 100644
--- a/osu.Game/Database/LegacyModelExporter.cs
+++ b/osu.Game/Database/LegacyModelExporter.cs
@@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System;
+using System.IO;
using System.Linq;
using System.Threading.Tasks;
using osu.Framework.Platform;
@@ -25,89 +26,92 @@ namespace osu.Game.Database
protected readonly Storage UserFileStorage;
- private readonly Storage exportStorage;
+ protected readonly Storage ExportStorage;
- private readonly RealmAccess realmAccess;
+ protected readonly RealmAccess RealmAccess;
- private readonly ProgressNotification notification;
+ protected readonly ProgressNotification Notification;
- protected ProgressNotification Notification = null!;
+ protected string Filename = null!;
- private string filename = null!;
+ protected Stream? OutputStream;
- protected LegacyModelExporter(Storage storage, RealmAccess realm, ProgressNotification notification)
+ protected bool ShouldDisposeStream;
+
+ protected LegacyModelExporter(Storage storage, RealmAccess realm, ProgressNotification notification, Stream? stream = null)
{
- exportStorage = storage.GetStorageForDirectory(@"exports");
+ ExportStorage = storage.GetStorageForDirectory(@"exports");
UserFileStorage = storage.GetStorageForDirectory(@"files");
- this.notification = notification;
- realmAccess = realm;
+ Notification = notification;
+ RealmAccess = realm;
+ OutputStream = stream;
+ ShouldDisposeStream = false;
}
- public async Task ExportASync(IHasGuidPrimaryKey uuid, bool needZipArchive = true)
+ public virtual async Task ExportASync(IHasGuidPrimaryKey uuid)
{
Guid id = uuid.ID;
await Task.Run(() =>
{
- realmAccess.Run(r =>
+ RealmAccess.Run(r =>
{
if (r.Find(id) is IHasNamedFiles model)
{
- filename = $"{model.GetDisplayString().GetValidFilename()}{FileExtension}";
+ Filename = $"{model.GetDisplayString().GetValidFilename()}{FileExtension}";
}
else
{
return;
}
- using (var outputStream = exportStorage.CreateFileSafely(filename))
+ if (OutputStream == null)
{
- if (needZipArchive)
+ OutputStream = ExportStorage.CreateFileSafely(Filename);
+ ShouldDisposeStream = true;
+ }
+
+ using (var archive = ZipArchive.Create())
+ {
+ float i = 0;
+
+ foreach (var file in model.Files)
{
- using (var archive = ZipArchive.Create())
- {
- float i = 0;
+ if (Notification.CancellationToken.IsCancellationRequested) return;
- foreach (var file in model.Files)
- {
- if (notification.CancellationToken.IsCancellationRequested) return;
- archive.AddEntry(file.Filename, UserFileStorage.GetStream(file.File.GetStoragePath()));
- i++;
- notification.Progress = i / model.Files.Count();
- notification.Text = $"Exporting... ({i}/{model.Files.Count()})";
- }
-
- notification.Text = "Saving Zip Archive...";
- archive.SaveTo(outputStream);
- }
+ archive.AddEntry(file.Filename, UserFileStorage.GetStream(file.File.GetStoragePath()));
+ i++;
+ Notification.Progress = i / model.Files.Count();
+ Notification.Text = $"Exporting... ({i}/{model.Files.Count()})";
}
- else
- {
- var file = model.Files.SingleOrDefault();
- if (file == null)
- return;
- using (var inputStream = UserFileStorage.GetStream(file.File.GetStoragePath()))
- inputStream.CopyTo(outputStream);
- }
+ Notification.Text = "Saving Zip Archive...";
+ archive.SaveTo(OutputStream);
}
});
- }).ContinueWith(t =>
+ }).ContinueWith(OnComplete);
+ }
+
+ protected void OnComplete(Task t)
+ {
+ if (ShouldDisposeStream)
{
- if (t.IsFaulted)
- {
- notification.State = ProgressNotificationState.Cancelled;
- return;
- }
+ OutputStream?.Dispose();
+ }
- if (notification.CancellationToken.IsCancellationRequested)
- {
- return;
- }
+ if (t.IsFaulted)
+ {
+ Notification.State = ProgressNotificationState.Cancelled;
+ return;
+ }
- notification.CompletionText = "Export Complete, Click to open the folder";
- notification.CompletionClickAction += () => exportStorage.PresentFileExternally(filename);
- notification.State = ProgressNotificationState.Completed;
- });
+ if (Notification.CancellationToken.IsCancellationRequested)
+ {
+ return;
+ }
+
+ Notification.CompletionText = "Export Complete, Click to open the folder";
+ Notification.CompletionClickAction += () => ExportStorage.PresentFileExternally(Filename);
+ Notification.State = ProgressNotificationState.Completed;
}
}
}
diff --git a/osu.Game/Database/LegacyScoreExporter.cs b/osu.Game/Database/LegacyScoreExporter.cs
index ffbec0530b..3004c02978 100644
--- a/osu.Game/Database/LegacyScoreExporter.cs
+++ b/osu.Game/Database/LegacyScoreExporter.cs
@@ -1,7 +1,11 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
using osu.Framework.Platform;
+using osu.Game.Extensions;
using osu.Game.Overlays.Notifications;
using osu.Game.Scoring;
@@ -11,22 +15,42 @@ namespace osu.Game.Database
{
protected override string FileExtension => ".osr";
- public LegacyScoreExporter(Storage storage, RealmAccess realm, ProgressNotification notification)
- : base(storage, realm, notification)
+ public LegacyScoreExporter(Storage storage, RealmAccess realm, ProgressNotification notification, Stream? stream = null)
+ : base(storage, realm, notification, stream)
{
}
- //public override void ExportModelTo(ScoreInfo model, Stream outputStream)
- //{
- // var file = model.Files.SingleOrDefault();
- // if (file == null)
- // return;
- //
- // using (var inputStream = UserFileStorage.GetStream(file.File.GetStoragePath()))
- // inputStream.CopyTo(outputStream);
- //
- // Notification.State = ProgressNotificationState.Completed;
- // outputStream.Dispose();
- //}
+ public override async Task ExportASync(IHasGuidPrimaryKey uuid)
+ {
+ await Task.Run(() =>
+ {
+ RealmAccess.Run(r =>
+ {
+ if (r.Find(uuid.ID) is IHasNamedFiles model)
+ {
+ Filename = $"{model.GetDisplayString().GetValidFilename()}{FileExtension}";
+ }
+ else
+ {
+ return;
+ }
+
+ var file = model.Files.SingleOrDefault();
+ if (file == null)
+ return;
+
+ if (Notification.CancellationToken.IsCancellationRequested) return;
+
+ if (OutputStream == null)
+ {
+ OutputStream = ExportStorage.CreateFileSafely(Filename);
+ ShouldDisposeStream = true;
+ }
+
+ using (var inputStream = UserFileStorage.GetStream(file.File.GetStoragePath()))
+ inputStream.CopyTo(OutputStream);
+ });
+ }).ContinueWith(OnComplete);
+ }
}
}
diff --git a/osu.Game/Database/LegacySkinExporter.cs b/osu.Game/Database/LegacySkinExporter.cs
index a35636c248..4168763324 100644
--- a/osu.Game/Database/LegacySkinExporter.cs
+++ b/osu.Game/Database/LegacySkinExporter.cs
@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System.IO;
using osu.Framework.Platform;
using osu.Game.Overlays.Notifications;
using osu.Game.Skinning;
@@ -11,8 +12,8 @@ namespace osu.Game.Database
{
protected override string FileExtension => ".osk";
- public LegacySkinExporter(Storage storage, RealmAccess realm, ProgressNotification notification)
- : base(storage, realm, notification)
+ public LegacySkinExporter(Storage storage, RealmAccess realm, ProgressNotification notification, Stream? stream = null)
+ : base(storage, realm, notification, stream)
{
}
}
From 4e457871f3a518b05d6d95e7637c74b7ddc978fb Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Sat, 19 Nov 2022 01:03:09 +0900
Subject: [PATCH 0016/1400] impossible null and remove storage
---
osu.Game/Online/Leaderboards/LeaderboardScore.cs | 12 ++++--------
osu.Game/Overlays/Settings/Sections/SkinSection.cs | 8 ++------
osu.Game/Screens/Edit/Editor.cs | 8 ++------
3 files changed, 8 insertions(+), 20 deletions(-)
diff --git a/osu.Game/Online/Leaderboards/LeaderboardScore.cs b/osu.Game/Online/Leaderboards/LeaderboardScore.cs
index e2f640a44c..b374736648 100644
--- a/osu.Game/Online/Leaderboards/LeaderboardScore.cs
+++ b/osu.Game/Online/Leaderboards/LeaderboardScore.cs
@@ -18,7 +18,6 @@ using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input.Events;
using osu.Framework.Localisation;
-using osu.Framework.Platform;
using osu.Game.Database;
using osu.Game.Extensions;
using osu.Game.Graphics;
@@ -67,16 +66,13 @@ namespace osu.Game.Online.Leaderboards
private List statisticsLabels;
- [Resolved(CanBeNull = true)]
+ [Resolved(canBeNull: true)]
private IDialogOverlay dialogOverlay { get; set; }
- [Resolved(CanBeNull = true)]
+ [Resolved(canBeNull: true)]
private SongSelect songSelect { get; set; }
- [Resolved]
- private Storage storage { get; set; }
-
- [Resolved]
+ [Resolved(canBeNull: true)]
private LegacyExportManager exporter { get; set; }
public ITooltip GetCustomTooltip() => new LeaderboardScoreTooltip();
@@ -431,7 +427,7 @@ namespace osu.Game.Online.Leaderboards
if (Score.Files.Count > 0)
{
- items.Add(new OsuMenuItem("Export", MenuItemType.Standard, () => Task.Run(() => exporter.ExportAsync(Score))));
+ items.Add(new OsuMenuItem("Export", MenuItemType.Standard, () => Task.Run(() => exporter?.ExportAsync(Score))));
items.Add(new OsuMenuItem(CommonStrings.ButtonsDelete, MenuItemType.Destructive, () => dialogOverlay?.Push(new LocalScoreDeleteDialog(Score))));
}
diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs
index 6cd9e591e1..e5a26c19fc 100644
--- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs
+++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs
@@ -13,7 +13,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Framework.Logging;
-using osu.Framework.Platform;
using osu.Game.Database;
using osu.Game.Graphics.UserInterface;
using osu.Game.Localisation;
@@ -138,10 +137,7 @@ namespace osu.Game.Overlays.Settings.Sections
[Resolved]
private SkinManager skins { get; set; }
- [Resolved]
- private Storage storage { get; set; }
-
- [Resolved]
+ [Resolved(canBeNull: true)]
private LegacyExportManager exporter { get; set; }
private Bindable currentSkin;
@@ -165,7 +161,7 @@ namespace osu.Game.Overlays.Settings.Sections
{
try
{
- currentSkin.Value.SkinInfo.PerformRead(s => exporter.ExportAsync(s));
+ currentSkin.Value.SkinInfo.PerformRead(s => exporter?.ExportAsync(s));
}
catch (Exception e)
{
diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs
index e266239f34..77f14f689a 100644
--- a/osu.Game/Screens/Edit/Editor.cs
+++ b/osu.Game/Screens/Edit/Editor.cs
@@ -21,7 +21,6 @@ using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
using osu.Framework.Localisation;
using osu.Framework.Logging;
-using osu.Framework.Platform;
using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Framework.Threading;
@@ -91,9 +90,6 @@ namespace osu.Game.Screens.Edit
[Resolved]
private RulesetStore rulesets { get; set; }
- [Resolved]
- private Storage storage { get; set; }
-
[Resolved(canBeNull: true)]
private IDialogOverlay dialogOverlay { get; set; }
@@ -183,7 +179,7 @@ namespace osu.Game.Screens.Edit
private Bindable editorBackgroundDim;
private Bindable editorHitMarkers;
- [Resolved]
+ [Resolved(canBeNull: true)]
private LegacyExportManager exporter { get; set; }
public Editor(EditorLoader loader = null)
@@ -942,7 +938,7 @@ namespace osu.Game.Screens.Edit
private void exportBeatmap()
{
Save();
- Task.Run(() => exporter.ExportAsync(Beatmap.Value.BeatmapSetInfo));
+ Task.Run(() => exporter?.ExportAsync(Beatmap.Value.BeatmapSetInfo));
}
///
From 28867fbbb1750640a30113d576500d0a82502db7 Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Sat, 19 Nov 2022 12:34:35 +0900
Subject: [PATCH 0017/1400] Add comment
---
osu.Game/Database/LegacyExportManager.cs | 18 ++++++++++++++----
osu.Game/Database/LegacyModelExporter.cs | 6 ++++++
2 files changed, 20 insertions(+), 4 deletions(-)
diff --git a/osu.Game/Database/LegacyExportManager.cs b/osu.Game/Database/LegacyExportManager.cs
index 08594ab020..19fca623c5 100644
--- a/osu.Game/Database/LegacyExportManager.cs
+++ b/osu.Game/Database/LegacyExportManager.cs
@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System.IO;
using System.Threading.Tasks;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
@@ -14,6 +15,9 @@ using osu.Game.Skinning;
namespace osu.Game.Database
{
+ ///
+ /// A class which centrally manage legacy file exports.
+ ///
[ExcludeFromDynamicCompile]
public class LegacyExportManager : Component
{
@@ -26,7 +30,13 @@ namespace osu.Game.Database
[Resolved]
private INotificationOverlay? notifications { get; set; }
- public async Task ExportAsync(IHasGuidPrimaryKey item)
+ ///
+ /// Identify the model type and and automatically assigned to the corresponding exporter.
+ ///
+ /// The model should export.
+ /// The stream if requires a specific output-stream
+ ///
+ public async Task ExportAsync(IHasGuidPrimaryKey item, Stream? stream = null)
{
var notification = new ProgressNotification
{
@@ -39,15 +49,15 @@ namespace osu.Game.Database
switch (item)
{
case SkinInfo:
- await new LegacySkinExporter(exportStorage, realmAccess, notification).ExportASync(item);
+ await new LegacySkinExporter(exportStorage, realmAccess, notification, stream).ExportASync(item);
break;
case ScoreInfo:
- await new LegacyScoreExporter(exportStorage, realmAccess, notification).ExportASync(item);
+ await new LegacyScoreExporter(exportStorage, realmAccess, notification, stream).ExportASync(item);
break;
case BeatmapSetInfo:
- await new LegacyBeatmapExporter(exportStorage, realmAccess, notification).ExportASync(item);
+ await new LegacyBeatmapExporter(exportStorage, realmAccess, notification, stream).ExportASync(item);
break;
}
}
diff --git a/osu.Game/Database/LegacyModelExporter.cs b/osu.Game/Database/LegacyModelExporter.cs
index a4b0f7ba9d..d734d3341c 100644
--- a/osu.Game/Database/LegacyModelExporter.cs
+++ b/osu.Game/Database/LegacyModelExporter.cs
@@ -48,6 +48,12 @@ namespace osu.Game.Database
ShouldDisposeStream = false;
}
+ ///
+ /// Export model to
+ /// if is null, model will export to default folder.
+ ///
+ /// The model which have Guid.
+ ///
public virtual async Task ExportASync(IHasGuidPrimaryKey uuid)
{
Guid id = uuid.ID;
From 2653bd2f997c305d1497d74da66e33be9630cc84 Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Sat, 19 Nov 2022 12:57:56 +0900
Subject: [PATCH 0018/1400] Make notification cannot cancel when Saving Zip
Archive
This operation cannot be stopped(if not dispose stream).
so make it cannot cancel
---
osu.Game/Database/LegacyModelExporter.cs | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/osu.Game/Database/LegacyModelExporter.cs b/osu.Game/Database/LegacyModelExporter.cs
index d734d3341c..9fa6f64ee4 100644
--- a/osu.Game/Database/LegacyModelExporter.cs
+++ b/osu.Game/Database/LegacyModelExporter.cs
@@ -56,6 +56,9 @@ namespace osu.Game.Database
///
public virtual async Task ExportASync(IHasGuidPrimaryKey uuid)
{
+ bool canCancel = true;
+ Notification.CancelRequested += () => canCancel;
+
Guid id = uuid.ID;
await Task.Run(() =>
{
@@ -91,6 +94,7 @@ namespace osu.Game.Database
}
Notification.Text = "Saving Zip Archive...";
+ canCancel = false;
archive.SaveTo(OutputStream);
}
});
From 60ef88844c31459dfa94a5ffdb1fdf41530f2c96 Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Mon, 21 Nov 2022 17:09:56 +0900
Subject: [PATCH 0019/1400] Recover accidentally deleted codes
---
osu.Game/Database/RealmAccess.cs | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs
index 5a7ead1c59..1a938c12e5 100644
--- a/osu.Game/Database/RealmAccess.cs
+++ b/osu.Game/Database/RealmAccess.cs
@@ -173,6 +173,11 @@ namespace osu.Game.Database
if (!Filename.EndsWith(realm_extension, StringComparison.Ordinal))
Filename += realm_extension;
+#if DEBUG
+ if (!DebugUtils.IsNUnitRunning)
+ applyFilenameSchemaSuffix(ref Filename);
+#endif
+
string newerVersionFilename = $"{Filename.Replace(realm_extension, string.Empty)}_newer_version{realm_extension}";
// Attempt to recover a newer database version if available.
From ed53168267485ba0ca2bdc97057fd43566770cd4 Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Mon, 21 Nov 2022 17:42:11 +0900
Subject: [PATCH 0020/1400] typo fix
---
osu.Game.Tests/Skins/IO/ImportSkinTest.cs | 6 +++---
osu.Game/Database/LegacyExportManager.cs | 4 ++--
osu.Game/Database/LegacyModelExporter.cs | 2 +-
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs
index 0c3c459e87..c4dde59e3f 100644
--- a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs
+++ b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs
@@ -122,7 +122,7 @@ namespace osu.Game.Tests.Skins.IO
await import1.PerformRead(async s =>
{
- await new LegacySkinExporter(osu.Dependencies.Get(), osu.Dependencies.Get(), new ProgressNotification(), exportStream).ExportASync(s);
+ await new LegacySkinExporter(osu.Dependencies.Get(), osu.Dependencies.Get(), new ProgressNotification(), exportStream).ExportAsync(s);
});
string exportFilename = import1.GetDisplayString();
@@ -204,7 +204,7 @@ namespace osu.Game.Tests.Skins.IO
Assert.IsFalse(s.Protected);
Assert.AreEqual(typeof(ArgonSkin), s.CreateInstance(skinManager).GetType());
- await new LegacySkinExporter(osu.Dependencies.Get(), osu.Dependencies.Get(), new ProgressNotification(), exportStream).ExportASync(s);
+ await new LegacySkinExporter(osu.Dependencies.Get(), osu.Dependencies.Get(), new ProgressNotification(), exportStream).ExportAsync(s);
Assert.Greater(exportStream.Length, 0);
});
@@ -237,7 +237,7 @@ namespace osu.Game.Tests.Skins.IO
Assert.IsFalse(s.Protected);
Assert.AreEqual(typeof(DefaultLegacySkin), s.CreateInstance(skinManager).GetType());
- await new LegacySkinExporter(osu.Dependencies.Get(), osu.Dependencies.Get(), new ProgressNotification(), exportStream).ExportASync(s);
+ await new LegacySkinExporter(osu.Dependencies.Get(), osu.Dependencies.Get(), new ProgressNotification(), exportStream).ExportAsync(s);
Assert.Greater(exportStream.Length, 0);
});
diff --git a/osu.Game/Database/LegacyExportManager.cs b/osu.Game/Database/LegacyExportManager.cs
index 19fca623c5..a694a0705e 100644
--- a/osu.Game/Database/LegacyExportManager.cs
+++ b/osu.Game/Database/LegacyExportManager.cs
@@ -49,7 +49,7 @@ namespace osu.Game.Database
switch (item)
{
case SkinInfo:
- await new LegacySkinExporter(exportStorage, realmAccess, notification, stream).ExportASync(item);
+ await new LegacySkinExporter(exportStorage, realmAccess, notification, stream).ExportAsync(item);
break;
case ScoreInfo:
@@ -57,7 +57,7 @@ namespace osu.Game.Database
break;
case BeatmapSetInfo:
- await new LegacyBeatmapExporter(exportStorage, realmAccess, notification, stream).ExportASync(item);
+ await new LegacyBeatmapExporter(exportStorage, realmAccess, notification, stream).ExportAsync(item);
break;
}
}
diff --git a/osu.Game/Database/LegacyModelExporter.cs b/osu.Game/Database/LegacyModelExporter.cs
index 9fa6f64ee4..01ebbdcaff 100644
--- a/osu.Game/Database/LegacyModelExporter.cs
+++ b/osu.Game/Database/LegacyModelExporter.cs
@@ -54,11 +54,11 @@ namespace osu.Game.Database
///
/// The model which have Guid.
///
- public virtual async Task ExportASync(IHasGuidPrimaryKey uuid)
{
bool canCancel = true;
Notification.CancelRequested += () => canCancel;
+ public virtual async Task ExportAsync(IHasGuidPrimaryKey uuid)
Guid id = uuid.ID;
await Task.Run(() =>
{
From e37d30a3733871eb39622d6f5ea95d6cfe22a5a6 Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Mon, 21 Nov 2022 18:58:01 +0900
Subject: [PATCH 0021/1400] refactor based on reviews
removed LegacyExportManager
Separated the method of CreateZip method and the default export method
---
osu.Game.Tests/Skins/IO/ImportSkinTest.cs | 7 +-
osu.Game/Database/LegacyBeatmapExporter.cs | 11 +-
osu.Game/Database/LegacyExportManager.cs | 65 ---------
osu.Game/Database/LegacyModelExporter.cs | 128 +++++++++---------
osu.Game/Database/LegacyScoreExporter.cs | 33 ++---
osu.Game/Database/LegacySkinExporter.cs | 11 +-
.../Online/Leaderboards/LeaderboardScore.cs | 13 +-
osu.Game/OsuGame.cs | 4 -
.../Overlays/Settings/Sections/SkinSection.cs | 13 +-
osu.Game/Screens/Edit/Editor.cs | 12 +-
10 files changed, 113 insertions(+), 184 deletions(-)
delete mode 100644 osu.Game/Database/LegacyExportManager.cs
diff --git a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs
index c4dde59e3f..703c63b91a 100644
--- a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs
+++ b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs
@@ -14,7 +14,6 @@ using osu.Framework.Platform;
using osu.Game.Database;
using osu.Game.Extensions;
using osu.Game.IO;
-using osu.Game.Overlays.Notifications;
using osu.Game.Skinning;
using SharpCompress.Archives.Zip;
@@ -122,7 +121,7 @@ namespace osu.Game.Tests.Skins.IO
await import1.PerformRead(async s =>
{
- await new LegacySkinExporter(osu.Dependencies.Get(), osu.Dependencies.Get(), new ProgressNotification(), exportStream).ExportAsync(s);
+ await new LegacySkinExporter(osu.Dependencies.Get(), osu.Dependencies.Get()).ExportToStreamAsync(s, exportStream);
});
string exportFilename = import1.GetDisplayString();
@@ -204,7 +203,7 @@ namespace osu.Game.Tests.Skins.IO
Assert.IsFalse(s.Protected);
Assert.AreEqual(typeof(ArgonSkin), s.CreateInstance(skinManager).GetType());
- await new LegacySkinExporter(osu.Dependencies.Get(), osu.Dependencies.Get(), new ProgressNotification(), exportStream).ExportAsync(s);
+ await new LegacySkinExporter(osu.Dependencies.Get(), osu.Dependencies.Get()).ExportToStreamAsync(s, exportStream);
Assert.Greater(exportStream.Length, 0);
});
@@ -237,7 +236,7 @@ namespace osu.Game.Tests.Skins.IO
Assert.IsFalse(s.Protected);
Assert.AreEqual(typeof(DefaultLegacySkin), s.CreateInstance(skinManager).GetType());
- await new LegacySkinExporter(osu.Dependencies.Get(), osu.Dependencies.Get(), new ProgressNotification(), exportStream).ExportAsync(s);
+ await new LegacySkinExporter(osu.Dependencies.Get(), osu.Dependencies.Get()).ExportToStreamAsync(s, exportStream);
Assert.Greater(exportStream.Length, 0);
});
diff --git a/osu.Game/Database/LegacyBeatmapExporter.cs b/osu.Game/Database/LegacyBeatmapExporter.cs
index 5505d141ee..22bccbcda6 100644
--- a/osu.Game/Database/LegacyBeatmapExporter.cs
+++ b/osu.Game/Database/LegacyBeatmapExporter.cs
@@ -1,20 +1,19 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using System.IO;
using osu.Framework.Platform;
using osu.Game.Beatmaps;
-using osu.Game.Overlays.Notifications;
+using osu.Game.Overlays;
namespace osu.Game.Database
{
public class LegacyBeatmapExporter : LegacyModelExporter
{
- protected override string FileExtension => ".osz";
-
- public LegacyBeatmapExporter(Storage storage, RealmAccess realm, ProgressNotification notification, Stream? stream = null)
- : base(storage, realm, notification, stream)
+ public LegacyBeatmapExporter(Storage storage, RealmAccess realm, INotificationOverlay? notifications = null)
+ : base(storage, realm, notifications)
{
}
+
+ protected override string FileExtension => ".osz";
}
}
diff --git a/osu.Game/Database/LegacyExportManager.cs b/osu.Game/Database/LegacyExportManager.cs
deleted file mode 100644
index a694a0705e..0000000000
--- a/osu.Game/Database/LegacyExportManager.cs
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-using System.IO;
-using System.Threading.Tasks;
-using osu.Framework.Allocation;
-using osu.Framework.Graphics;
-using osu.Framework.Platform;
-using osu.Framework.Testing;
-using osu.Game.Beatmaps;
-using osu.Game.Overlays;
-using osu.Game.Overlays.Notifications;
-using osu.Game.Scoring;
-using osu.Game.Skinning;
-
-namespace osu.Game.Database
-{
- ///
- /// A class which centrally manage legacy file exports.
- ///
- [ExcludeFromDynamicCompile]
- public class LegacyExportManager : Component
- {
- [Resolved]
- private RealmAccess realmAccess { get; set; } = null!;
-
- [Resolved]
- private Storage exportStorage { get; set; } = null!;
-
- [Resolved]
- private INotificationOverlay? notifications { get; set; }
-
- ///
- /// Identify the model type and and automatically assigned to the corresponding exporter.
- ///
- /// The model should export.
- /// The stream if requires a specific output-stream
- ///
- public async Task ExportAsync(IHasGuidPrimaryKey item, Stream? stream = null)
- {
- var notification = new ProgressNotification
- {
- State = ProgressNotificationState.Active,
- Text = "Exporting...",
- CompletionText = "Export completed"
- };
- notifications?.Post(notification);
-
- switch (item)
- {
- case SkinInfo:
- await new LegacySkinExporter(exportStorage, realmAccess, notification, stream).ExportAsync(item);
- break;
-
- case ScoreInfo:
- await new LegacyScoreExporter(exportStorage, realmAccess, notification, stream).ExportASync(item);
- break;
-
- case BeatmapSetInfo:
- await new LegacyBeatmapExporter(exportStorage, realmAccess, notification, stream).ExportAsync(item);
- break;
- }
- }
- }
-}
diff --git a/osu.Game/Database/LegacyModelExporter.cs b/osu.Game/Database/LegacyModelExporter.cs
index 01ebbdcaff..83167e7319 100644
--- a/osu.Game/Database/LegacyModelExporter.cs
+++ b/osu.Game/Database/LegacyModelExporter.cs
@@ -5,8 +5,10 @@ using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
+using osu.Framework.Graphics;
using osu.Framework.Platform;
using osu.Game.Extensions;
+using osu.Game.Overlays;
using osu.Game.Overlays.Notifications;
using Realms;
using SharpCompress.Archives.Zip;
@@ -16,112 +18,106 @@ namespace osu.Game.Database
///
/// A class which handles exporting legacy user data of a single type from osu-stable.
///
- public abstract class LegacyModelExporter
- where TModel : RealmObject
+ public abstract class LegacyModelExporter : Component
+ where TModel : RealmObject, IHasNamedFiles, IHasGuidPrimaryKey
{
///
/// The file extension for exports (including the leading '.').
///
protected abstract string FileExtension { get; }
- protected readonly Storage UserFileStorage;
+ protected Storage UserFileStorage;
+ protected Storage ExportStorage;
- protected readonly Storage ExportStorage;
+ protected RealmAccess RealmAccess;
- protected readonly RealmAccess RealmAccess;
-
- protected readonly ProgressNotification Notification;
+ private readonly ProgressNotification notification;
protected string Filename = null!;
- protected Stream? OutputStream;
+ private bool canCancel = true;
- protected bool ShouldDisposeStream;
-
- protected LegacyModelExporter(Storage storage, RealmAccess realm, ProgressNotification notification, Stream? stream = null)
+ protected LegacyModelExporter(Storage storage, RealmAccess realm, INotificationOverlay? notifications = null)
{
ExportStorage = storage.GetStorageForDirectory(@"exports");
UserFileStorage = storage.GetStorageForDirectory(@"files");
- Notification = notification;
RealmAccess = realm;
- OutputStream = stream;
- ShouldDisposeStream = false;
+
+ notification = new ProgressNotification
+ {
+ State = ProgressNotificationState.Active,
+ Text = "Exporting...",
+ CompletionText = "Export completed"
+ };
+ notification.CancelRequested += () => canCancel;
+
+ notifications?.Post(notification);
}
- ///
- /// Export model to
- /// if is null, model will export to default folder.
- ///
- /// The model which have Guid.
- ///
+ public async Task ExportAsync(RealmObject item)
{
- bool canCancel = true;
- Notification.CancelRequested += () => canCancel;
+ if (item is TModel model)
+ {
+ Filename = $"{model.GetDisplayString().GetValidFilename()}{FileExtension}";
- public virtual async Task ExportAsync(IHasGuidPrimaryKey uuid)
+ using (var stream = ExportStorage.CreateFileSafely(Filename))
+ {
+ await ExportToStreamAsync(model, stream);
+ }
+ }
+ }
+
+ public virtual async Task ExportToStreamAsync(TModel uuid, Stream stream)
+ {
Guid id = uuid.ID;
await Task.Run(() =>
{
RealmAccess.Run(r =>
{
- if (r.Find(id) is IHasNamedFiles model)
- {
- Filename = $"{model.GetDisplayString().GetValidFilename()}{FileExtension}";
- }
- else
- {
- return;
- }
-
- if (OutputStream == null)
- {
- OutputStream = ExportStorage.CreateFileSafely(Filename);
- ShouldDisposeStream = true;
- }
-
- using (var archive = ZipArchive.Create())
- {
- float i = 0;
-
- foreach (var file in model.Files)
- {
- if (Notification.CancellationToken.IsCancellationRequested) return;
-
- archive.AddEntry(file.Filename, UserFileStorage.GetStream(file.File.GetStoragePath()));
- i++;
- Notification.Progress = i / model.Files.Count();
- Notification.Text = $"Exporting... ({i}/{model.Files.Count()})";
- }
-
- Notification.Text = "Saving Zip Archive...";
- canCancel = false;
- archive.SaveTo(OutputStream);
- }
+ TModel model = r.Find(id);
+ createZipArchive(model, stream);
});
}).ContinueWith(OnComplete);
}
+ private void createZipArchive(TModel model, Stream outputStream)
+ {
+ using (var archive = ZipArchive.Create())
+ {
+ float i = 0;
+
+ foreach (var file in model.Files)
+ {
+ if (notification.CancellationToken.IsCancellationRequested) return;
+
+ archive.AddEntry(file.Filename, UserFileStorage.GetStream(file.File.GetStoragePath()));
+ i++;
+ notification.Progress = i / model.Files.Count();
+ notification.Text = $"Exporting... ({i}/{model.Files.Count()})";
+ }
+
+ notification.Text = "Saving Zip Archive...";
+ canCancel = false;
+ archive.SaveTo(outputStream);
+ }
+ }
+
protected void OnComplete(Task t)
{
- if (ShouldDisposeStream)
- {
- OutputStream?.Dispose();
- }
-
if (t.IsFaulted)
{
- Notification.State = ProgressNotificationState.Cancelled;
+ notification.State = ProgressNotificationState.Cancelled;
return;
}
- if (Notification.CancellationToken.IsCancellationRequested)
+ if (notification.CancellationToken.IsCancellationRequested)
{
return;
}
- Notification.CompletionText = "Export Complete, Click to open the folder";
- Notification.CompletionClickAction += () => ExportStorage.PresentFileExternally(Filename);
- Notification.State = ProgressNotificationState.Completed;
+ notification.CompletionText = "Export Complete, Click to open the folder";
+ notification.CompletionClickAction += () => ExportStorage.PresentFileExternally(Filename);
+ notification.State = ProgressNotificationState.Completed;
}
}
}
diff --git a/osu.Game/Database/LegacyScoreExporter.cs b/osu.Game/Database/LegacyScoreExporter.cs
index 3004c02978..e00bc2a0ca 100644
--- a/osu.Game/Database/LegacyScoreExporter.cs
+++ b/osu.Game/Database/LegacyScoreExporter.cs
@@ -6,49 +6,36 @@ using System.Linq;
using System.Threading.Tasks;
using osu.Framework.Platform;
using osu.Game.Extensions;
-using osu.Game.Overlays.Notifications;
+using osu.Game.Overlays;
using osu.Game.Scoring;
namespace osu.Game.Database
{
public class LegacyScoreExporter : LegacyModelExporter
{
- protected override string FileExtension => ".osr";
-
- public LegacyScoreExporter(Storage storage, RealmAccess realm, ProgressNotification notification, Stream? stream = null)
- : base(storage, realm, notification, stream)
+ public LegacyScoreExporter(Storage storage, RealmAccess realm, INotificationOverlay? notifications = null)
+ : base(storage, realm, notifications)
{
}
- public override async Task ExportASync(IHasGuidPrimaryKey uuid)
+ protected override string FileExtension => ".osr";
+
+ public override async Task ExportToStreamAsync(ScoreInfo uuid, Stream stream)
{
await Task.Run(() =>
{
RealmAccess.Run(r =>
{
- if (r.Find(uuid.ID) is IHasNamedFiles model)
- {
- Filename = $"{model.GetDisplayString().GetValidFilename()}{FileExtension}";
- }
- else
- {
- return;
- }
+ ScoreInfo model = r.Find(uuid.ID);
+
+ Filename = $"{model.GetDisplayString().GetValidFilename()}{FileExtension}";
var file = model.Files.SingleOrDefault();
if (file == null)
return;
- if (Notification.CancellationToken.IsCancellationRequested) return;
-
- if (OutputStream == null)
- {
- OutputStream = ExportStorage.CreateFileSafely(Filename);
- ShouldDisposeStream = true;
- }
-
using (var inputStream = UserFileStorage.GetStream(file.File.GetStoragePath()))
- inputStream.CopyTo(OutputStream);
+ inputStream.CopyTo(stream);
});
}).ContinueWith(OnComplete);
}
diff --git a/osu.Game/Database/LegacySkinExporter.cs b/osu.Game/Database/LegacySkinExporter.cs
index 4168763324..6e65963f29 100644
--- a/osu.Game/Database/LegacySkinExporter.cs
+++ b/osu.Game/Database/LegacySkinExporter.cs
@@ -1,20 +1,19 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using System.IO;
using osu.Framework.Platform;
-using osu.Game.Overlays.Notifications;
+using osu.Game.Overlays;
using osu.Game.Skinning;
namespace osu.Game.Database
{
public class LegacySkinExporter : LegacyModelExporter
{
- protected override string FileExtension => ".osk";
-
- public LegacySkinExporter(Storage storage, RealmAccess realm, ProgressNotification notification, Stream? stream = null)
- : base(storage, realm, notification, stream)
+ public LegacySkinExporter(Storage storage, RealmAccess realm, INotificationOverlay? notifications = null)
+ : base(storage, realm, notifications)
{
}
+
+ protected override string FileExtension => ".osk";
}
}
diff --git a/osu.Game/Online/Leaderboards/LeaderboardScore.cs b/osu.Game/Online/Leaderboards/LeaderboardScore.cs
index b374736648..0a9f2a81bd 100644
--- a/osu.Game/Online/Leaderboards/LeaderboardScore.cs
+++ b/osu.Game/Online/Leaderboards/LeaderboardScore.cs
@@ -34,6 +34,7 @@ using osuTK.Graphics;
using osu.Game.Online.API;
using osu.Game.Resources.Localisation.Web;
using osu.Game.Utils;
+using osu.Framework.Platform;
namespace osu.Game.Online.Leaderboards
{
@@ -72,8 +73,14 @@ namespace osu.Game.Online.Leaderboards
[Resolved(canBeNull: true)]
private SongSelect songSelect { get; set; }
- [Resolved(canBeNull: true)]
- private LegacyExportManager exporter { get; set; }
+ [Resolved]
+ private Storage storage { get; set; }
+
+ [Resolved]
+ private RealmAccess realm { get; set; }
+
+ [Resolved]
+ private INotificationOverlay notifications { get; set; }
public ITooltip GetCustomTooltip() => new LeaderboardScoreTooltip();
public virtual ScoreInfo TooltipContent => Score;
@@ -427,7 +434,7 @@ namespace osu.Game.Online.Leaderboards
if (Score.Files.Count > 0)
{
- items.Add(new OsuMenuItem("Export", MenuItemType.Standard, () => Task.Run(() => exporter?.ExportAsync(Score))));
+ items.Add(new OsuMenuItem("Export", MenuItemType.Standard, () => Task.Run(() => new LegacyScoreExporter(storage, realm, notifications).ExportAsync(Score))));
items.Add(new OsuMenuItem(CommonStrings.ButtonsDelete, MenuItemType.Destructive, () => dialogOverlay?.Push(new LocalScoreDeleteDialog(Score))));
}
diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs
index 09647f9d1e..a93c187e53 100644
--- a/osu.Game/OsuGame.cs
+++ b/osu.Game/OsuGame.cs
@@ -126,9 +126,6 @@ namespace osu.Game
[Cached]
private readonly LegacyImportManager legacyImportManager = new LegacyImportManager();
- [Cached]
- private readonly LegacyExportManager legacyExportManager = new LegacyExportManager();
-
[Cached]
private readonly ScreenshotManager screenshotManager = new ScreenshotManager();
@@ -871,7 +868,6 @@ namespace osu.Game
}), rightFloatingOverlayContent.Add, true);
loadComponentSingleFile(legacyImportManager, Add);
- loadComponentSingleFile(legacyExportManager, Add);
loadComponentSingleFile(screenshotManager, Add);
diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs
index e5a26c19fc..46e760283d 100644
--- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs
+++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs
@@ -13,6 +13,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Framework.Logging;
+using osu.Framework.Platform;
using osu.Game.Database;
using osu.Game.Graphics.UserInterface;
using osu.Game.Localisation;
@@ -137,8 +138,14 @@ namespace osu.Game.Overlays.Settings.Sections
[Resolved]
private SkinManager skins { get; set; }
- [Resolved(canBeNull: true)]
- private LegacyExportManager exporter { get; set; }
+ [Resolved]
+ private Storage storage { get; set; }
+
+ [Resolved]
+ private RealmAccess realm { get; set; }
+
+ [Resolved]
+ private INotificationOverlay notifications { get; set; }
private Bindable currentSkin;
@@ -161,7 +168,7 @@ namespace osu.Game.Overlays.Settings.Sections
{
try
{
- currentSkin.Value.SkinInfo.PerformRead(s => exporter?.ExportAsync(s));
+ currentSkin.Value.SkinInfo.PerformRead(s => new LegacySkinExporter(storage, realm, notifications).ExportAsync(s));
}
catch (Exception e)
{
diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs
index 77f14f689a..e53c550a1a 100644
--- a/osu.Game/Screens/Edit/Editor.cs
+++ b/osu.Game/Screens/Edit/Editor.cs
@@ -21,6 +21,7 @@ using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
using osu.Framework.Localisation;
using osu.Framework.Logging;
+using osu.Framework.Platform;
using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Framework.Threading;
@@ -90,6 +91,12 @@ namespace osu.Game.Screens.Edit
[Resolved]
private RulesetStore rulesets { get; set; }
+ [Resolved]
+ private Storage storage { get; set; }
+
+ [Resolved]
+ private RealmAccess realm { get; set; }
+
[Resolved(canBeNull: true)]
private IDialogOverlay dialogOverlay { get; set; }
@@ -179,9 +186,6 @@ namespace osu.Game.Screens.Edit
private Bindable editorBackgroundDim;
private Bindable editorHitMarkers;
- [Resolved(canBeNull: true)]
- private LegacyExportManager exporter { get; set; }
-
public Editor(EditorLoader loader = null)
{
this.loader = loader;
@@ -938,7 +942,7 @@ namespace osu.Game.Screens.Edit
private void exportBeatmap()
{
Save();
- Task.Run(() => exporter?.ExportAsync(Beatmap.Value.BeatmapSetInfo));
+ Task.Run(() => new LegacyBeatmapExporter(storage, realm, notifications).ExportAsync(Beatmap.Value.BeatmapSetInfo));
}
///
From 9c6421a462d67e30d9bf9d4b2cdf9171765ae97e Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Mon, 21 Nov 2022 19:00:10 +0900
Subject: [PATCH 0022/1400] log the error
---
osu.Game/Database/LegacyModelExporter.cs | 3 +++
1 file changed, 3 insertions(+)
diff --git a/osu.Game/Database/LegacyModelExporter.cs b/osu.Game/Database/LegacyModelExporter.cs
index 83167e7319..9769a6d42a 100644
--- a/osu.Game/Database/LegacyModelExporter.cs
+++ b/osu.Game/Database/LegacyModelExporter.cs
@@ -6,6 +6,7 @@ using System.IO;
using System.Linq;
using System.Threading.Tasks;
using osu.Framework.Graphics;
+using osu.Framework.Logging;
using osu.Framework.Platform;
using osu.Game.Extensions;
using osu.Game.Overlays;
@@ -107,6 +108,8 @@ namespace osu.Game.Database
if (t.IsFaulted)
{
notification.State = ProgressNotificationState.Cancelled;
+ Logger.Error(t.Exception, "An error occurred while exporting");
+
return;
}
From 564f136945c0f3fef744014c5762f44145e325ae Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Mon, 21 Nov 2022 19:04:05 +0900
Subject: [PATCH 0023/1400] add xmldoc
---
osu.Game/Database/LegacyModelExporter.cs | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/osu.Game/Database/LegacyModelExporter.cs b/osu.Game/Database/LegacyModelExporter.cs
index 9769a6d42a..47068a8d2b 100644
--- a/osu.Game/Database/LegacyModelExporter.cs
+++ b/osu.Game/Database/LegacyModelExporter.cs
@@ -55,6 +55,11 @@ namespace osu.Game.Database
notifications?.Post(notification);
}
+ ///
+ /// Export the model to default folder.
+ ///
+ /// The model should export.
+ ///
public async Task ExportAsync(RealmObject item)
{
if (item is TModel model)
@@ -68,6 +73,12 @@ namespace osu.Game.Database
}
}
+ ///
+ /// Export te model corresponding to uuid to given stream.
+ ///
+ /// The medel which have .
+ /// The stream to export.
+ ///
public virtual async Task ExportToStreamAsync(TModel uuid, Stream stream)
{
Guid id = uuid.ID;
From 162f0bb95e1c525ce926935fafbcf98f3a76bdac Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Mon, 21 Nov 2022 19:05:26 +0900
Subject: [PATCH 0024/1400] filename can be private
---
osu.Game/Database/LegacyModelExporter.cs | 8 ++++----
osu.Game/Database/LegacyScoreExporter.cs | 2 --
2 files changed, 4 insertions(+), 6 deletions(-)
diff --git a/osu.Game/Database/LegacyModelExporter.cs b/osu.Game/Database/LegacyModelExporter.cs
index 47068a8d2b..3780f2b9cc 100644
--- a/osu.Game/Database/LegacyModelExporter.cs
+++ b/osu.Game/Database/LegacyModelExporter.cs
@@ -34,7 +34,7 @@ namespace osu.Game.Database
private readonly ProgressNotification notification;
- protected string Filename = null!;
+ private string filename = "";
private bool canCancel = true;
@@ -64,9 +64,9 @@ namespace osu.Game.Database
{
if (item is TModel model)
{
- Filename = $"{model.GetDisplayString().GetValidFilename()}{FileExtension}";
+ filename = $"{model.GetDisplayString().GetValidFilename()}{FileExtension}";
- using (var stream = ExportStorage.CreateFileSafely(Filename))
+ using (var stream = ExportStorage.CreateFileSafely(filename))
{
await ExportToStreamAsync(model, stream);
}
@@ -130,7 +130,7 @@ namespace osu.Game.Database
}
notification.CompletionText = "Export Complete, Click to open the folder";
- notification.CompletionClickAction += () => ExportStorage.PresentFileExternally(Filename);
+ notification.CompletionClickAction += () => ExportStorage.PresentFileExternally(filename);
notification.State = ProgressNotificationState.Completed;
}
}
diff --git a/osu.Game/Database/LegacyScoreExporter.cs b/osu.Game/Database/LegacyScoreExporter.cs
index e00bc2a0ca..ae0fbf8d19 100644
--- a/osu.Game/Database/LegacyScoreExporter.cs
+++ b/osu.Game/Database/LegacyScoreExporter.cs
@@ -28,8 +28,6 @@ namespace osu.Game.Database
{
ScoreInfo model = r.Find(uuid.ID);
- Filename = $"{model.GetDisplayString().GetValidFilename()}{FileExtension}";
-
var file = model.Files.SingleOrDefault();
if (file == null)
return;
From c509c5be40a449b872053e129358dd747b7e72f1 Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Mon, 21 Nov 2022 19:45:30 +0900
Subject: [PATCH 0025/1400] impossible null
---
osu.Game/Online/Leaderboards/LeaderboardScore.cs | 2 +-
osu.Game/Overlays/Settings/Sections/SkinSection.cs | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/osu.Game/Online/Leaderboards/LeaderboardScore.cs b/osu.Game/Online/Leaderboards/LeaderboardScore.cs
index 0a9f2a81bd..27c3e0ce47 100644
--- a/osu.Game/Online/Leaderboards/LeaderboardScore.cs
+++ b/osu.Game/Online/Leaderboards/LeaderboardScore.cs
@@ -79,7 +79,7 @@ namespace osu.Game.Online.Leaderboards
[Resolved]
private RealmAccess realm { get; set; }
- [Resolved]
+ [Resolved(canBeNull: true)]
private INotificationOverlay notifications { get; set; }
public ITooltip GetCustomTooltip() => new LeaderboardScoreTooltip();
diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs
index 46e760283d..eb51c18e31 100644
--- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs
+++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs
@@ -144,7 +144,7 @@ namespace osu.Game.Overlays.Settings.Sections
[Resolved]
private RealmAccess realm { get; set; }
- [Resolved]
+ [Resolved(canBeNull: true)]
private INotificationOverlay notifications { get; set; }
private Bindable currentSkin;
From 6adac853e85f7ebf81f61fa90a3d3afc8f556d0a Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Sun, 27 Nov 2022 09:58:54 +0900
Subject: [PATCH 0026/1400] Spite sync method `ExportToStream`
`uuid` to `model`
---
osu.Game/Database/LegacyModelExporter.cs | 14 ++++++++------
osu.Game/Database/LegacyScoreExporter.cs | 21 ++++++---------------
2 files changed, 14 insertions(+), 21 deletions(-)
diff --git a/osu.Game/Database/LegacyModelExporter.cs b/osu.Game/Database/LegacyModelExporter.cs
index 3780f2b9cc..3523d18f29 100644
--- a/osu.Game/Database/LegacyModelExporter.cs
+++ b/osu.Game/Database/LegacyModelExporter.cs
@@ -74,24 +74,26 @@ namespace osu.Game.Database
}
///
- /// Export te model corresponding to uuid to given stream.
+ /// Export te model corresponding to model to given stream.
///
- /// The medel which have .
+ /// The medel which have .
/// The stream to export.
///
- public virtual async Task ExportToStreamAsync(TModel uuid, Stream stream)
+ public async Task ExportToStreamAsync(TModel model, Stream stream)
{
- Guid id = uuid.ID;
+ Guid id = model.ID;
await Task.Run(() =>
{
RealmAccess.Run(r =>
{
- TModel model = r.Find(id);
- createZipArchive(model, stream);
+ TModel refetchModel = r.Find(id);
+ ExportToStream(refetchModel, stream);
});
}).ContinueWith(OnComplete);
}
+ protected virtual void ExportToStream(TModel model, Stream outputStream) => createZipArchive(model, outputStream);
+
private void createZipArchive(TModel model, Stream outputStream)
{
using (var archive = ZipArchive.Create())
diff --git a/osu.Game/Database/LegacyScoreExporter.cs b/osu.Game/Database/LegacyScoreExporter.cs
index ae0fbf8d19..eb46bc6db2 100644
--- a/osu.Game/Database/LegacyScoreExporter.cs
+++ b/osu.Game/Database/LegacyScoreExporter.cs
@@ -3,7 +3,6 @@
using System.IO;
using System.Linq;
-using System.Threading.Tasks;
using osu.Framework.Platform;
using osu.Game.Extensions;
using osu.Game.Overlays;
@@ -20,22 +19,14 @@ namespace osu.Game.Database
protected override string FileExtension => ".osr";
- public override async Task ExportToStreamAsync(ScoreInfo uuid, Stream stream)
+ protected override void ExportToStream(ScoreInfo model, Stream stream)
{
- await Task.Run(() =>
- {
- RealmAccess.Run(r =>
- {
- ScoreInfo model = r.Find(uuid.ID);
+ var file = model.Files.SingleOrDefault();
+ if (file == null)
+ return;
- var file = model.Files.SingleOrDefault();
- if (file == null)
- return;
-
- using (var inputStream = UserFileStorage.GetStream(file.File.GetStoragePath()))
- inputStream.CopyTo(stream);
- });
- }).ContinueWith(OnComplete);
+ using (var inputStream = UserFileStorage.GetStream(file.File.GetStoragePath()))
+ inputStream.CopyTo(stream);
}
}
}
From 19afce67767b95e67aaf06ea1df8c5b291797ddd Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Fri, 9 Dec 2022 23:41:07 +0900
Subject: [PATCH 0027/1400] Fix overwriting existing files
https://github.com/ppy/osu/pull/21468
---
osu.Game/Database/LegacyModelExporter.cs | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/osu.Game/Database/LegacyModelExporter.cs b/osu.Game/Database/LegacyModelExporter.cs
index 3523d18f29..5c4b7a4578 100644
--- a/osu.Game/Database/LegacyModelExporter.cs
+++ b/osu.Game/Database/LegacyModelExporter.cs
@@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System;
+using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
@@ -11,6 +12,7 @@ using osu.Framework.Platform;
using osu.Game.Extensions;
using osu.Game.Overlays;
using osu.Game.Overlays.Notifications;
+using osu.Game.Utils;
using Realms;
using SharpCompress.Archives.Zip;
@@ -64,7 +66,11 @@ namespace osu.Game.Database
{
if (item is TModel model)
{
- filename = $"{model.GetDisplayString().GetValidFilename()}{FileExtension}";
+ string itemFilename = item.GetDisplayString().GetValidFilename();
+
+ IEnumerable existingExports = ExportStorage.GetFiles("", $"{itemFilename}*{FileExtension}");
+
+ string filename = NamingUtils.GetNextBestFilename(existingExports, $"{itemFilename}{FileExtension}");
using (var stream = ExportStorage.CreateFileSafely(filename))
{
From 405985ec5b09769ca5d9031eadc2c8ad801b399d Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Fri, 9 Dec 2022 23:57:03 +0900
Subject: [PATCH 0028/1400] remove Component
exportStorage to private
notification should post when export instead of class being constructed
---
osu.Game/Database/LegacyModelExporter.cs | 25 ++++++++++++------------
1 file changed, 12 insertions(+), 13 deletions(-)
diff --git a/osu.Game/Database/LegacyModelExporter.cs b/osu.Game/Database/LegacyModelExporter.cs
index 5c4b7a4578..ae092d15e8 100644
--- a/osu.Game/Database/LegacyModelExporter.cs
+++ b/osu.Game/Database/LegacyModelExporter.cs
@@ -6,7 +6,6 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
-using osu.Framework.Graphics;
using osu.Framework.Logging;
using osu.Framework.Platform;
using osu.Game.Extensions;
@@ -21,7 +20,7 @@ namespace osu.Game.Database
///
/// A class which handles exporting legacy user data of a single type from osu-stable.
///
- public abstract class LegacyModelExporter : Component
+ public abstract class LegacyModelExporter
where TModel : RealmObject, IHasNamedFiles, IHasGuidPrimaryKey
{
///
@@ -30,22 +29,23 @@ namespace osu.Game.Database
protected abstract string FileExtension { get; }
protected Storage UserFileStorage;
- protected Storage ExportStorage;
+ private readonly Storage exportStorage;
protected RealmAccess RealmAccess;
private readonly ProgressNotification notification;
- private string filename = "";
-
private bool canCancel = true;
+ private readonly INotificationOverlay? notifications;
+
protected LegacyModelExporter(Storage storage, RealmAccess realm, INotificationOverlay? notifications = null)
{
- ExportStorage = storage.GetStorageForDirectory(@"exports");
+ exportStorage = storage.GetStorageForDirectory(@"exports");
UserFileStorage = storage.GetStorageForDirectory(@"files");
RealmAccess = realm;
+ this.notifications = notifications;
notification = new ProgressNotification
{
State = ProgressNotificationState.Active,
@@ -53,8 +53,6 @@ namespace osu.Game.Database
CompletionText = "Export completed"
};
notification.CancelRequested += () => canCancel;
-
- notifications?.Post(notification);
}
///
@@ -66,13 +64,15 @@ namespace osu.Game.Database
{
if (item is TModel model)
{
+ notifications?.Post(notification);
+
string itemFilename = item.GetDisplayString().GetValidFilename();
-
- IEnumerable existingExports = ExportStorage.GetFiles("", $"{itemFilename}*{FileExtension}");
-
+ IEnumerable existingExports = exportStorage.GetFiles("", $"{itemFilename}*{FileExtension}");
string filename = NamingUtils.GetNextBestFilename(existingExports, $"{itemFilename}{FileExtension}");
- using (var stream = ExportStorage.CreateFileSafely(filename))
+ notification.CompletionClickAction += () => exportStorage.PresentFileExternally(filename);
+
+ using (var stream = exportStorage.CreateFileSafely(filename))
{
await ExportToStreamAsync(model, stream);
}
@@ -138,7 +138,6 @@ namespace osu.Game.Database
}
notification.CompletionText = "Export Complete, Click to open the folder";
- notification.CompletionClickAction += () => ExportStorage.PresentFileExternally(filename);
notification.State = ProgressNotificationState.Completed;
}
}
From 951302fe61374cb8b4cc1dedf830c6d8fe748ae6 Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Sat, 10 Dec 2022 00:43:03 +0900
Subject: [PATCH 0029/1400] ExportAsync use TModel
---
osu.Game/Database/LegacyModelExporter.cs | 27 +++++++++++-------------
1 file changed, 12 insertions(+), 15 deletions(-)
diff --git a/osu.Game/Database/LegacyModelExporter.cs b/osu.Game/Database/LegacyModelExporter.cs
index ae092d15e8..ad61338c8b 100644
--- a/osu.Game/Database/LegacyModelExporter.cs
+++ b/osu.Game/Database/LegacyModelExporter.cs
@@ -58,24 +58,21 @@ namespace osu.Game.Database
///
/// Export the model to default folder.
///
- /// The model should export.
+ /// The model should export.
///
- public async Task ExportAsync(RealmObject item)
+ public async Task ExportAsync(TModel model)
{
- if (item is TModel model)
+ notifications?.Post(notification);
+
+ string itemFilename = model.GetDisplayString().GetValidFilename();
+ IEnumerable existingExports = exportStorage.GetFiles("", $"{itemFilename}*{FileExtension}");
+ string filename = NamingUtils.GetNextBestFilename(existingExports, $"{itemFilename}{FileExtension}");
+
+ notification.CompletionClickAction += () => exportStorage.PresentFileExternally(filename);
+
+ using (var stream = exportStorage.CreateFileSafely(filename))
{
- notifications?.Post(notification);
-
- string itemFilename = item.GetDisplayString().GetValidFilename();
- IEnumerable existingExports = exportStorage.GetFiles("", $"{itemFilename}*{FileExtension}");
- string filename = NamingUtils.GetNextBestFilename(existingExports, $"{itemFilename}{FileExtension}");
-
- notification.CompletionClickAction += () => exportStorage.PresentFileExternally(filename);
-
- using (var stream = exportStorage.CreateFileSafely(filename))
- {
- await ExportToStreamAsync(model, stream);
- }
+ await ExportToStreamAsync(model, stream);
}
}
From fa30f3348ff11e68c42b9b63082b5409ee479746 Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Sun, 11 Dec 2022 16:53:11 +0900
Subject: [PATCH 0030/1400] `onComplete` should private
---
osu.Game/Database/LegacyModelExporter.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/osu.Game/Database/LegacyModelExporter.cs b/osu.Game/Database/LegacyModelExporter.cs
index ad61338c8b..4ea56c0056 100644
--- a/osu.Game/Database/LegacyModelExporter.cs
+++ b/osu.Game/Database/LegacyModelExporter.cs
@@ -92,7 +92,7 @@ namespace osu.Game.Database
TModel refetchModel = r.Find(id);
ExportToStream(refetchModel, stream);
});
- }).ContinueWith(OnComplete);
+ }).ContinueWith(onComplete);
}
protected virtual void ExportToStream(TModel model, Stream outputStream) => createZipArchive(model, outputStream);
@@ -119,7 +119,7 @@ namespace osu.Game.Database
}
}
- protected void OnComplete(Task t)
+ private void onComplete(Task t)
{
if (t.IsFaulted)
{
From 2d5763340944ab99fcffb81f3c2915a441befa6e Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Sun, 11 Dec 2022 16:54:20 +0900
Subject: [PATCH 0031/1400] rename method name and add xmldoc
---
osu.Game/Database/LegacyModelExporter.cs | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/osu.Game/Database/LegacyModelExporter.cs b/osu.Game/Database/LegacyModelExporter.cs
index 4ea56c0056..cf41ffc780 100644
--- a/osu.Game/Database/LegacyModelExporter.cs
+++ b/osu.Game/Database/LegacyModelExporter.cs
@@ -95,9 +95,14 @@ namespace osu.Game.Database
}).ContinueWith(onComplete);
}
- protected virtual void ExportToStream(TModel model, Stream outputStream) => createZipArchive(model, outputStream);
+ protected virtual void ExportToStream(TModel model, Stream outputStream) => exportZipArchive(model, outputStream);
- private void createZipArchive(TModel model, Stream outputStream)
+ ///
+ /// Exports an item to Stream as a legacy (.zip based) package.
+ ///
+ /// The item to export.
+ /// The output stream to export to.
+ private void exportZipArchive(TModel model, Stream outputStream)
{
using (var archive = ZipArchive.Create())
{
From a87bcccc42b2e69d619087b46b324499bfdd058a Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Sun, 11 Dec 2022 16:55:44 +0900
Subject: [PATCH 0032/1400] xmldoc
---
osu.Game/Database/LegacyModelExporter.cs | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/osu.Game/Database/LegacyModelExporter.cs b/osu.Game/Database/LegacyModelExporter.cs
index cf41ffc780..18e840fedd 100644
--- a/osu.Game/Database/LegacyModelExporter.cs
+++ b/osu.Game/Database/LegacyModelExporter.cs
@@ -95,6 +95,12 @@ namespace osu.Game.Database
}).ContinueWith(onComplete);
}
+ ///
+ /// Exports an item to Stream.
+ /// Override if custom export method is required.
+ ///
+ /// The item to export.
+ /// The output stream to export to.
protected virtual void ExportToStream(TModel model, Stream outputStream) => exportZipArchive(model, outputStream);
///
From e02b8cb199ebdc13f18aaae292febbfb9c75ec89 Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Sun, 11 Dec 2022 18:30:24 +0900
Subject: [PATCH 0033/1400] Group export methods into their respective managers
---
osu.Game/Beatmaps/BeatmapManager.cs | 9 ++
osu.Game/Database/LegacyBeatmapExporter.cs | 5 +-
osu.Game/Database/LegacyModelExporter.cs | 82 +++++++++----------
osu.Game/Database/LegacyScoreExporter.cs | 8 +-
osu.Game/Database/LegacySkinExporter.cs | 5 +-
.../Online/Leaderboards/LeaderboardScore.cs | 18 ++--
.../Overlays/Settings/Sections/SkinSection.cs | 12 +--
osu.Game/Scoring/ScoreManager.cs | 8 ++
osu.Game/Screens/Edit/Editor.cs | 11 +--
osu.Game/Skinning/SkinManager.cs | 9 ++
10 files changed, 80 insertions(+), 87 deletions(-)
diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs
index 965cc43815..34780082da 100644
--- a/osu.Game/Beatmaps/BeatmapManager.cs
+++ b/osu.Game/Beatmaps/BeatmapManager.cs
@@ -42,6 +42,8 @@ namespace osu.Game.Beatmaps
private readonly WorkingBeatmapCache workingBeatmapCache;
+ private readonly LegacyBeatmapExporter beatmapExporter;
+
public Action<(BeatmapSetInfo beatmapSet, bool isBatch)>? ProcessBeatmap { private get; set; }
public BeatmapManager(Storage storage, RealmAccess realm, IAPIProvider? api, AudioManager audioManager, IResourceStore gameResources, GameHost? host = null,
@@ -66,6 +68,11 @@ namespace osu.Game.Beatmaps
beatmapImporter.PostNotification = obj => PostNotification?.Invoke(obj);
workingBeatmapCache = CreateWorkingBeatmapCache(audioManager, gameResources, userResources, defaultBeatmap, host);
+
+ beatmapExporter = new LegacyBeatmapExporter(storage, realm)
+ {
+ PostNotification = obj => PostNotification?.Invoke(obj)
+ };
}
protected virtual WorkingBeatmapCache CreateWorkingBeatmapCache(AudioManager audioManager, IResourceStore resources, IResourceStore storage, WorkingBeatmap? defaultBeatmap,
@@ -446,6 +453,8 @@ namespace osu.Game.Beatmaps
public Task?> ImportAsUpdate(ProgressNotification notification, ImportTask importTask, BeatmapSetInfo original) =>
beatmapImporter.ImportAsUpdate(notification, importTask, original);
+ public void Export(BeatmapSetInfo beatmap) => Task.Run(() => beatmapExporter.ExportAsync(beatmap));
+
private void updateHashAndMarkDirty(BeatmapSetInfo setInfo)
{
setInfo.Hash = beatmapImporter.ComputeHash(setInfo);
diff --git a/osu.Game/Database/LegacyBeatmapExporter.cs b/osu.Game/Database/LegacyBeatmapExporter.cs
index 22bccbcda6..6349ebde2c 100644
--- a/osu.Game/Database/LegacyBeatmapExporter.cs
+++ b/osu.Game/Database/LegacyBeatmapExporter.cs
@@ -3,14 +3,13 @@
using osu.Framework.Platform;
using osu.Game.Beatmaps;
-using osu.Game.Overlays;
namespace osu.Game.Database
{
public class LegacyBeatmapExporter : LegacyModelExporter
{
- public LegacyBeatmapExporter(Storage storage, RealmAccess realm, INotificationOverlay? notifications = null)
- : base(storage, realm, notifications)
+ public LegacyBeatmapExporter(Storage storage, RealmAccess realm)
+ : base(storage, realm)
{
}
diff --git a/osu.Game/Database/LegacyModelExporter.cs b/osu.Game/Database/LegacyModelExporter.cs
index 18e840fedd..5150651b15 100644
--- a/osu.Game/Database/LegacyModelExporter.cs
+++ b/osu.Game/Database/LegacyModelExporter.cs
@@ -9,7 +9,6 @@ using System.Threading.Tasks;
using osu.Framework.Logging;
using osu.Framework.Platform;
using osu.Game.Extensions;
-using osu.Game.Overlays;
using osu.Game.Overlays.Notifications;
using osu.Game.Utils;
using Realms;
@@ -33,26 +32,16 @@ namespace osu.Game.Database
protected RealmAccess RealmAccess;
- private readonly ProgressNotification notification;
-
private bool canCancel = true;
- private readonly INotificationOverlay? notifications;
+ private string filename = string.Empty;
+ public Action? PostNotification { get; set; }
- protected LegacyModelExporter(Storage storage, RealmAccess realm, INotificationOverlay? notifications = null)
+ protected LegacyModelExporter(Storage storage, RealmAccess realm)
{
exportStorage = storage.GetStorageForDirectory(@"exports");
UserFileStorage = storage.GetStorageForDirectory(@"files");
RealmAccess = realm;
-
- this.notifications = notifications;
- notification = new ProgressNotification
- {
- State = ProgressNotificationState.Active,
- Text = "Exporting...",
- CompletionText = "Export completed"
- };
- notification.CancelRequested += () => canCancel;
}
///
@@ -62,13 +51,9 @@ namespace osu.Game.Database
///
public async Task ExportAsync(TModel model)
{
- notifications?.Post(notification);
-
string itemFilename = model.GetDisplayString().GetValidFilename();
IEnumerable existingExports = exportStorage.GetFiles("", $"{itemFilename}*{FileExtension}");
- string filename = NamingUtils.GetNextBestFilename(existingExports, $"{itemFilename}{FileExtension}");
-
- notification.CompletionClickAction += () => exportStorage.PresentFileExternally(filename);
+ filename = NamingUtils.GetNextBestFilename(existingExports, $"{itemFilename}{FileExtension}");
using (var stream = exportStorage.CreateFileSafely(filename))
{
@@ -77,22 +62,50 @@ namespace osu.Game.Database
}
///
- /// Export te model corresponding to model to given stream.
+ /// Export model to stream.
///
/// The medel which have .
/// The stream to export.
///
public async Task ExportToStreamAsync(TModel model, Stream stream)
{
+ ProgressNotification notification = new ProgressNotification
+ {
+ State = ProgressNotificationState.Active,
+ Text = "Exporting...",
+ CompletionText = "Export completed"
+ };
+ notification.CompletionClickAction += () => exportStorage.PresentFileExternally(filename);
+ notification.CancelRequested += () => canCancel;
+ PostNotification?.Invoke(notification);
+ canCancel = true;
+
Guid id = model.ID;
await Task.Run(() =>
{
RealmAccess.Run(r =>
{
TModel refetchModel = r.Find(id);
- ExportToStream(refetchModel, stream);
+ ExportToStream(refetchModel, stream, notification);
});
- }).ContinueWith(onComplete);
+ }).ContinueWith(t =>
+ {
+ if (t.IsFaulted)
+ {
+ notification.State = ProgressNotificationState.Cancelled;
+ Logger.Error(t.Exception, "An error occurred while exporting");
+
+ return;
+ }
+
+ if (notification.CancellationToken.IsCancellationRequested)
+ {
+ return;
+ }
+
+ notification.CompletionText = "Export Complete, Click to open the folder";
+ notification.State = ProgressNotificationState.Completed;
+ });
}
///
@@ -101,14 +114,16 @@ namespace osu.Game.Database
///
/// The item to export.
/// The output stream to export to.
- protected virtual void ExportToStream(TModel model, Stream outputStream) => exportZipArchive(model, outputStream);
+ /// The notification will displayed to the user
+ protected virtual void ExportToStream(TModel model, Stream outputStream, ProgressNotification notification) => exportZipArchive(model, outputStream, notification);
///
/// Exports an item to Stream as a legacy (.zip based) package.
///
/// The item to export.
/// The output stream to export to.
- private void exportZipArchive(TModel model, Stream outputStream)
+ /// The notification will displayed to the user
+ private void exportZipArchive(TModel model, Stream outputStream, ProgressNotification notification)
{
using (var archive = ZipArchive.Create())
{
@@ -129,24 +144,5 @@ namespace osu.Game.Database
archive.SaveTo(outputStream);
}
}
-
- private void onComplete(Task t)
- {
- if (t.IsFaulted)
- {
- notification.State = ProgressNotificationState.Cancelled;
- Logger.Error(t.Exception, "An error occurred while exporting");
-
- return;
- }
-
- if (notification.CancellationToken.IsCancellationRequested)
- {
- return;
- }
-
- notification.CompletionText = "Export Complete, Click to open the folder";
- notification.State = ProgressNotificationState.Completed;
- }
}
}
diff --git a/osu.Game/Database/LegacyScoreExporter.cs b/osu.Game/Database/LegacyScoreExporter.cs
index eb46bc6db2..1a30d823e1 100644
--- a/osu.Game/Database/LegacyScoreExporter.cs
+++ b/osu.Game/Database/LegacyScoreExporter.cs
@@ -5,21 +5,21 @@ using System.IO;
using System.Linq;
using osu.Framework.Platform;
using osu.Game.Extensions;
-using osu.Game.Overlays;
+using osu.Game.Overlays.Notifications;
using osu.Game.Scoring;
namespace osu.Game.Database
{
public class LegacyScoreExporter : LegacyModelExporter
{
- public LegacyScoreExporter(Storage storage, RealmAccess realm, INotificationOverlay? notifications = null)
- : base(storage, realm, notifications)
+ public LegacyScoreExporter(Storage storage, RealmAccess realm)
+ : base(storage, realm)
{
}
protected override string FileExtension => ".osr";
- protected override void ExportToStream(ScoreInfo model, Stream stream)
+ protected override void ExportToStream(ScoreInfo model, Stream stream, ProgressNotification notification)
{
var file = model.Files.SingleOrDefault();
if (file == null)
diff --git a/osu.Game/Database/LegacySkinExporter.cs b/osu.Game/Database/LegacySkinExporter.cs
index 6e65963f29..52d0e56cbf 100644
--- a/osu.Game/Database/LegacySkinExporter.cs
+++ b/osu.Game/Database/LegacySkinExporter.cs
@@ -2,15 +2,14 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Platform;
-using osu.Game.Overlays;
using osu.Game.Skinning;
namespace osu.Game.Database
{
public class LegacySkinExporter : LegacyModelExporter
{
- public LegacySkinExporter(Storage storage, RealmAccess realm, INotificationOverlay? notifications = null)
- : base(storage, realm, notifications)
+ public LegacySkinExporter(Storage storage, RealmAccess realm)
+ : base(storage, realm)
{
}
diff --git a/osu.Game/Online/Leaderboards/LeaderboardScore.cs b/osu.Game/Online/Leaderboards/LeaderboardScore.cs
index f0457de2dc..e5edf90d1a 100644
--- a/osu.Game/Online/Leaderboards/LeaderboardScore.cs
+++ b/osu.Game/Online/Leaderboards/LeaderboardScore.cs
@@ -6,7 +6,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Threading.Tasks;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
@@ -18,7 +17,6 @@ using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input.Events;
using osu.Framework.Localisation;
-using osu.Game.Database;
using osu.Game.Extensions;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
@@ -34,7 +32,6 @@ using osuTK.Graphics;
using osu.Game.Online.API;
using osu.Game.Resources.Localisation.Web;
using osu.Game.Utils;
-using osu.Framework.Platform;
namespace osu.Game.Online.Leaderboards
{
@@ -73,18 +70,11 @@ namespace osu.Game.Online.Leaderboards
[Resolved(canBeNull: true)]
private SongSelect songSelect { get; set; }
- [Resolved]
- private Storage storage { get; set; }
-
- [Resolved]
- private RealmAccess realm { get; set; }
-
- [Resolved(canBeNull: true)]
- private INotificationOverlay notifications { get; set; }
-
public ITooltip GetCustomTooltip() => new LeaderboardScoreTooltip();
public virtual ScoreInfo TooltipContent => Score;
+ private ScoreManager scoreManager = null!;
+
public LeaderboardScore(ScoreInfo score, int? rank, bool isOnlineScope = true)
{
Score = score;
@@ -103,6 +93,8 @@ namespace osu.Game.Online.Leaderboards
statisticsLabels = GetStatistics(Score).Select(s => new ScoreComponentLabel(s)).ToList();
+ this.scoreManager = scoreManager;
+
ClickableAvatar innerAvatar;
Children = new Drawable[]
@@ -434,7 +426,7 @@ namespace osu.Game.Online.Leaderboards
if (Score.Files.Count > 0)
{
- items.Add(new OsuMenuItem("Export", MenuItemType.Standard, () => Task.Run(() => new LegacyScoreExporter(storage, realm, notifications).ExportAsync(Score))));
+ items.Add(new OsuMenuItem("Export", MenuItemType.Standard, () => scoreManager.Export(Score)));
items.Add(new OsuMenuItem(CommonStrings.ButtonsDelete, MenuItemType.Destructive, () => dialogOverlay?.Push(new LocalScoreDeleteDialog(Score))));
}
diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs
index 9400e803c8..6d338df2fe 100644
--- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs
+++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs
@@ -13,7 +13,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Framework.Logging;
-using osu.Framework.Platform;
using osu.Game.Database;
using osu.Game.Graphics.UserInterface;
using osu.Game.Localisation;
@@ -138,15 +137,6 @@ namespace osu.Game.Overlays.Settings.Sections
[Resolved]
private SkinManager skins { get; set; }
- [Resolved]
- private Storage storage { get; set; }
-
- [Resolved]
- private RealmAccess realm { get; set; }
-
- [Resolved(canBeNull: true)]
- private INotificationOverlay notifications { get; set; }
-
private Bindable currentSkin;
[BackgroundDependencyLoader]
@@ -168,7 +158,7 @@ namespace osu.Game.Overlays.Settings.Sections
{
try
{
- currentSkin.Value.SkinInfo.PerformRead(s => new LegacySkinExporter(storage, realm, notifications).ExportAsync(s));
+ skins.ExporCurrenttSkin();
}
catch (Exception e)
{
diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs
index b2944ad219..525ff58778 100644
--- a/osu.Game/Scoring/ScoreManager.cs
+++ b/osu.Game/Scoring/ScoreManager.cs
@@ -27,6 +27,7 @@ namespace osu.Game.Scoring
{
private readonly OsuConfigManager configManager;
private readonly ScoreImporter scoreImporter;
+ private readonly LegacyScoreExporter scoreExporter;
public ScoreManager(RulesetStore rulesets, Func beatmaps, Storage storage, RealmAccess realm, IAPIProvider api,
OsuConfigManager configManager = null)
@@ -38,6 +39,11 @@ namespace osu.Game.Scoring
{
PostNotification = obj => PostNotification?.Invoke(obj)
};
+
+ scoreExporter = new LegacyScoreExporter(storage, realm)
+ {
+ PostNotification = obj => PostNotification?.Invoke(obj)
+ };
}
public Score GetScore(ScoreInfo score) => scoreImporter.GetScore(score);
@@ -177,6 +183,8 @@ namespace osu.Game.Scoring
public Task>> Import(ProgressNotification notification, params ImportTask[] tasks) => scoreImporter.Import(notification, tasks);
+ public void Export(ScoreInfo score) => Task.Run(() => scoreExporter.ExportAsync(score));
+
public Task> ImportAsUpdate(ProgressNotification notification, ImportTask task, ScoreInfo original) => scoreImporter.ImportAsUpdate(notification, task, original);
public Live Import(ScoreInfo item, ArchiveReader archive = null, bool batchImport = false, CancellationToken cancellationToken = default) =>
diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs
index 342ee2e219..69bcda69c1 100644
--- a/osu.Game/Screens/Edit/Editor.cs
+++ b/osu.Game/Screens/Edit/Editor.cs
@@ -6,7 +6,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Threading.Tasks;
using JetBrains.Annotations;
using osu.Framework;
using osu.Framework.Allocation;
@@ -21,7 +20,6 @@ using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
using osu.Framework.Localisation;
using osu.Framework.Logging;
-using osu.Framework.Platform;
using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Framework.Threading;
@@ -30,7 +28,6 @@ using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Configuration;
-using osu.Game.Database;
using osu.Game.Graphics.Cursor;
using osu.Game.Graphics.UserInterface;
using osu.Game.Input.Bindings;
@@ -89,12 +86,6 @@ namespace osu.Game.Screens.Edit
[Resolved]
private RulesetStore rulesets { get; set; }
- [Resolved]
- private Storage storage { get; set; }
-
- [Resolved]
- private RealmAccess realm { get; set; }
-
[Resolved(canBeNull: true)]
private IDialogOverlay dialogOverlay { get; set; }
@@ -958,7 +949,7 @@ namespace osu.Game.Screens.Edit
private void exportBeatmap()
{
Save();
- Task.Run(() => new LegacyBeatmapExporter(storage, realm, notifications).ExportAsync(Beatmap.Value.BeatmapSetInfo));
+ beatmapManager.Export(Beatmap.Value.BeatmapSetInfo);
}
///
diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs
index 4a5277f3bf..65a602b764 100644
--- a/osu.Game/Skinning/SkinManager.cs
+++ b/osu.Game/Skinning/SkinManager.cs
@@ -58,6 +58,8 @@ namespace osu.Game.Skinning
private readonly SkinImporter skinImporter;
+ private readonly LegacySkinExporter skinExporter;
+
private readonly IResourceStore userFiles;
private Skin argonSkin { get; }
@@ -109,6 +111,11 @@ namespace osu.Game.Skinning
SourceChanged?.Invoke();
};
+
+ skinExporter = new LegacySkinExporter(storage, realm)
+ {
+ PostNotification = obj => PostNotification?.Invoke(obj)
+ };
}
public void SelectRandomSkin()
@@ -280,6 +287,8 @@ namespace osu.Game.Skinning
public Task> Import(ImportTask task, bool batchImport = false, CancellationToken cancellationToken = default) => skinImporter.Import(task, batchImport, cancellationToken);
+ public void ExporCurrenttSkin() => CurrentSkinInfo.Value.PerformRead(s => skinExporter.ExportAsync(s));
+
#endregion
public void Delete([CanBeNull] Expression> filter = null, bool silent = false)
From 3d6d3b40257c17184311f1442b850747d1b3b287 Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Thu, 15 Dec 2022 20:59:11 +0900
Subject: [PATCH 0034/1400] fix weird async logic
---
osu.Game/Beatmaps/BeatmapManager.cs | 2 +-
osu.Game/Scoring/ScoreManager.cs | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs
index 34780082da..56b87eaf11 100644
--- a/osu.Game/Beatmaps/BeatmapManager.cs
+++ b/osu.Game/Beatmaps/BeatmapManager.cs
@@ -453,7 +453,7 @@ namespace osu.Game.Beatmaps
public Task?> ImportAsUpdate(ProgressNotification notification, ImportTask importTask, BeatmapSetInfo original) =>
beatmapImporter.ImportAsUpdate(notification, importTask, original);
- public void Export(BeatmapSetInfo beatmap) => Task.Run(() => beatmapExporter.ExportAsync(beatmap));
+ public Task Export(BeatmapSetInfo beatmap) => beatmapExporter.ExportAsync(beatmap);
private void updateHashAndMarkDirty(BeatmapSetInfo setInfo)
{
diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs
index 525ff58778..f52172a200 100644
--- a/osu.Game/Scoring/ScoreManager.cs
+++ b/osu.Game/Scoring/ScoreManager.cs
@@ -183,7 +183,7 @@ namespace osu.Game.Scoring
public Task>> Import(ProgressNotification notification, params ImportTask[] tasks) => scoreImporter.Import(notification, tasks);
- public void Export(ScoreInfo score) => Task.Run(() => scoreExporter.ExportAsync(score));
+ public Task Export(ScoreInfo score) => scoreExporter.ExportAsync(score);
public Task> ImportAsUpdate(ProgressNotification notification, ImportTask task, ScoreInfo original) => scoreImporter.ImportAsUpdate(notification, task, original);
From c9cffc82484f32c70395509111149d5b0123b539 Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Thu, 15 Dec 2022 21:01:38 +0900
Subject: [PATCH 0035/1400] use resolved attribute
---
osu.Game/Online/Leaderboards/LeaderboardScore.cs | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/osu.Game/Online/Leaderboards/LeaderboardScore.cs b/osu.Game/Online/Leaderboards/LeaderboardScore.cs
index e5edf90d1a..e4ea277756 100644
--- a/osu.Game/Online/Leaderboards/LeaderboardScore.cs
+++ b/osu.Game/Online/Leaderboards/LeaderboardScore.cs
@@ -73,7 +73,8 @@ namespace osu.Game.Online.Leaderboards
public ITooltip GetCustomTooltip() => new LeaderboardScoreTooltip();
public virtual ScoreInfo TooltipContent => Score;
- private ScoreManager scoreManager = null!;
+ [Resolved]
+ private ScoreManager scoreManager { get; set; } = null!;
public LeaderboardScore(ScoreInfo score, int? rank, bool isOnlineScope = true)
{
@@ -87,14 +88,12 @@ namespace osu.Game.Online.Leaderboards
}
[BackgroundDependencyLoader]
- private void load(IAPIProvider api, OsuColour colour, ScoreManager scoreManager)
+ private void load(IAPIProvider api, OsuColour colour)
{
var user = Score.User;
statisticsLabels = GetStatistics(Score).Select(s => new ScoreComponentLabel(s)).ToList();
- this.scoreManager = scoreManager;
-
ClickableAvatar innerAvatar;
Children = new Drawable[]
From 6900d0120a70287ef531a4c0facd398508a76b06 Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Thu, 15 Dec 2022 21:39:48 +0900
Subject: [PATCH 0036/1400] change abstract implement
---
osu.Game/Database/LegacyBeatmapExporter.cs | 2 +-
osu.Game/Database/LegacyModelExporter.cs | 21 ++++++++++++++++-----
osu.Game/Database/LegacySkinExporter.cs | 2 +-
3 files changed, 18 insertions(+), 7 deletions(-)
diff --git a/osu.Game/Database/LegacyBeatmapExporter.cs b/osu.Game/Database/LegacyBeatmapExporter.cs
index 6349ebde2c..107b91a234 100644
--- a/osu.Game/Database/LegacyBeatmapExporter.cs
+++ b/osu.Game/Database/LegacyBeatmapExporter.cs
@@ -6,7 +6,7 @@ using osu.Game.Beatmaps;
namespace osu.Game.Database
{
- public class LegacyBeatmapExporter : LegacyModelExporter
+ public class LegacyBeatmapExporter : LegacyArchiveExporter
{
public LegacyBeatmapExporter(Storage storage, RealmAccess realm)
: base(storage, realm)
diff --git a/osu.Game/Database/LegacyModelExporter.cs b/osu.Game/Database/LegacyModelExporter.cs
index 5150651b15..6b5f8e7e96 100644
--- a/osu.Game/Database/LegacyModelExporter.cs
+++ b/osu.Game/Database/LegacyModelExporter.cs
@@ -32,7 +32,7 @@ namespace osu.Game.Database
protected RealmAccess RealmAccess;
- private bool canCancel = true;
+ protected bool CanCancel = true;
private string filename = string.Empty;
public Action? PostNotification { get; set; }
@@ -76,9 +76,9 @@ namespace osu.Game.Database
CompletionText = "Export completed"
};
notification.CompletionClickAction += () => exportStorage.PresentFileExternally(filename);
- notification.CancelRequested += () => canCancel;
+ notification.CancelRequested += () => CanCancel;
PostNotification?.Invoke(notification);
- canCancel = true;
+ CanCancel = true;
Guid id = model.ID;
await Task.Run(() =>
@@ -115,7 +115,18 @@ namespace osu.Game.Database
/// The item to export.
/// The output stream to export to.
/// The notification will displayed to the user
- protected virtual void ExportToStream(TModel model, Stream outputStream, ProgressNotification notification) => exportZipArchive(model, outputStream, notification);
+ protected abstract void ExportToStream(TModel model, Stream outputStream, ProgressNotification notification);
+ }
+
+ public abstract class LegacyArchiveExporter : LegacyModelExporter
+ where TModel : RealmObject, IHasNamedFiles, IHasGuidPrimaryKey
+ {
+ protected LegacyArchiveExporter(Storage storage, RealmAccess realm)
+ : base(storage, realm)
+ {
+ }
+
+ protected override void ExportToStream(TModel model, Stream outputStream, ProgressNotification notification) => exportZipArchive(model, outputStream, notification);
///
/// Exports an item to Stream as a legacy (.zip based) package.
@@ -140,7 +151,7 @@ namespace osu.Game.Database
}
notification.Text = "Saving Zip Archive...";
- canCancel = false;
+ CanCancel = false;
archive.SaveTo(outputStream);
}
}
diff --git a/osu.Game/Database/LegacySkinExporter.cs b/osu.Game/Database/LegacySkinExporter.cs
index 52d0e56cbf..d3e6a2f0f4 100644
--- a/osu.Game/Database/LegacySkinExporter.cs
+++ b/osu.Game/Database/LegacySkinExporter.cs
@@ -6,7 +6,7 @@ using osu.Game.Skinning;
namespace osu.Game.Database
{
- public class LegacySkinExporter : LegacyModelExporter
+ public class LegacySkinExporter : LegacyArchiveExporter
{
public LegacySkinExporter(Storage storage, RealmAccess realm)
: base(storage, realm)
From 6ef5b2733f01a4ebd2ccd733a4e6c80c6158698f Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Thu, 15 Dec 2022 21:41:15 +0900
Subject: [PATCH 0037/1400] Export instead of ExportCurrentSkin
---
osu.Game/Overlays/Settings/Sections/SkinSection.cs | 2 +-
osu.Game/Skinning/SkinManager.cs | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs
index 6d338df2fe..1a64416b3e 100644
--- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs
+++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs
@@ -158,7 +158,7 @@ namespace osu.Game.Overlays.Settings.Sections
{
try
{
- skins.ExporCurrenttSkin();
+ skins.CurrentSkinInfo.Value.PerformRead(s => skins.ExportSkin(s));
}
catch (Exception e)
{
diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs
index 65a602b764..d4e7d252ac 100644
--- a/osu.Game/Skinning/SkinManager.cs
+++ b/osu.Game/Skinning/SkinManager.cs
@@ -287,7 +287,7 @@ namespace osu.Game.Skinning
public Task> Import(ImportTask task, bool batchImport = false, CancellationToken cancellationToken = default) => skinImporter.Import(task, batchImport, cancellationToken);
- public void ExporCurrenttSkin() => CurrentSkinInfo.Value.PerformRead(s => skinExporter.ExportAsync(s));
+ public Task ExportSkin(SkinInfo skin) => skinExporter.ExportAsync(skin);
#endregion
From ec251664a7c4a2bbb6b022a046cf35960bd2497b Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Thu, 15 Dec 2022 22:45:36 +0900
Subject: [PATCH 0038/1400] use ThrowIfCancellationRequested instead of
CancelRequested
---
osu.Game/Database/LegacyModelExporter.cs | 70 ++++++++++++++----------
1 file changed, 42 insertions(+), 28 deletions(-)
diff --git a/osu.Game/Database/LegacyModelExporter.cs b/osu.Game/Database/LegacyModelExporter.cs
index 6b5f8e7e96..0ebcfaa07e 100644
--- a/osu.Game/Database/LegacyModelExporter.cs
+++ b/osu.Game/Database/LegacyModelExporter.cs
@@ -32,8 +32,6 @@ namespace osu.Game.Database
protected RealmAccess RealmAccess;
- protected bool CanCancel = true;
-
private string filename = string.Empty;
public Action? PostNotification { get; set; }
@@ -54,10 +52,16 @@ namespace osu.Game.Database
string itemFilename = model.GetDisplayString().GetValidFilename();
IEnumerable existingExports = exportStorage.GetFiles("", $"{itemFilename}*{FileExtension}");
filename = NamingUtils.GetNextBestFilename(existingExports, $"{itemFilename}{FileExtension}");
+ bool success;
using (var stream = exportStorage.CreateFileSafely(filename))
{
- await ExportToStreamAsync(model, stream);
+ success = await ExportToStreamAsync(model, stream);
+ }
+
+ if (!success)
+ {
+ exportStorage.Delete(filename);
}
}
@@ -66,8 +70,8 @@ namespace osu.Game.Database
///
/// The medel which have .
/// The stream to export.
- ///
- public async Task ExportToStreamAsync(TModel model, Stream stream)
+ /// Whether the export was successful
+ public async Task ExportToStreamAsync(TModel model, Stream stream)
{
ProgressNotification notification = new ProgressNotification
{
@@ -76,35 +80,33 @@ namespace osu.Game.Database
CompletionText = "Export completed"
};
notification.CompletionClickAction += () => exportStorage.PresentFileExternally(filename);
- notification.CancelRequested += () => CanCancel;
PostNotification?.Invoke(notification);
- CanCancel = true;
Guid id = model.ID;
- await Task.Run(() =>
+ return await Task.Run(() =>
{
RealmAccess.Run(r =>
{
TModel refetchModel = r.Find(id);
ExportToStream(refetchModel, stream, notification);
});
- }).ContinueWith(t =>
+ }, notification.CancellationToken).ContinueWith(t =>
{
+ if (t.IsCanceled)
+ {
+ return false;
+ }
+
if (t.IsFaulted)
{
notification.State = ProgressNotificationState.Cancelled;
Logger.Error(t.Exception, "An error occurred while exporting");
-
- return;
- }
-
- if (notification.CancellationToken.IsCancellationRequested)
- {
- return;
+ return false;
}
notification.CompletionText = "Export Complete, Click to open the folder";
notification.State = ProgressNotificationState.Completed;
+ return true;
});
}
@@ -121,6 +123,8 @@ namespace osu.Game.Database
public abstract class LegacyArchiveExporter : LegacyModelExporter
where TModel : RealmObject, IHasNamedFiles, IHasGuidPrimaryKey
{
+ private bool canCancel = true;
+
protected LegacyArchiveExporter(Storage storage, RealmAccess realm)
: base(storage, realm)
{
@@ -136,23 +140,33 @@ namespace osu.Game.Database
/// The notification will displayed to the user
private void exportZipArchive(TModel model, Stream outputStream, ProgressNotification notification)
{
- using (var archive = ZipArchive.Create())
+ try
{
- float i = 0;
+ notification.CancelRequested += () => canCancel;
- foreach (var file in model.Files)
+ using (var archive = ZipArchive.Create())
{
- if (notification.CancellationToken.IsCancellationRequested) return;
+ float i = 0;
- archive.AddEntry(file.Filename, UserFileStorage.GetStream(file.File.GetStoragePath()));
- i++;
- notification.Progress = i / model.Files.Count();
- notification.Text = $"Exporting... ({i}/{model.Files.Count()})";
+ foreach (var file in model.Files)
+ {
+ notification.CancellationToken.ThrowIfCancellationRequested();
+
+ archive.AddEntry(file.Filename, UserFileStorage.GetStream(file.File.GetStoragePath()));
+ i++;
+ notification.Progress = i / model.Files.Count();
+ notification.Text = $"Exporting... ({i}/{model.Files.Count()})";
+ }
+
+ notification.Text = "Saving Zip Archive...";
+ canCancel = false;
+ archive.SaveTo(outputStream);
}
-
- notification.Text = "Saving Zip Archive...";
- CanCancel = false;
- archive.SaveTo(outputStream);
+ }
+ catch (OperationCanceledException)
+ {
+ Logger.Log("Export operat canceled");
+ throw;
}
}
}
From f5226bd50b02068e42116940e12c1f47bbf158ce Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Thu, 15 Dec 2022 23:12:25 +0900
Subject: [PATCH 0039/1400] use ZipWriter
Export directly to stream instead of creating a archive
so we can cancel this anytime
---
osu.Game/Database/LegacyModelExporter.cs | 16 +++++-----------
1 file changed, 5 insertions(+), 11 deletions(-)
diff --git a/osu.Game/Database/LegacyModelExporter.cs b/osu.Game/Database/LegacyModelExporter.cs
index 0ebcfaa07e..9e0c1e0c6d 100644
--- a/osu.Game/Database/LegacyModelExporter.cs
+++ b/osu.Game/Database/LegacyModelExporter.cs
@@ -12,7 +12,9 @@ using osu.Game.Extensions;
using osu.Game.Overlays.Notifications;
using osu.Game.Utils;
using Realms;
-using SharpCompress.Archives.Zip;
+using SharpCompress.Common;
+using SharpCompress.Writers;
+using SharpCompress.Writers.Zip;
namespace osu.Game.Database
{
@@ -123,8 +125,6 @@ namespace osu.Game.Database
public abstract class LegacyArchiveExporter : LegacyModelExporter
where TModel : RealmObject, IHasNamedFiles, IHasGuidPrimaryKey
{
- private bool canCancel = true;
-
protected LegacyArchiveExporter(Storage storage, RealmAccess realm)
: base(storage, realm)
{
@@ -142,9 +142,7 @@ namespace osu.Game.Database
{
try
{
- notification.CancelRequested += () => canCancel;
-
- using (var archive = ZipArchive.Create())
+ using (var writer = new ZipWriter(outputStream, new ZipWriterOptions(CompressionType.Deflate)))
{
float i = 0;
@@ -152,15 +150,11 @@ namespace osu.Game.Database
{
notification.CancellationToken.ThrowIfCancellationRequested();
- archive.AddEntry(file.Filename, UserFileStorage.GetStream(file.File.GetStoragePath()));
+ writer.Write(file.Filename, UserFileStorage.GetStream(file.File.GetStoragePath()));
i++;
notification.Progress = i / model.Files.Count();
notification.Text = $"Exporting... ({i}/{model.Files.Count()})";
}
-
- notification.Text = "Saving Zip Archive...";
- canCancel = false;
- archive.SaveTo(outputStream);
}
}
catch (OperationCanceledException)
From dadadaff65057cd16210ae9ba05634e308b5ec53 Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Thu, 15 Dec 2022 23:20:29 +0900
Subject: [PATCH 0040/1400] remove try catch
---
osu.Game/Database/LegacyModelExporter.cs | 26 ++++++++----------------
1 file changed, 9 insertions(+), 17 deletions(-)
diff --git a/osu.Game/Database/LegacyModelExporter.cs b/osu.Game/Database/LegacyModelExporter.cs
index 9e0c1e0c6d..824460cdc9 100644
--- a/osu.Game/Database/LegacyModelExporter.cs
+++ b/osu.Game/Database/LegacyModelExporter.cs
@@ -140,28 +140,20 @@ namespace osu.Game.Database
/// The notification will displayed to the user
private void exportZipArchive(TModel model, Stream outputStream, ProgressNotification notification)
{
- try
+ using (var writer = new ZipWriter(outputStream, new ZipWriterOptions(CompressionType.Deflate)))
{
- using (var writer = new ZipWriter(outputStream, new ZipWriterOptions(CompressionType.Deflate)))
+ float i = 0;
+
+ foreach (var file in model.Files)
{
- float i = 0;
+ notification.CancellationToken.ThrowIfCancellationRequested();
- foreach (var file in model.Files)
- {
- notification.CancellationToken.ThrowIfCancellationRequested();
-
- writer.Write(file.Filename, UserFileStorage.GetStream(file.File.GetStoragePath()));
- i++;
- notification.Progress = i / model.Files.Count();
- notification.Text = $"Exporting... ({i}/{model.Files.Count()})";
- }
+ writer.Write(file.Filename, UserFileStorage.GetStream(file.File.GetStoragePath()));
+ i++;
+ notification.Progress = i / model.Files.Count();
+ notification.Text = $"Exporting... ({i}/{model.Files.Count()})";
}
}
- catch (OperationCanceledException)
- {
- Logger.Log("Export operat canceled");
- throw;
- }
}
}
}
From cd8420bc66c56aa7e686a579ebd9a18634861b45 Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Thu, 15 Dec 2022 23:34:40 +0900
Subject: [PATCH 0041/1400] Handle the case where the file cannot be found
---
osu.Game/Database/LegacyModelExporter.cs | 23 ++++++++++++++++++++++-
1 file changed, 22 insertions(+), 1 deletion(-)
diff --git a/osu.Game/Database/LegacyModelExporter.cs b/osu.Game/Database/LegacyModelExporter.cs
index 824460cdc9..531a6f48da 100644
--- a/osu.Game/Database/LegacyModelExporter.cs
+++ b/osu.Game/Database/LegacyModelExporter.cs
@@ -143,12 +143,33 @@ namespace osu.Game.Database
using (var writer = new ZipWriter(outputStream, new ZipWriterOptions(CompressionType.Deflate)))
{
float i = 0;
+ bool fileMissing = false;
foreach (var file in model.Files)
{
notification.CancellationToken.ThrowIfCancellationRequested();
- writer.Write(file.Filename, UserFileStorage.GetStream(file.File.GetStoragePath()));
+ using (var stream = UserFileStorage.GetStream(file.File.GetStoragePath()))
+ {
+ // Sometimes we cannot find the file(probably deleted by the user), so we handle this and post a error.
+ if (stream == null)
+ {
+ // Only pop up once to prevent spam.
+ if (!fileMissing)
+ {
+ PostNotification?.Invoke(new SimpleErrorNotification
+ {
+ Text = "Some of your files are missing, they will not be included in the archive"
+ });
+ fileMissing = true;
+ }
+ }
+ else
+ {
+ writer.Write(file.Filename, stream);
+ }
+ }
+
i++;
notification.Progress = i / model.Files.Count();
notification.Text = $"Exporting... ({i}/{model.Files.Count()})";
From 5912dfd443effad317f5085aba57f4b380868d6e Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Thu, 15 Dec 2022 23:42:49 +0900
Subject: [PATCH 0042/1400] using declaration
reshaper
---
osu.Game/Database/LegacyModelExporter.cs | 49 ++++++++++++------------
1 file changed, 24 insertions(+), 25 deletions(-)
diff --git a/osu.Game/Database/LegacyModelExporter.cs b/osu.Game/Database/LegacyModelExporter.cs
index 531a6f48da..d896e4bce6 100644
--- a/osu.Game/Database/LegacyModelExporter.cs
+++ b/osu.Game/Database/LegacyModelExporter.cs
@@ -140,40 +140,39 @@ namespace osu.Game.Database
/// The notification will displayed to the user
private void exportZipArchive(TModel model, Stream outputStream, ProgressNotification notification)
{
- using (var writer = new ZipWriter(outputStream, new ZipWriterOptions(CompressionType.Deflate)))
+ using var writer = new ZipWriter(outputStream, new ZipWriterOptions(CompressionType.Deflate));
+
+ float i = 0;
+ bool fileMissing = false;
+
+ foreach (var file in model.Files)
{
- float i = 0;
- bool fileMissing = false;
+ notification.CancellationToken.ThrowIfCancellationRequested();
- foreach (var file in model.Files)
+ using (var stream = UserFileStorage.GetStream(file.File.GetStoragePath()))
{
- notification.CancellationToken.ThrowIfCancellationRequested();
-
- using (var stream = UserFileStorage.GetStream(file.File.GetStoragePath()))
+ // Sometimes we cannot find the file(probably deleted by the user), so we handle this and post a error.
+ if (stream == null)
{
- // Sometimes we cannot find the file(probably deleted by the user), so we handle this and post a error.
- if (stream == null)
+ // Only pop up once to prevent spam.
+ if (!fileMissing)
{
- // Only pop up once to prevent spam.
- if (!fileMissing)
+ PostNotification?.Invoke(new SimpleErrorNotification
{
- PostNotification?.Invoke(new SimpleErrorNotification
- {
- Text = "Some of your files are missing, they will not be included in the archive"
- });
- fileMissing = true;
- }
- }
- else
- {
- writer.Write(file.Filename, stream);
+ Text = "Some of your files are missing, they will not be included in the archive"
+ });
+ fileMissing = true;
}
}
-
- i++;
- notification.Progress = i / model.Files.Count();
- notification.Text = $"Exporting... ({i}/{model.Files.Count()})";
+ else
+ {
+ writer.Write(file.Filename, stream);
+ }
}
+
+ i++;
+ notification.Progress = i / model.Files.Count();
+ notification.Text = $"Exporting... ({i}/{model.Files.Count()})";
}
}
}
From b37f1cce3fc4bfd3c5408a8fe32a4fdc796f3b8d Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Tue, 20 Dec 2022 23:46:05 +0900
Subject: [PATCH 0043/1400] Added ability to report chat
---
.../Visual/Online/TestSceneChatOverlay.cs | 38 +++++++
osu.Game/Overlays/Chat/ChatReportReason.cs | 36 ++++++
osu.Game/Overlays/Chat/DrawableUsername.cs | 16 ++-
osu.Game/Overlays/Chat/ReportChatPopover.cs | 106 ++++++++++++++++++
osu.Game/Overlays/ChatOverlay.cs | 3 +-
5 files changed, 197 insertions(+), 2 deletions(-)
create mode 100644 osu.Game/Overlays/Chat/ChatReportReason.cs
create mode 100644 osu.Game/Overlays/Chat/ReportChatPopover.cs
diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs
index 8cc4eabcd7..44d739a6e3 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs
@@ -30,6 +30,8 @@ using osu.Game.Overlays.Chat.Listing;
using osu.Game.Overlays.Chat.ChannelList;
using osuTK;
using osuTK.Input;
+using osu.Game.Graphics.UserInterfaceV2;
+using osu.Game.Graphics.Sprites;
namespace osu.Game.Tests.Visual.Online
{
@@ -530,6 +532,42 @@ namespace osu.Game.Tests.Visual.Online
});
}
+ [Test]
+ public void TestChatReport()
+ {
+ AddStep("Show overlay with channel", () =>
+ {
+ chatOverlay.Show();
+ channelManager.CurrentChannel.Value = channelManager.JoinChannel(testChannel1);
+ });
+
+ AddAssert("Overlay is visible", () => chatOverlay.State.Value == Visibility.Visible);
+ waitForChannel1Visible();
+
+ AddStep("Right click username", () =>
+ {
+ var username = this.ChildrenOfType().First();
+ InputManager.MoveMouseTo(username);
+ InputManager.Click(MouseButton.Right);
+ });
+
+ AddStep("Click report", () =>
+ {
+ var btn = this.ChildrenOfType().First(x => x.Text == "Report");
+ InputManager.MoveMouseTo(btn);
+ InputManager.Click(MouseButton.Left);
+ });
+
+ AddStep("Try to report", () =>
+ {
+ var btn = this.ChildrenOfType().Single().ChildrenOfType().Single();
+ InputManager.MoveMouseTo(btn);
+ InputManager.Click(MouseButton.Left);
+ });
+
+ AddAssert("Report message sended", () => channelManager.CurrentChannel.Value.Messages.Any(x => x.Content.Contains("!report")));
+ }
+
private void joinTestChannel(int i)
{
AddStep($"Join test channel {i}", () => channelManager.JoinChannel(testChannels[i]));
diff --git a/osu.Game/Overlays/Chat/ChatReportReason.cs b/osu.Game/Overlays/Chat/ChatReportReason.cs
new file mode 100644
index 0000000000..55593d29ad
--- /dev/null
+++ b/osu.Game/Overlays/Chat/ChatReportReason.cs
@@ -0,0 +1,36 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.ComponentModel;
+using osu.Framework.Localisation;
+using osu.Game.Resources.Localisation.Web;
+
+namespace osu.Game.Overlays.Chat
+{
+ public enum ChatReportReason
+ {
+ [Description("Insulting People")]
+ [LocalisableDescription(typeof(UsersStrings), nameof(UsersStrings.ReportOptionsInsults))]
+ Insults,
+
+ [Description("Spam")]
+ [LocalisableDescription(typeof(UsersStrings), nameof(UsersStrings.ReportOptionsSpam))]
+ Spam,
+
+ [Description("Cheating")]
+ [LocalisableDescription(typeof(UsersStrings), nameof(UsersStrings.ReportOptionsCheating))]
+ FoulPlay,
+
+ [Description("Unwanted Content")]
+ [LocalisableDescription(typeof(UsersStrings), nameof(UsersStrings.ReportOptionsUnwantedContent))]
+ UnwantedContent,
+
+ [Description("Nonsense")]
+ [LocalisableDescription(typeof(UsersStrings), nameof(UsersStrings.ReportOptionsNonsense))]
+ Nonsense,
+
+ [Description("Other")]
+ [LocalisableDescription(typeof(UsersStrings), nameof(UsersStrings.ReportOptionsOther))]
+ Other
+ }
+}
diff --git a/osu.Game/Overlays/Chat/DrawableUsername.cs b/osu.Game/Overlays/Chat/DrawableUsername.cs
index 6bae498a6c..f70175f081 100644
--- a/osu.Game/Overlays/Chat/DrawableUsername.cs
+++ b/osu.Game/Overlays/Chat/DrawableUsername.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using osu.Framework.Allocation;
+using osu.Framework.Extensions;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@@ -25,7 +26,7 @@ using osuTK.Graphics;
namespace osu.Game.Overlays.Chat
{
- public partial class DrawableUsername : OsuClickableContainer, IHasContextMenu
+ public partial class DrawableUsername : OsuClickableContainer, IHasContextMenu, IHasPopover
{
public Color4 AccentColour { get; }
@@ -152,12 +153,20 @@ namespace osu.Game.Overlays.Chat
};
if (!user.Equals(api.LocalUser.Value))
+ {
items.Add(new OsuMenuItem("Start Chat", MenuItemType.Standard, openUserChannel));
+ items.Add(new OsuMenuItem("Report", MenuItemType.Destructive, this.ShowPopover));
+ }
return items.ToArray();
}
}
+ private void report(ChatReportReason reason, string comments)
+ {
+ chatManager?.PostMessage($"!report {user.Username} ({reason.GetDescription()}): {comments}");
+ }
+
private void openUserChannel()
{
chatManager?.OpenPrivateChannel(user);
@@ -221,5 +230,10 @@ namespace osu.Game.Overlays.Chat
Color4Extensions.FromHex("812a96"),
Color4Extensions.FromHex("992861"),
};
+
+ public Popover GetPopover() => new ReportChatPopover(user)
+ {
+ Action = report
+ };
}
}
diff --git a/osu.Game/Overlays/Chat/ReportChatPopover.cs b/osu.Game/Overlays/Chat/ReportChatPopover.cs
new file mode 100644
index 0000000000..cf5e456874
--- /dev/null
+++ b/osu.Game/Overlays/Chat/ReportChatPopover.cs
@@ -0,0 +1,106 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using osu.Framework.Allocation;
+using osu.Framework.Audio;
+using osu.Framework.Extensions;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Sprites;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Containers;
+using osu.Game.Graphics.Sprites;
+using osu.Game.Graphics.UserInterface;
+using osu.Game.Graphics.UserInterfaceV2;
+using osu.Game.Online.API.Requests.Responses;
+using osu.Game.Resources.Localisation.Web;
+using osuTK;
+
+namespace osu.Game.Overlays.Chat
+{
+ public partial class ReportChatPopover : OsuPopover
+ {
+ public Action? Action;
+
+ private readonly APIUser? user;
+
+ private OsuEnumDropdown reasonDropdown = null!;
+ private OsuTextBox commentsTextBox = null!;
+
+ public ReportChatPopover(APIUser? user)
+ {
+ this.user = user;
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours, AudioManager audio)
+ {
+ Child = new ReverseChildIDFillFlowContainer
+ {
+ Direction = FillDirection.Vertical,
+ Width = 500,
+ AutoSizeAxes = Axes.Y,
+ Spacing = new Vector2(7),
+ Children = new Drawable[]
+ {
+ new SpriteIcon
+ {
+ Origin = Anchor.TopCentre,
+ Anchor = Anchor.TopCentre,
+ Icon = FontAwesome.Solid.ExclamationTriangle,
+ Size = new Vector2(36),
+ },
+ new OsuSpriteText
+ {
+ Origin = Anchor.TopCentre,
+ Anchor = Anchor.TopCentre,
+ Text = ReportStrings.UserTitle(user?.Username ?? @"Someone"),
+ Font = OsuFont.Torus.With(size: 25),
+ Margin = new MarginPadding { Bottom = 10 }
+ },
+ new OsuSpriteText
+ {
+ Origin = Anchor.TopCentre,
+ Anchor = Anchor.TopCentre,
+ Text = UsersStrings.ReportReason,
+ },
+ new Container
+ {
+ RelativeSizeAxes = Axes.X,
+ Height = 40,
+ Child = reasonDropdown = new OsuEnumDropdown
+ {
+ RelativeSizeAxes = Axes.X
+ }
+ },
+ new OsuSpriteText
+ {
+ Origin = Anchor.TopCentre,
+ Anchor = Anchor.TopCentre,
+ Text = UsersStrings.ReportComments,
+ },
+ commentsTextBox = new OsuTextBox
+ {
+ RelativeSizeAxes = Axes.X,
+ PlaceholderText = UsersStrings.ReportPlaceholder,
+ },
+ new RoundedButton
+ {
+ Origin = Anchor.TopCentre,
+ Anchor = Anchor.TopCentre,
+ Width = 200,
+ BackgroundColour = colours.Red3,
+ Text = UsersStrings.ReportActionsSend,
+ Action = () =>
+ {
+ Action?.Invoke(reasonDropdown.Current.Value, commentsTextBox.Text);
+ this.HidePopover();
+ },
+ Margin = new MarginPadding { Bottom = 5, Top = 10 },
+ }
+ }
+ };
+ }
+ }
+}
diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs
index c539cdc5ec..c3a6ed0175 100644
--- a/osu.Game/Overlays/ChatOverlay.cs
+++ b/osu.Game/Overlays/ChatOverlay.cs
@@ -9,6 +9,7 @@ using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input;
using osu.Framework.Input.Bindings;
@@ -122,7 +123,7 @@ namespace osu.Game.Overlays
RelativeSizeAxes = Axes.Y,
Width = side_bar_width,
},
- new Container
+ new PopoverContainer
{
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.TopRight,
From ffa32307c3ef8c9917a210a31871b9000cf80246 Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Wed, 21 Dec 2022 01:37:16 +0900
Subject: [PATCH 0044/1400] abstract ReportPopover
---
.../Graphics/UserInterfaceV2/ReportPopover.cs | 114 ++++++++++++++++++
osu.Game/Overlays/Chat/ReportChatPopover.cs | 94 +--------------
.../Overlays/Comments/ReportCommentPopover.cs | 98 +--------------
3 files changed, 119 insertions(+), 187 deletions(-)
create mode 100644 osu.Game/Graphics/UserInterfaceV2/ReportPopover.cs
diff --git a/osu.Game/Graphics/UserInterfaceV2/ReportPopover.cs b/osu.Game/Graphics/UserInterfaceV2/ReportPopover.cs
new file mode 100644
index 0000000000..44af108ab1
--- /dev/null
+++ b/osu.Game/Graphics/UserInterfaceV2/ReportPopover.cs
@@ -0,0 +1,114 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using osu.Framework.Allocation;
+using osu.Framework.Extensions;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Sprites;
+using osu.Framework.Localisation;
+using osu.Game.Graphics.Containers;
+using osu.Game.Graphics.Sprites;
+using osu.Game.Graphics.UserInterface;
+using osu.Game.Resources.Localisation.Web;
+using osuTK;
+
+namespace osu.Game.Graphics.UserInterfaceV2
+{
+ public abstract partial class ReportPopover : OsuPopover
+ where T : struct, Enum
+ {
+ public Action? Action;
+
+ private OsuEnumDropdown reasonDropdown = null!;
+ private OsuTextBox commentsTextBox = null!;
+ private RoundedButton submitButton = null!;
+
+ public bool CanSubmitEmptyReason = false;
+ public LocalisableString Header;
+
+ protected ReportPopover(LocalisableString headerString)
+ {
+ Header = headerString;
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours)
+ {
+ Child = new ReverseChildIDFillFlowContainer
+ {
+ Direction = FillDirection.Vertical,
+ Width = 500,
+ AutoSizeAxes = Axes.Y,
+ Spacing = new Vector2(7),
+ Children = new Drawable[]
+ {
+ new SpriteIcon
+ {
+ Origin = Anchor.TopCentre,
+ Anchor = Anchor.TopCentre,
+ Icon = FontAwesome.Solid.ExclamationTriangle,
+ Size = new Vector2(36),
+ },
+ new OsuSpriteText
+ {
+ Origin = Anchor.TopCentre,
+ Anchor = Anchor.TopCentre,
+ Text = Header,
+ Font = OsuFont.Torus.With(size: 25),
+ Margin = new MarginPadding { Bottom = 10 }
+ },
+ new OsuSpriteText
+ {
+ Origin = Anchor.TopCentre,
+ Anchor = Anchor.TopCentre,
+ Text = UsersStrings.ReportReason,
+ },
+ new Container
+ {
+ RelativeSizeAxes = Axes.X,
+ Height = 40,
+ Child = reasonDropdown = new OsuEnumDropdown
+ {
+ RelativeSizeAxes = Axes.X
+ }
+ },
+ new OsuSpriteText
+ {
+ Origin = Anchor.TopCentre,
+ Anchor = Anchor.TopCentre,
+ Text = UsersStrings.ReportComments,
+ },
+ commentsTextBox = new OsuTextBox
+ {
+ RelativeSizeAxes = Axes.X,
+ PlaceholderText = UsersStrings.ReportPlaceholder,
+ },
+ submitButton = new RoundedButton
+ {
+ Origin = Anchor.TopCentre,
+ Anchor = Anchor.TopCentre,
+ Width = 200,
+ BackgroundColour = colours.Red3,
+ Text = UsersStrings.ReportActionsSend,
+ Action = () =>
+ {
+ Action?.Invoke(reasonDropdown.Current.Value, commentsTextBox.Text);
+ this.HidePopover();
+ },
+ Margin = new MarginPadding { Bottom = 5, Top = 10 },
+ }
+ }
+ };
+
+ if (!CanSubmitEmptyReason)
+ {
+ commentsTextBox.Current.BindValueChanged(e =>
+ {
+ submitButton.Enabled.Value = !string.IsNullOrWhiteSpace(e.NewValue);
+ }, true);
+ }
+ }
+ }
+}
diff --git a/osu.Game/Overlays/Chat/ReportChatPopover.cs b/osu.Game/Overlays/Chat/ReportChatPopover.cs
index cf5e456874..79c3922795 100644
--- a/osu.Game/Overlays/Chat/ReportChatPopover.cs
+++ b/osu.Game/Overlays/Chat/ReportChatPopover.cs
@@ -1,106 +1,18 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using System;
-using osu.Framework.Allocation;
-using osu.Framework.Audio;
-using osu.Framework.Extensions;
-using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
-using osu.Game.Graphics;
-using osu.Game.Graphics.Containers;
-using osu.Game.Graphics.Sprites;
-using osu.Game.Graphics.UserInterface;
using osu.Game.Graphics.UserInterfaceV2;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Resources.Localisation.Web;
-using osuTK;
namespace osu.Game.Overlays.Chat
{
- public partial class ReportChatPopover : OsuPopover
+ public partial class ReportChatPopover : ReportPopover
{
- public Action? Action;
-
- private readonly APIUser? user;
-
- private OsuEnumDropdown reasonDropdown = null!;
- private OsuTextBox commentsTextBox = null!;
-
public ReportChatPopover(APIUser? user)
+ : base(ReportStrings.UserTitle(user?.Username ?? @"Someone"))
{
- this.user = user;
- }
-
- [BackgroundDependencyLoader]
- private void load(OsuColour colours, AudioManager audio)
- {
- Child = new ReverseChildIDFillFlowContainer
- {
- Direction = FillDirection.Vertical,
- Width = 500,
- AutoSizeAxes = Axes.Y,
- Spacing = new Vector2(7),
- Children = new Drawable[]
- {
- new SpriteIcon
- {
- Origin = Anchor.TopCentre,
- Anchor = Anchor.TopCentre,
- Icon = FontAwesome.Solid.ExclamationTriangle,
- Size = new Vector2(36),
- },
- new OsuSpriteText
- {
- Origin = Anchor.TopCentre,
- Anchor = Anchor.TopCentre,
- Text = ReportStrings.UserTitle(user?.Username ?? @"Someone"),
- Font = OsuFont.Torus.With(size: 25),
- Margin = new MarginPadding { Bottom = 10 }
- },
- new OsuSpriteText
- {
- Origin = Anchor.TopCentre,
- Anchor = Anchor.TopCentre,
- Text = UsersStrings.ReportReason,
- },
- new Container
- {
- RelativeSizeAxes = Axes.X,
- Height = 40,
- Child = reasonDropdown = new OsuEnumDropdown
- {
- RelativeSizeAxes = Axes.X
- }
- },
- new OsuSpriteText
- {
- Origin = Anchor.TopCentre,
- Anchor = Anchor.TopCentre,
- Text = UsersStrings.ReportComments,
- },
- commentsTextBox = new OsuTextBox
- {
- RelativeSizeAxes = Axes.X,
- PlaceholderText = UsersStrings.ReportPlaceholder,
- },
- new RoundedButton
- {
- Origin = Anchor.TopCentre,
- Anchor = Anchor.TopCentre,
- Width = 200,
- BackgroundColour = colours.Red3,
- Text = UsersStrings.ReportActionsSend,
- Action = () =>
- {
- Action?.Invoke(reasonDropdown.Current.Value, commentsTextBox.Text);
- this.HidePopover();
- },
- Margin = new MarginPadding { Bottom = 5, Top = 10 },
- }
- }
- };
+ CanSubmitEmptyReason = true;
}
}
}
diff --git a/osu.Game/Overlays/Comments/ReportCommentPopover.cs b/osu.Game/Overlays/Comments/ReportCommentPopover.cs
index f3b2a2f97c..e688dad755 100644
--- a/osu.Game/Overlays/Comments/ReportCommentPopover.cs
+++ b/osu.Game/Overlays/Comments/ReportCommentPopover.cs
@@ -1,111 +1,17 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using System;
-using osu.Framework.Allocation;
-using osu.Framework.Extensions;
-using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
-using osu.Game.Graphics;
-using osu.Game.Graphics.Containers;
-using osu.Game.Graphics.Sprites;
-using osu.Game.Graphics.UserInterface;
using osu.Game.Graphics.UserInterfaceV2;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Resources.Localisation.Web;
-using osuTK;
namespace osu.Game.Overlays.Comments
{
- public partial class ReportCommentPopover : OsuPopover
+ public partial class ReportCommentPopover : ReportPopover
{
- public Action? Action;
-
- private readonly Comment? comment;
-
- private OsuEnumDropdown reasonDropdown = null!;
- private OsuTextBox commentsTextBox = null!;
- private RoundedButton submitButton = null!;
-
public ReportCommentPopover(Comment? comment)
+ : base(ReportStrings.CommentTitle(comment?.User?.Username ?? comment?.LegacyName ?? @"Someone"))
{
- this.comment = comment;
- }
-
- [BackgroundDependencyLoader]
- private void load(OsuColour colours)
- {
- Child = new ReverseChildIDFillFlowContainer
- {
- Direction = FillDirection.Vertical,
- Width = 500,
- AutoSizeAxes = Axes.Y,
- Spacing = new Vector2(7),
- Children = new Drawable[]
- {
- new SpriteIcon
- {
- Origin = Anchor.TopCentre,
- Anchor = Anchor.TopCentre,
- Icon = FontAwesome.Solid.ExclamationTriangle,
- Size = new Vector2(36),
- },
- new OsuSpriteText
- {
- Origin = Anchor.TopCentre,
- Anchor = Anchor.TopCentre,
- Text = ReportStrings.CommentTitle(comment?.User?.Username ?? comment?.LegacyName ?? @"Someone"),
- Font = OsuFont.Torus.With(size: 25),
- Margin = new MarginPadding { Bottom = 10 }
- },
- new OsuSpriteText
- {
- Origin = Anchor.TopCentre,
- Anchor = Anchor.TopCentre,
- Text = UsersStrings.ReportReason,
- },
- new Container
- {
- RelativeSizeAxes = Axes.X,
- Height = 40,
- Child = reasonDropdown = new OsuEnumDropdown
- {
- RelativeSizeAxes = Axes.X
- }
- },
- new OsuSpriteText
- {
- Origin = Anchor.TopCentre,
- Anchor = Anchor.TopCentre,
- Text = UsersStrings.ReportComments,
- },
- commentsTextBox = new OsuTextBox
- {
- RelativeSizeAxes = Axes.X,
- PlaceholderText = UsersStrings.ReportPlaceholder,
- },
- submitButton = new RoundedButton
- {
- Origin = Anchor.TopCentre,
- Anchor = Anchor.TopCentre,
- Width = 200,
- BackgroundColour = colours.Red3,
- Text = UsersStrings.ReportActionsSend,
- Action = () =>
- {
- Action?.Invoke(reasonDropdown.Current.Value, commentsTextBox.Text);
- this.HidePopover();
- },
- Margin = new MarginPadding { Bottom = 5, Top = 10 },
- }
- }
- };
-
- commentsTextBox.Current.BindValueChanged(e =>
- {
- submitButton.Enabled.Value = !string.IsNullOrWhiteSpace(e.NewValue);
- }, true);
}
}
}
From 1b2c821346da690e932b4d74fda4ac9307d99bb3 Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Wed, 21 Dec 2022 15:44:02 +0900
Subject: [PATCH 0045/1400] showpopover directly
---
.../Visual/Online/TestSceneChatOverlay.cs | 15 ++-------------
1 file changed, 2 insertions(+), 13 deletions(-)
diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs
index 44d739a6e3..3a6cbdfb0f 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs
@@ -12,6 +12,7 @@ using JetBrains.Annotations;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
+using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input;
@@ -544,19 +545,7 @@ namespace osu.Game.Tests.Visual.Online
AddAssert("Overlay is visible", () => chatOverlay.State.Value == Visibility.Visible);
waitForChannel1Visible();
- AddStep("Right click username", () =>
- {
- var username = this.ChildrenOfType().First();
- InputManager.MoveMouseTo(username);
- InputManager.Click(MouseButton.Right);
- });
-
- AddStep("Click report", () =>
- {
- var btn = this.ChildrenOfType().First(x => x.Text == "Report");
- InputManager.MoveMouseTo(btn);
- InputManager.Click(MouseButton.Left);
- });
+ AddStep("Show report popover", () => this.ChildrenOfType().First().ShowPopover());
AddStep("Try to report", () =>
{
From bbb22479a8aefd1b040d236dde395c0220ed4bc4 Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Sun, 25 Dec 2022 21:32:47 +0100
Subject: [PATCH 0046/1400] Add "ModBubbles" for the osu ruleset.
---
.../Mods/TestSceneOsuModBubbles.cs | 19 ++
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 228 ++++++++++++++++++
osu.Game.Rulesets.Osu/OsuRuleset.cs | 3 +-
osu.Game/Rulesets/Mods/ModFlashlight.cs | 3 +
4 files changed, 252 insertions(+), 1 deletion(-)
create mode 100644 osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModBubbles.cs
create mode 100644 osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModBubbles.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModBubbles.cs
new file mode 100644
index 0000000000..e72a1f79f5
--- /dev/null
+++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModBubbles.cs
@@ -0,0 +1,19 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using NUnit.Framework;
+using osu.Game.Rulesets.Osu.Mods;
+
+namespace osu.Game.Rulesets.Osu.Tests.Mods
+{
+ public partial class TestSceneOsuModBubbles : OsuModTestScene
+ {
+ [Test]
+ public void TestOsuModBubbles() => CreateModTest(new ModTestData
+ {
+ Mod = new OsuModBubbles(),
+ Autoplay = true,
+ PassCondition = () => true
+ });
+ }
+}
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
new file mode 100644
index 0000000000..c51ebde383
--- /dev/null
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -0,0 +1,228 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Linq;
+using osu.Framework.Allocation;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Effects;
+using osu.Framework.Graphics.Performance;
+using osu.Framework.Graphics.Pooling;
+using osu.Framework.Graphics.Shapes;
+using osu.Framework.Localisation;
+using osu.Game.Rulesets.Mods;
+using osu.Game.Rulesets.Objects.Drawables;
+using osu.Game.Rulesets.Objects.Pooling;
+using osu.Game.Rulesets.Osu.Objects;
+using osu.Game.Rulesets.Osu.Objects.Drawables;
+using osu.Game.Rulesets.Scoring;
+using osu.Game.Rulesets.UI;
+using osu.Game.Scoring;
+using osuTK;
+
+namespace osu.Game.Rulesets.Osu.Mods
+{
+ public partial class OsuModBubbles : ModWithVisibilityAdjustment, IApplicableToDrawableRuleset, IApplicableToScoreProcessor
+ {
+ public override string Name => "Bubbles";
+
+ public override string Acronym => "BB";
+
+ public override LocalisableString Description => "Dont let their popping distract you!";
+
+ public override double ScoreMultiplier => 1;
+
+ public override ModType Type => ModType.Fun;
+
+ // Compatibility with these seems potentially feasible in the future, blocked for now because they dont work as one would expect
+ public override Type[] IncompatibleMods => new[] { typeof(OsuModBarrelRoll), typeof(OsuModMagnetised), typeof(OsuModRepel) };
+
+ private PlayfieldAdjustmentContainer adjustmentContainer = null!;
+ private BubbleContainer bubbleContainer = null!;
+
+ private readonly Bindable currentCombo = new BindableInt();
+
+ private float maxSize;
+ private float bubbleRadius;
+ private double bubbleFade;
+
+ public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank;
+
+ public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor)
+ {
+ currentCombo.BindTo(scoreProcessor.Combo);
+ currentCombo.BindValueChanged(combo =>
+ maxSize = Math.Min(1.75f, (float)(1.25 + 0.005 * combo.NewValue)), true);
+ }
+
+ public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset)
+ {
+ // Multiplying by 2 results in an initial size that is too large, hence 1.85 has been chosen
+ bubbleRadius = (float)(drawableRuleset.Beatmap.HitObjects.OfType().First().Radius * 1.85f);
+ bubbleFade = drawableRuleset.Beatmap.HitObjects.OfType().First().TimeFadeIn * 2;
+
+ // We want to hide the judgements since they are obscured by the BubbleDrawable (due to layering)
+ drawableRuleset.Playfield.DisplayJudgements.Value = false;
+
+ adjustmentContainer = drawableRuleset.CreatePlayfieldAdjustmentContainer();
+
+ adjustmentContainer.Add(bubbleContainer = new BubbleContainer());
+ drawableRuleset.KeyBindingInputManager.Add(adjustmentContainer);
+ }
+
+ protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state) => applyBubbleState(hitObject);
+
+ protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject, ArmedState state) => applyBubbleState(hitObject);
+
+ private void applyBubbleState(DrawableHitObject drawableObject)
+ {
+ if (drawableObject is not DrawableOsuHitObject drawableOsuObject || !drawableObject.Judged) return;
+
+ OsuHitObject hitObject = drawableOsuObject.HitObject;
+
+ switch (drawableOsuObject)
+ {
+ //Needs to be done explicitly to avoid being handled by DrawableHitCircle below
+ case DrawableSliderHead:
+ addBubbleContainer(hitObject.Position);
+ break;
+
+ //Stack leniency causes placement issues if this isn't handled as such.
+ case DrawableHitCircle hitCircle:
+ addBubbleContainer(hitCircle.Position);
+ break;
+
+ case DrawableSpinnerTick:
+ case DrawableSlider:
+ return;
+
+ default:
+ addBubbleContainer(hitObject.Position);
+ break;
+ }
+
+ void addBubbleContainer(Vector2 position) => bubbleContainer.Add(new BubbleLifeTimeEntry
+ {
+ LifetimeStart = bubbleContainer.Time.Current,
+ Colour = drawableOsuObject.AccentColour.Value,
+ Position = position,
+ InitialSize = new Vector2(bubbleRadius),
+ MaxSize = maxSize,
+ FadeTime = bubbleFade,
+ IsHit = drawableOsuObject.IsHit
+ }
+ );
+ }
+
+ #region Pooled Bubble drawable
+
+ //LifetimeEntry flow is necessary to allow for correct rewind behaviour, can probably be made generic later if more mods are made requiring it
+ //Todo: find solution to bubbles rewinding in "groups"
+ private sealed partial class BubbleContainer : PooledDrawableWithLifetimeContainer
+ {
+ protected override bool RemoveRewoundEntry => true;
+
+ private readonly DrawablePool pool;
+
+ public BubbleContainer()
+ {
+ RelativeSizeAxes = Axes.Both;
+ AddInternal(pool = new DrawablePool(10, 1000));
+ }
+
+ protected override BubbleObject GetDrawable(BubbleLifeTimeEntry entry) => pool.Get(d => d.Apply(entry));
+ }
+
+ private sealed partial class BubbleObject : PoolableDrawableWithLifetime
+ {
+ private readonly BubbleDrawable bubbleDrawable;
+
+ public BubbleObject()
+ {
+ InternalChild = bubbleDrawable = new BubbleDrawable();
+ }
+
+ protected override void OnApply(BubbleLifeTimeEntry entry)
+ {
+ base.OnApply(entry);
+ if (IsLoaded)
+ apply(entry);
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+ apply(Entry);
+ }
+
+ private void apply(BubbleLifeTimeEntry? entry)
+ {
+ if (entry == null)
+ return;
+
+ ApplyTransformsAt(float.MinValue, true);
+ ClearTransforms(true);
+
+ Position = entry.Position;
+
+ bubbleDrawable.Animate(entry);
+
+ LifetimeEnd = bubbleDrawable.LatestTransformEndTime;
+ }
+ }
+
+ private partial class BubbleDrawable : CompositeDrawable
+ {
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ InternalChild = new Circle
+ {
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.Both,
+ Masking = true,
+ EdgeEffect = new EdgeEffectParameters
+ {
+ Colour = Colour4.Black.Opacity(0.05f),
+ Type = EdgeEffectType.Shadow,
+ Radius = 5
+ }
+ };
+ }
+
+ public void Animate(BubbleLifeTimeEntry entry)
+ {
+ Size = entry.InitialSize;
+ this
+ .ScaleTo(entry.MaxSize, entry.FadeTime * 6, Easing.OutSine)
+ .FadeColour(entry.IsHit ? entry.Colour : Colour4.Black, entry.FadeTime, Easing.OutSine)
+ .Delay(entry.FadeTime)
+ .FadeColour(entry.IsHit ? entry.Colour.Darken(.4f) : Colour4.Black, entry.FadeTime * 5, Easing.OutSine)
+ .Then()
+ .ScaleTo(entry.MaxSize * 1.5f, entry.FadeTime, Easing.OutSine)
+ .FadeTo(0, entry.FadeTime, Easing.OutQuint);
+ }
+ }
+
+ private class BubbleLifeTimeEntry : LifetimeEntry
+ {
+ public Vector2 InitialSize { get; set; }
+
+ public float MaxSize { get; set; }
+
+ public Vector2 Position { get; set; }
+
+ public Colour4 Colour { get; set; }
+
+ // FadeTime is based on the approach rate of the beatmap.
+ public double FadeTime { get; set; }
+
+ // Whether the corresponding HitObject was hit
+ public bool IsHit { get; set; }
+ }
+
+ #endregion
+ }
+}
diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs
index 79a566e33c..0df1e4dfca 100644
--- a/osu.Game.Rulesets.Osu/OsuRuleset.cs
+++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs
@@ -202,7 +202,8 @@ namespace osu.Game.Rulesets.Osu
new OsuModNoScope(),
new MultiMod(new OsuModMagnetised(), new OsuModRepel()),
new ModAdaptiveSpeed(),
- new OsuModFreezeFrame()
+ new OsuModFreezeFrame(),
+ new OsuModBubbles()
};
case ModType.System:
diff --git a/osu.Game/Rulesets/Mods/ModFlashlight.cs b/osu.Game/Rulesets/Mods/ModFlashlight.cs
index 45fa55c7f2..2c9ef357b5 100644
--- a/osu.Game/Rulesets/Mods/ModFlashlight.cs
+++ b/osu.Game/Rulesets/Mods/ModFlashlight.cs
@@ -83,6 +83,9 @@ namespace osu.Game.Rulesets.Mods
flashlight.Combo.BindTo(Combo);
drawableRuleset.KeyBindingInputManager.Add(flashlight);
+
+ // Stop flashlight from being drawn underneath other mods that generate HitObjects.
+ drawableRuleset.KeyBindingInputManager.ChangeChildDepth(flashlight, -1);
}
protected abstract Flashlight CreateFlashlight();
From 8a108b143e10bf80162eb0109aad7a68ae9692fc Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Sun, 25 Dec 2022 21:33:10 +0100
Subject: [PATCH 0047/1400] Address mod incompatibilities
---
osu.Game.Rulesets.Osu/Mods/OsuModBarrelRoll.cs | 3 +++
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 17 +++++++++++------
osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs | 2 +-
osu.Game.Rulesets.Osu/Mods/OsuModRepel.cs | 2 +-
4 files changed, 16 insertions(+), 8 deletions(-)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBarrelRoll.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBarrelRoll.cs
index 9e71f657ce..2394cf92fc 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBarrelRoll.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBarrelRoll.cs
@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects;
@@ -10,6 +11,8 @@ namespace osu.Game.Rulesets.Osu.Mods
{
public class OsuModBarrelRoll : ModBarrelRoll, IApplicableToDrawableHitObject
{
+ public override Type[] IncompatibleMods => new[] { typeof(OsuModBubbles) };
+
public void ApplyToDrawableHitObject(DrawableHitObject d)
{
d.OnUpdate += _ =>
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index c51ebde383..2e4d574148 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -86,12 +86,12 @@ namespace osu.Game.Rulesets.Osu.Mods
{
//Needs to be done explicitly to avoid being handled by DrawableHitCircle below
case DrawableSliderHead:
- addBubbleContainer(hitObject.Position);
+ addBubbleContainer(hitObject.Position, drawableOsuObject);
break;
//Stack leniency causes placement issues if this isn't handled as such.
case DrawableHitCircle hitCircle:
- addBubbleContainer(hitCircle.Position);
+ addBubbleContainer(hitCircle.Position, drawableOsuObject);
break;
case DrawableSpinnerTick:
@@ -99,19 +99,24 @@ namespace osu.Game.Rulesets.Osu.Mods
return;
default:
- addBubbleContainer(hitObject.Position);
+ addBubbleContainer(hitObject.Position, drawableOsuObject);
break;
}
+ }
- void addBubbleContainer(Vector2 position) => bubbleContainer.Add(new BubbleLifeTimeEntry
+ private void addBubbleContainer(Vector2 position, DrawableHitObject hitObject)
+ {
+ bubbleContainer.Add
+ (
+ new BubbleLifeTimeEntry
{
LifetimeStart = bubbleContainer.Time.Current,
- Colour = drawableOsuObject.AccentColour.Value,
+ Colour = hitObject.AccentColour.Value,
Position = position,
InitialSize = new Vector2(bubbleRadius),
MaxSize = maxSize,
FadeTime = bubbleFade,
- IsHit = drawableOsuObject.IsHit
+ IsHit = hitObject.IsHit
}
);
}
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs b/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs
index 38d90eb121..c8c4cd6a14 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs
@@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Osu.Mods
public override ModType Type => ModType.Fun;
public override LocalisableString Description => "No need to chase the circles – your cursor is a magnet!";
public override double ScoreMultiplier => 0.5;
- public override Type[] IncompatibleMods => new[] { typeof(OsuModAutopilot), typeof(OsuModWiggle), typeof(OsuModTransform), typeof(ModAutoplay), typeof(OsuModRelax), typeof(OsuModRepel) };
+ public override Type[] IncompatibleMods => new[] { typeof(OsuModAutopilot), typeof(OsuModWiggle), typeof(OsuModTransform), typeof(ModAutoplay), typeof(OsuModRelax), typeof(OsuModRepel), typeof(OsuModBubbles) };
[SettingSource("Attraction strength", "How strong the pull is.", 0)]
public BindableFloat AttractionStrength { get; } = new BindableFloat(0.5f)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRepel.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRepel.cs
index 31a6b69d6b..28d459cedb 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModRepel.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModRepel.cs
@@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Osu.Mods
public override ModType Type => ModType.Fun;
public override LocalisableString Description => "Hit objects run away!";
public override double ScoreMultiplier => 1;
- public override Type[] IncompatibleMods => new[] { typeof(OsuModAutopilot), typeof(OsuModWiggle), typeof(OsuModTransform), typeof(ModAutoplay), typeof(OsuModMagnetised) };
+ public override Type[] IncompatibleMods => new[] { typeof(OsuModAutopilot), typeof(OsuModWiggle), typeof(OsuModTransform), typeof(ModAutoplay), typeof(OsuModMagnetised), typeof(OsuModBubbles) };
[SettingSource("Repulsion strength", "How strong the repulsion is.", 0)]
public BindableFloat RepulsionStrength { get; } = new BindableFloat(0.5f)
From ca84b885dcc6695cb7da3549757f7e6338bc37de Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Wed, 11 Jan 2023 17:51:41 +0100
Subject: [PATCH 0048/1400] Add more detail to bubbles
---
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 58 ++++++++++++++++-----
1 file changed, 45 insertions(+), 13 deletions(-)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index 2e4d574148..f5e7e035b2 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -12,6 +12,7 @@ using osu.Framework.Graphics.Performance;
using osu.Framework.Graphics.Pooling;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Localisation;
+using osu.Game.Graphics;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Objects.Pooling;
@@ -21,6 +22,7 @@ using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
using osu.Game.Scoring;
using osuTK;
+using osuTK.Graphics;
namespace osu.Game.Rulesets.Osu.Mods
{
@@ -178,21 +180,38 @@ namespace osu.Game.Rulesets.Osu.Mods
}
}
- private partial class BubbleDrawable : CompositeDrawable
+ private partial class BubbleDrawable : CompositeDrawable, IHasAccentColour
{
+ public Color4 AccentColour { get; set; }
+
+ private Circle outerCircle = null!;
+ private Circle innerCircle = null!;
+
[BackgroundDependencyLoader]
private void load()
{
- InternalChild = new Circle
+ InternalChildren = new Drawable[]
{
- Origin = Anchor.Centre,
- RelativeSizeAxes = Axes.Both,
- Masking = true,
- EdgeEffect = new EdgeEffectParameters
+ outerCircle = new Circle
{
- Colour = Colour4.Black.Opacity(0.05f),
- Type = EdgeEffectType.Shadow,
- Radius = 5
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.Both,
+ Masking = true,
+ MaskingSmoothness = 2,
+ BorderThickness = 0,
+ BorderColour = Colour4.Transparent,
+ EdgeEffect = new EdgeEffectParameters
+ {
+ Type = EdgeEffectType.Shadow,
+ Radius = 3,
+ Colour = Colour4.Black.Opacity(0.05f)
+ }
+ },
+ innerCircle = new Circle
+ {
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.Both,
+ Scale = new Vector2(0.5f)
}
};
}
@@ -202,12 +221,25 @@ namespace osu.Game.Rulesets.Osu.Mods
Size = entry.InitialSize;
this
.ScaleTo(entry.MaxSize, entry.FadeTime * 6, Easing.OutSine)
- .FadeColour(entry.IsHit ? entry.Colour : Colour4.Black, entry.FadeTime, Easing.OutSine)
- .Delay(entry.FadeTime)
- .FadeColour(entry.IsHit ? entry.Colour.Darken(.4f) : Colour4.Black, entry.FadeTime * 5, Easing.OutSine)
.Then()
.ScaleTo(entry.MaxSize * 1.5f, entry.FadeTime, Easing.OutSine)
- .FadeTo(0, entry.FadeTime, Easing.OutQuint);
+ .FadeTo(0, entry.FadeTime, Easing.OutExpo);
+
+ animateCircles(entry);
+ }
+
+ private void animateCircles(BubbleLifeTimeEntry entry)
+ {
+ innerCircle.FadeColour(entry.IsHit ? entry.Colour.Darken(0.2f) : Colour4.Black)
+ .FadeColour(entry.IsHit ? entry.Colour.Lighten(0.2f) : Colour4.Black, entry.FadeTime * 7);
+
+ innerCircle.FadeTo(0.5f, entry.FadeTime * 7, Easing.InExpo)
+ .ScaleTo(1.1f, entry.FadeTime * 7, Easing.InSine);
+
+ outerCircle
+ .FadeColour(entry.IsHit ? entry.Colour : Colour4.Black, entry.FadeTime, Easing.OutSine)
+ .Delay(entry.FadeTime)
+ .FadeColour(entry.IsHit ? entry.Colour.Darken(.4f) : Colour4.Black, entry.FadeTime * 5, Easing.OutSine);
}
}
From ff5a12fcb4be833fdeb21b406b2ec9e19f88f8ff Mon Sep 17 00:00:00 2001
From: ansel <79257300125@ya.ru>
Date: Mon, 16 Jan 2023 20:39:38 +0300
Subject: [PATCH 0049/1400] Localise login form
---
osu.Game/Localisation/LoginPanelStrings.cs | 54 ++++++++++++++++++++++
osu.Game/Overlays/Login/LoginForm.cs | 13 +++---
osu.Game/Overlays/Login/LoginPanel.cs | 7 +--
osu.Game/Overlays/Login/UserAction.cs | 10 ++--
4 files changed, 69 insertions(+), 15 deletions(-)
create mode 100644 osu.Game/Localisation/LoginPanelStrings.cs
diff --git a/osu.Game/Localisation/LoginPanelStrings.cs b/osu.Game/Localisation/LoginPanelStrings.cs
new file mode 100644
index 0000000000..6dfb48fbdc
--- /dev/null
+++ b/osu.Game/Localisation/LoginPanelStrings.cs
@@ -0,0 +1,54 @@
+// Copyright (c) ppy Pty Ltd . 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 LoginPanelStrings
+ {
+ private const string prefix = @"osu.Game.Resources.Localisation.LoginPanel";
+
+ ///
+ /// "Do not disturb"
+ ///
+ public static LocalisableString DoNotDisturb => new TranslatableString(getKey(@"do_not_disturb"), @"Do not disturb");
+
+ ///
+ /// "Appear offline"
+ ///
+ public static LocalisableString AppearOffline => new TranslatableString(getKey(@"appear_offline"), @"Appear offline");
+
+ ///
+ /// "Sign out"
+ ///
+ public static LocalisableString SignOut => new TranslatableString(getKey(@"sign_out"), @"Sign out");
+
+ ///
+ /// "Signed in"
+ ///
+ public static LocalisableString SignedIn => new TranslatableString(getKey(@"signed_in"), @"Signed in");
+
+ ///
+ /// "ACCOUNT"
+ ///
+ public static LocalisableString Account => new TranslatableString(getKey(@"account"), @"ACCOUNT");
+
+ ///
+ /// "Remember username"
+ ///
+ public static LocalisableString RememberUsername => new TranslatableString(getKey(@"remember_username"), @"Remember username");
+
+ ///
+ /// "Stay signed in"
+ ///
+ public static LocalisableString StaySignedIn => new TranslatableString(getKey(@"stay_signed_in"), @"Stay signed in");
+
+ ///
+ /// "Register"
+ ///
+ public static LocalisableString Register => new TranslatableString(getKey(@"register"), @"Register");
+
+ private static string getKey(string key) => $@"{prefix}:{key}";
+ }
+}
diff --git a/osu.Game/Overlays/Login/LoginForm.cs b/osu.Game/Overlays/Login/LoginForm.cs
index af145c418c..9f9b8d9342 100644
--- a/osu.Game/Overlays/Login/LoginForm.cs
+++ b/osu.Game/Overlays/Login/LoginForm.cs
@@ -16,6 +16,7 @@ using osu.Game.Online.API;
using osu.Game.Overlays.Settings;
using osu.Game.Resources.Localisation.Web;
using osuTK;
+using osu.Game.Localisation;
namespace osu.Game.Overlays.Login
{
@@ -47,7 +48,7 @@ namespace osu.Game.Overlays.Login
RelativeSizeAxes = Axes.X;
ErrorTextFlowContainer errorText;
- LinkFlowContainer forgottenPaswordLink;
+ LinkFlowContainer forgottenPasswordLink;
Children = new Drawable[]
{
@@ -71,15 +72,15 @@ namespace osu.Game.Overlays.Login
},
new SettingsCheckbox
{
- LabelText = "Remember username",
+ LabelText = LoginPanelStrings.RememberUsername,
Current = config.GetBindable(OsuSetting.SaveUsername),
},
new SettingsCheckbox
{
- LabelText = "Stay signed in",
+ LabelText = LoginPanelStrings.StaySignedIn,
Current = config.GetBindable(OsuSetting.SavePassword),
},
- forgottenPaswordLink = new LinkFlowContainer
+ forgottenPasswordLink = new LinkFlowContainer
{
Padding = new MarginPadding { Left = SettingsPanel.CONTENT_MARGINS },
RelativeSizeAxes = Axes.X,
@@ -105,7 +106,7 @@ namespace osu.Game.Overlays.Login
},
new SettingsButton
{
- Text = "Register",
+ Text = LoginPanelStrings.Register,
Action = () =>
{
RequestHide?.Invoke();
@@ -114,7 +115,7 @@ namespace osu.Game.Overlays.Login
}
};
- forgottenPaswordLink.AddLink(LayoutStrings.PopupLoginLoginForgot, $"{api.WebsiteRootUrl}/home/password-reset");
+ forgottenPasswordLink.AddLink(LayoutStrings.PopupLoginLoginForgot, $"{api.WebsiteRootUrl}/home/password-reset");
password.OnCommit += (_, _) => performLogin();
diff --git a/osu.Game/Overlays/Login/LoginPanel.cs b/osu.Game/Overlays/Login/LoginPanel.cs
index 44f2f3273a..fb9987bd82 100644
--- a/osu.Game/Overlays/Login/LoginPanel.cs
+++ b/osu.Game/Overlays/Login/LoginPanel.cs
@@ -6,6 +6,7 @@
using System;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
+using osu.Framework.Extensions.LocalisationExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Events;
@@ -81,7 +82,7 @@ namespace osu.Game.Overlays.Login
{
new OsuSpriteText
{
- Text = "ACCOUNT",
+ Text = LoginPanelStrings.Account,
Margin = new MarginPadding { Bottom = 5 },
Font = OsuFont.GetFont(weight: FontWeight.Bold),
},
@@ -115,7 +116,7 @@ namespace osu.Game.Overlays.Login
},
};
- linkFlow.AddLink("cancel", api.Logout, string.Empty);
+ linkFlow.AddLink(Resources.Localisation.Web.CommonStrings.ButtonsCancel.ToLower(), api.Logout, string.Empty);
break;
case APIState.Online:
@@ -140,7 +141,7 @@ namespace osu.Game.Overlays.Login
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
- Text = "Signed in",
+ Text = LoginPanelStrings.SignedIn,
Font = OsuFont.GetFont(size: 18, weight: FontWeight.Bold),
Margin = new MarginPadding { Top = 5, Bottom = 5 },
},
diff --git a/osu.Game/Overlays/Login/UserAction.cs b/osu.Game/Overlays/Login/UserAction.cs
index 7a18e38109..813968a053 100644
--- a/osu.Game/Overlays/Login/UserAction.cs
+++ b/osu.Game/Overlays/Login/UserAction.cs
@@ -1,11 +1,9 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
-using System.ComponentModel;
using osu.Framework.Localisation;
using osu.Game.Resources.Localisation.Web;
+using osu.Game.Localisation;
namespace osu.Game.Overlays.Login
{
@@ -14,13 +12,13 @@ namespace osu.Game.Overlays.Login
[LocalisableDescription(typeof(UsersStrings), nameof(UsersStrings.StatusOnline))]
Online,
- [Description(@"Do not disturb")]
+ [LocalisableDescription(typeof(LoginPanelStrings), nameof(LoginPanelStrings.DoNotDisturb))]
DoNotDisturb,
- [Description(@"Appear offline")]
+ [LocalisableDescription(typeof(LoginPanelStrings), nameof(LoginPanelStrings.AppearOffline))]
AppearOffline,
- [Description(@"Sign out")]
+ [LocalisableDescription(typeof(LoginPanelStrings), nameof(LoginPanelStrings.SignOut))]
SignOut,
}
}
From 4c341db33f12a05a1ec6e4abbf60fd4294b0a70d Mon Sep 17 00:00:00 2001
From: ansel <79257300125@ya.ru>
Date: Mon, 16 Jan 2023 21:31:01 +0300
Subject: [PATCH 0050/1400] Localise registration window
---
.../Localisation/AccountCreationStrings.cs | 77 +++++++++++++++++++
.../Overlays/AccountCreation/ScreenEntry.cs | 19 ++---
.../Overlays/AccountCreation/ScreenWarning.cs | 5 +-
.../Overlays/AccountCreation/ScreenWelcome.cs | 9 +--
4 files changed, 94 insertions(+), 16 deletions(-)
create mode 100644 osu.Game/Localisation/AccountCreationStrings.cs
diff --git a/osu.Game/Localisation/AccountCreationStrings.cs b/osu.Game/Localisation/AccountCreationStrings.cs
new file mode 100644
index 0000000000..4e702ea7cc
--- /dev/null
+++ b/osu.Game/Localisation/AccountCreationStrings.cs
@@ -0,0 +1,77 @@
+// Copyright (c) ppy Pty Ltd . 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 AccountCreationStrings
+ {
+ private const string prefix = @"osu.Game.Resources.Localisation.AccountCreation";
+
+ ///
+ /// "New Player Registration"
+ ///
+ public static LocalisableString NewPlayerRegistration => new TranslatableString(getKey(@"new_player_registration"), @"New Player Registration");
+
+ ///
+ /// "let's get you started"
+ ///
+ public static LocalisableString LetsGetYouStarted => new TranslatableString(getKey(@"lets_get_you_started"), @"let's get you started");
+
+ ///
+ /// "Let's create an account!"
+ ///
+ public static LocalisableString LetsCreateAnAccount => new TranslatableString(getKey(@"lets_create_an_account"), @"Let's create an account!");
+
+ ///
+ /// "Help, I can't access my account!"
+ ///
+ public static LocalisableString HelpICantAccess => new TranslatableString(getKey(@"help_icant_access"), @"Help, I can't access my account!");
+
+ ///
+ /// "I understand. This account isn't for me."
+ ///
+ public static LocalisableString AccountIsntForMe => new TranslatableString(getKey(@"account_isnt_for_me"), @"I understand. This account isn't for me.");
+
+ ///
+ /// "email address"
+ ///
+ public static LocalisableString EmailAddress => new TranslatableString(getKey(@"email_address"), @"email address");
+
+ ///
+ /// "This will be your public presence. No profanity, no impersonation. Avoid exposing your own personal details, too!"
+ ///
+ public static LocalisableString ThisWillBeYourPublic => new TranslatableString(getKey(@"this_will_be_your_public"),
+ @"This will be your public presence. No profanity, no impersonation. Avoid exposing your own personal details, too!");
+
+ ///
+ /// "Will be used for notifications, account verification and in the case you forget your password. No spam, ever."
+ ///
+ public static LocalisableString EmailUsage =>
+ new TranslatableString(getKey(@"email_usage"), @"Will be used for notifications, account verification and in the case you forget your password. No spam, ever.");
+
+ ///
+ /// " Make sure to get it right!"
+ ///
+ public static LocalisableString MakeSureToGetIt => new TranslatableString(getKey(@"make_sure_to_get_it"), @" Make sure to get it right!");
+
+ ///
+ /// "At least "
+ ///
+ public static LocalisableString BeforeCharactersLong => new TranslatableString(getKey(@"before_characters_long"), @"At least ");
+
+ ///
+ /// "8 characters long"
+ ///
+ public static LocalisableString CharactersLong => new TranslatableString(getKey(@"characters_long"), @"8 characters long");
+
+ ///
+ /// ". Choose something long but also something you will remember, like a line from your favourite song."
+ ///
+ public static LocalisableString AfterCharactersLong =>
+ new TranslatableString(getKey(@"after_characters_long"), @". Choose something long but also something you will remember, like a line from your favourite song.");
+
+ private static string getKey(string key) => $@"{prefix}:{key}";
+ }
+}
diff --git a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs
index 2e20f83e9e..6718b72805 100644
--- a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs
+++ b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs
@@ -17,6 +17,7 @@ using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
+using osu.Game.Localisation;
using osu.Game.Online.API;
using osu.Game.Overlays.Settings;
using osu.Game.Resources.Localisation.Web;
@@ -71,7 +72,7 @@ namespace osu.Game.Overlays.AccountCreation
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Font = OsuFont.GetFont(size: 20),
- Text = "Let's create an account!",
+ Text = AccountCreationStrings.LetsCreateAnAccount
},
usernameTextBox = new OsuTextBox
{
@@ -86,7 +87,7 @@ namespace osu.Game.Overlays.AccountCreation
},
emailTextBox = new OsuTextBox
{
- PlaceholderText = "email address",
+ PlaceholderText = AccountCreationStrings.EmailAddress,
RelativeSizeAxes = Axes.X,
TabbableContentContainer = this
},
@@ -118,7 +119,7 @@ namespace osu.Game.Overlays.AccountCreation
AutoSizeAxes = Axes.Y,
Child = new SettingsButton
{
- Text = "Register",
+ Text = LoginPanelStrings.Register,
Margin = new MarginPadding { Vertical = 20 },
Action = performRegistration
}
@@ -132,14 +133,14 @@ namespace osu.Game.Overlays.AccountCreation
textboxes = new[] { usernameTextBox, emailTextBox, passwordTextBox };
- usernameDescription.AddText("This will be your public presence. No profanity, no impersonation. Avoid exposing your own personal details, too!");
+ usernameDescription.AddText(AccountCreationStrings.ThisWillBeYourPublic);
- emailAddressDescription.AddText("Will be used for notifications, account verification and in the case you forget your password. No spam, ever.");
- emailAddressDescription.AddText(" Make sure to get it right!", cp => cp.Font = cp.Font.With(Typeface.Torus, weight: FontWeight.Bold));
+ emailAddressDescription.AddText(AccountCreationStrings.EmailUsage);
+ emailAddressDescription.AddText(AccountCreationStrings.MakeSureToGetIt, cp => cp.Font = cp.Font.With(Typeface.Torus, weight: FontWeight.Bold));
- passwordDescription.AddText("At least ");
- characterCheckText = passwordDescription.AddText("8 characters long");
- passwordDescription.AddText(". Choose something long but also something you will remember, like a line from your favourite song.");
+ passwordDescription.AddText(AccountCreationStrings.BeforeCharactersLong);
+ characterCheckText = passwordDescription.AddText(AccountCreationStrings.CharactersLong);
+ passwordDescription.AddText(AccountCreationStrings.AfterCharactersLong);
passwordTextBox.Current.BindValueChanged(_ => updateCharacterCheckTextColour(), true);
characterCheckText.DrawablePartsRecreated += _ => updateCharacterCheckTextColour();
diff --git a/osu.Game/Overlays/AccountCreation/ScreenWarning.cs b/osu.Game/Overlays/AccountCreation/ScreenWarning.cs
index a833a871f9..f5807b49b5 100644
--- a/osu.Game/Overlays/AccountCreation/ScreenWarning.cs
+++ b/osu.Game/Overlays/AccountCreation/ScreenWarning.cs
@@ -17,6 +17,7 @@ using osu.Game.Overlays.Settings;
using osu.Game.Screens.Menu;
using osuTK;
using osuTK.Graphics;
+using osu.Game.Localisation;
namespace osu.Game.Overlays.AccountCreation
{
@@ -101,13 +102,13 @@ namespace osu.Game.Overlays.AccountCreation
},
new SettingsButton
{
- Text = "Help, I can't access my account!",
+ Text = AccountCreationStrings.HelpICantAccess,
Margin = new MarginPadding { Top = 50 },
Action = () => game?.OpenUrlExternally(help_centre_url)
},
new DangerousSettingsButton
{
- Text = "I understand. This account isn't for me.",
+ Text = AccountCreationStrings.AccountIsntForMe,
Action = () => this.Push(new ScreenEntry())
},
furtherAssistance = new LinkFlowContainer(cp => cp.Font = cp.Font.With(size: 12))
diff --git a/osu.Game/Overlays/AccountCreation/ScreenWelcome.cs b/osu.Game/Overlays/AccountCreation/ScreenWelcome.cs
index 4becb225f8..a81b1019fe 100644
--- a/osu.Game/Overlays/AccountCreation/ScreenWelcome.cs
+++ b/osu.Game/Overlays/AccountCreation/ScreenWelcome.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@@ -12,6 +10,7 @@ using osu.Game.Graphics.Sprites;
using osu.Game.Overlays.Settings;
using osu.Game.Screens.Menu;
using osuTK;
+using osu.Game.Localisation;
namespace osu.Game.Overlays.AccountCreation
{
@@ -46,18 +45,18 @@ namespace osu.Game.Overlays.AccountCreation
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Font = OsuFont.GetFont(size: 24, weight: FontWeight.Light),
- Text = "New Player Registration",
+ Text = AccountCreationStrings.NewPlayerRegistration,
},
new OsuSpriteText
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Font = OsuFont.GetFont(size: 12),
- Text = "let's get you started",
+ Text = AccountCreationStrings.LetsGetYouStarted,
},
new SettingsButton
{
- Text = "Let's create an account!",
+ Text = AccountCreationStrings.LetsCreateAnAccount,
Margin = new MarginPadding { Vertical = 120 },
Action = () => this.Push(new ScreenWarning())
}
From bb3668c76901f5d2109697748b91627fdcb54878 Mon Sep 17 00:00:00 2001
From: ansel <79257300125@ya.ru>
Date: Mon, 16 Jan 2023 22:24:03 +0300
Subject: [PATCH 0051/1400] Reuse existing
---
osu.Game/Localisation/AccountCreationStrings.cs | 5 -----
osu.Game/Localisation/LoginPanelStrings.cs | 5 -----
osu.Game/Overlays/AccountCreation/ScreenEntry.cs | 2 +-
osu.Game/Overlays/Login/UserAction.cs | 2 +-
4 files changed, 2 insertions(+), 12 deletions(-)
diff --git a/osu.Game/Localisation/AccountCreationStrings.cs b/osu.Game/Localisation/AccountCreationStrings.cs
index 4e702ea7cc..0b27944a61 100644
--- a/osu.Game/Localisation/AccountCreationStrings.cs
+++ b/osu.Game/Localisation/AccountCreationStrings.cs
@@ -34,11 +34,6 @@ namespace osu.Game.Localisation
///
public static LocalisableString AccountIsntForMe => new TranslatableString(getKey(@"account_isnt_for_me"), @"I understand. This account isn't for me.");
- ///
- /// "email address"
- ///
- public static LocalisableString EmailAddress => new TranslatableString(getKey(@"email_address"), @"email address");
-
///
/// "This will be your public presence. No profanity, no impersonation. Avoid exposing your own personal details, too!"
///
diff --git a/osu.Game/Localisation/LoginPanelStrings.cs b/osu.Game/Localisation/LoginPanelStrings.cs
index 6dfb48fbdc..535d86fbc5 100644
--- a/osu.Game/Localisation/LoginPanelStrings.cs
+++ b/osu.Game/Localisation/LoginPanelStrings.cs
@@ -19,11 +19,6 @@ namespace osu.Game.Localisation
///
public static LocalisableString AppearOffline => new TranslatableString(getKey(@"appear_offline"), @"Appear offline");
- ///
- /// "Sign out"
- ///
- public static LocalisableString SignOut => new TranslatableString(getKey(@"sign_out"), @"Sign out");
-
///
/// "Signed in"
///
diff --git a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs
index 6718b72805..fc450c7a91 100644
--- a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs
+++ b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs
@@ -87,7 +87,7 @@ namespace osu.Game.Overlays.AccountCreation
},
emailTextBox = new OsuTextBox
{
- PlaceholderText = AccountCreationStrings.EmailAddress,
+ PlaceholderText = ModelValidationStrings.UserAttributesUserEmail.ToLower(),
RelativeSizeAxes = Axes.X,
TabbableContentContainer = this
},
diff --git a/osu.Game/Overlays/Login/UserAction.cs b/osu.Game/Overlays/Login/UserAction.cs
index 813968a053..d4d639f2fb 100644
--- a/osu.Game/Overlays/Login/UserAction.cs
+++ b/osu.Game/Overlays/Login/UserAction.cs
@@ -18,7 +18,7 @@ namespace osu.Game.Overlays.Login
[LocalisableDescription(typeof(LoginPanelStrings), nameof(LoginPanelStrings.AppearOffline))]
AppearOffline,
- [LocalisableDescription(typeof(LoginPanelStrings), nameof(LoginPanelStrings.SignOut))]
+ [LocalisableDescription(typeof(UserVerificationStrings), nameof(UserVerificationStrings.BoxInfoLogoutLink))]
SignOut,
}
}
From ad32d99daabe400402e59d4046de6de1e95a1d43 Mon Sep 17 00:00:00 2001
From: ansel <79257300125@ya.ru>
Date: Mon, 16 Jan 2023 23:08:29 +0300
Subject: [PATCH 0052/1400] Localise caps lock warning
---
osu.Game/Graphics/UserInterface/OsuPasswordTextBox.cs | 3 ++-
osu.Game/Localisation/CommonStrings.cs | 7 ++++++-
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/osu.Game/Graphics/UserInterface/OsuPasswordTextBox.cs b/osu.Game/Graphics/UserInterface/OsuPasswordTextBox.cs
index 63c98d7838..9de9eceb07 100644
--- a/osu.Game/Graphics/UserInterface/OsuPasswordTextBox.cs
+++ b/osu.Game/Graphics/UserInterface/OsuPasswordTextBox.cs
@@ -16,6 +16,7 @@ using osu.Framework.Input;
using osu.Framework.Input.Events;
using osu.Framework.Localisation;
using osu.Framework.Platform;
+using osu.Game.Localisation;
namespace osu.Game.Graphics.UserInterface
{
@@ -112,7 +113,7 @@ namespace osu.Game.Graphics.UserInterface
private partial class CapsWarning : SpriteIcon, IHasTooltip
{
- public LocalisableString TooltipText => "caps lock is active";
+ public LocalisableString TooltipText => CommonStrings.CapsLockIsActive;
public CapsWarning()
{
diff --git a/osu.Game/Localisation/CommonStrings.cs b/osu.Game/Localisation/CommonStrings.cs
index 10178915a2..a68f08efcc 100644
--- a/osu.Game/Localisation/CommonStrings.cs
+++ b/osu.Game/Localisation/CommonStrings.cs
@@ -154,6 +154,11 @@ namespace osu.Game.Localisation
///
public static LocalisableString Exit => new TranslatableString(getKey(@"exit"), @"Exit");
+ ///
+ /// "caps lock is active"
+ ///
+ public static LocalisableString CapsLockIsActive => new TranslatableString(getKey(@"caps_lock_is_active"), @"caps lock is active");
+
private static string getKey(string key) => $@"{prefix}:{key}";
}
-}
+}
\ No newline at end of file
From df74bccaaa7345e2b016516b799e85dc790a184c Mon Sep 17 00:00:00 2001
From: ansel <79257300125@ya.ru>
Date: Tue, 17 Jan 2023 13:31:03 +0300
Subject: [PATCH 0053/1400] Replace 2 strings with one formattable
---
osu.Game/Localisation/AccountCreationStrings.cs | 11 +++--------
osu.Game/Overlays/AccountCreation/ScreenEntry.cs | 10 +++++++---
2 files changed, 10 insertions(+), 11 deletions(-)
diff --git a/osu.Game/Localisation/AccountCreationStrings.cs b/osu.Game/Localisation/AccountCreationStrings.cs
index 0b27944a61..6acfaaa9ac 100644
--- a/osu.Game/Localisation/AccountCreationStrings.cs
+++ b/osu.Game/Localisation/AccountCreationStrings.cs
@@ -52,21 +52,16 @@ namespace osu.Game.Localisation
public static LocalisableString MakeSureToGetIt => new TranslatableString(getKey(@"make_sure_to_get_it"), @" Make sure to get it right!");
///
- /// "At least "
+ /// "At least {0}. Choose something long but also something you will remember, like a line from your favourite song."
///
- public static LocalisableString BeforeCharactersLong => new TranslatableString(getKey(@"before_characters_long"), @"At least ");
+ public static LocalisableString PasswordRequirements(string arg0) => new TranslatableString(getKey(@"password_requirements"),
+ @"At least {0}. Choose something long but also something you will remember, like a line from your favourite song.", arg0);
///
/// "8 characters long"
///
public static LocalisableString CharactersLong => new TranslatableString(getKey(@"characters_long"), @"8 characters long");
- ///
- /// ". Choose something long but also something you will remember, like a line from your favourite song."
- ///
- public static LocalisableString AfterCharactersLong =>
- new TranslatableString(getKey(@"after_characters_long"), @". Choose something long but also something you will remember, like a line from your favourite song.");
-
private static string getKey(string key) => $@"{prefix}:{key}";
}
}
diff --git a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs
index fc450c7a91..192b95b963 100644
--- a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs
+++ b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs
@@ -10,6 +10,7 @@ using osu.Framework.Allocation;
using osu.Framework.Extensions.LocalisationExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
+using osu.Framework.Localisation;
using osu.Framework.Utils;
using osu.Framework.Platform;
using osu.Framework.Screens;
@@ -52,7 +53,7 @@ namespace osu.Game.Overlays.AccountCreation
private OsuGame game { get; set; }
[BackgroundDependencyLoader]
- private void load()
+ private void load(LocalisationManager localisationManager)
{
InternalChildren = new Drawable[]
{
@@ -138,9 +139,12 @@ namespace osu.Game.Overlays.AccountCreation
emailAddressDescription.AddText(AccountCreationStrings.EmailUsage);
emailAddressDescription.AddText(AccountCreationStrings.MakeSureToGetIt, cp => cp.Font = cp.Font.With(Typeface.Torus, weight: FontWeight.Bold));
- passwordDescription.AddText(AccountCreationStrings.BeforeCharactersLong);
+ string[] passwordReq = localisationManager.GetLocalisedBindableString(AccountCreationStrings.PasswordRequirements("{}")).Value.Split("{}");
+ if (passwordReq.Length != 2) passwordReq = AccountCreationStrings.PasswordRequirements("{}").ToString().Split("{}");
+
+ passwordDescription.AddText(passwordReq[0]);
characterCheckText = passwordDescription.AddText(AccountCreationStrings.CharactersLong);
- passwordDescription.AddText(AccountCreationStrings.AfterCharactersLong);
+ passwordDescription.AddText(passwordReq[1]);
passwordTextBox.Current.BindValueChanged(_ => updateCharacterCheckTextColour(), true);
characterCheckText.DrawablePartsRecreated += _ => updateCharacterCheckTextColour();
From 7c81f1e75bb40981a55f16a3544d9521280bf49c Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Fri, 27 Jan 2023 11:21:11 +0100
Subject: [PATCH 0054/1400] Remove unnecessary BDL from bubble drawable
Improve animation duration formula
---
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 85 +++++++++------------
1 file changed, 38 insertions(+), 47 deletions(-)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index f5e7e035b2..6613d84e0e 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -3,7 +3,6 @@
using System;
using System.Linq;
-using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@@ -12,7 +11,6 @@ using osu.Framework.Graphics.Performance;
using osu.Framework.Graphics.Pooling;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Localisation;
-using osu.Game.Graphics;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Objects.Pooling;
@@ -22,7 +20,6 @@ using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
using osu.Game.Scoring;
using osuTK;
-using osuTK.Graphics;
namespace osu.Game.Rulesets.Osu.Mods
{
@@ -63,7 +60,7 @@ namespace osu.Game.Rulesets.Osu.Mods
{
// Multiplying by 2 results in an initial size that is too large, hence 1.85 has been chosen
bubbleRadius = (float)(drawableRuleset.Beatmap.HitObjects.OfType().First().Radius * 1.85f);
- bubbleFade = drawableRuleset.Beatmap.HitObjects.OfType().First().TimeFadeIn * 2;
+ bubbleFade = drawableRuleset.Beatmap.HitObjects.OfType().First().TimePreempt * 2;
// We want to hide the judgements since they are obscured by the BubbleDrawable (due to layering)
drawableRuleset.Playfield.DisplayJudgements.Value = false;
@@ -125,8 +122,8 @@ namespace osu.Game.Rulesets.Osu.Mods
#region Pooled Bubble drawable
- //LifetimeEntry flow is necessary to allow for correct rewind behaviour, can probably be made generic later if more mods are made requiring it
- //Todo: find solution to bubbles rewinding in "groups"
+ // LifetimeEntry flow is necessary to allow for correct rewind behaviour, can probably be made generic later if more mods are made requiring it
+ // Todo: find solution to bubbles rewinding in "groups"
private sealed partial class BubbleContainer : PooledDrawableWithLifetimeContainer
{
protected override bool RemoveRewoundEntry => true;
@@ -166,8 +163,7 @@ namespace osu.Game.Rulesets.Osu.Mods
private void apply(BubbleLifeTimeEntry? entry)
{
- if (entry == null)
- return;
+ if (entry == null) return;
ApplyTransformsAt(float.MinValue, true);
ClearTransforms(true);
@@ -180,38 +176,36 @@ namespace osu.Game.Rulesets.Osu.Mods
}
}
- private partial class BubbleDrawable : CompositeDrawable, IHasAccentColour
+ private partial class BubbleDrawable : CircularContainer
{
- public Color4 AccentColour { get; set; }
+ private readonly Circle innerCircle;
+ private readonly Box colourBox;
- private Circle outerCircle = null!;
- private Circle innerCircle = null!;
-
- [BackgroundDependencyLoader]
- private void load()
+ public BubbleDrawable()
{
- InternalChildren = new Drawable[]
+ Anchor = Anchor.Centre;
+ Origin = Anchor.Centre;
+
+ Masking = true;
+ MaskingSmoothness = 2;
+ BorderThickness = 0;
+ BorderColour = Colour4.Transparent;
+ EdgeEffect = new EdgeEffectParameters
{
- outerCircle = new Circle
- {
- Origin = Anchor.Centre,
- RelativeSizeAxes = Axes.Both,
- Masking = true,
- MaskingSmoothness = 2,
- BorderThickness = 0,
- BorderColour = Colour4.Transparent,
- EdgeEffect = new EdgeEffectParameters
- {
- Type = EdgeEffectType.Shadow,
- Radius = 3,
- Colour = Colour4.Black.Opacity(0.05f)
- }
- },
+ Type = EdgeEffectType.Shadow,
+ Radius = 3,
+ Colour = Colour4.Black.Opacity(0.05f)
+ };
+
+ Children = new Drawable[]
+ {
+ colourBox = new Box { RelativeSizeAxes = Axes.Both, },
innerCircle = new Circle
{
+ Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
- Scale = new Vector2(0.5f)
+ Size = new Vector2(0.5f),
}
};
}
@@ -219,27 +213,24 @@ namespace osu.Game.Rulesets.Osu.Mods
public void Animate(BubbleLifeTimeEntry entry)
{
Size = entry.InitialSize;
- this
- .ScaleTo(entry.MaxSize, entry.FadeTime * 6, Easing.OutSine)
+
+ this.ScaleTo(entry.MaxSize, getAnimationTime() * 0.8f, Easing.OutSine)
.Then()
- .ScaleTo(entry.MaxSize * 1.5f, entry.FadeTime, Easing.OutSine)
- .FadeTo(0, entry.FadeTime, Easing.OutExpo);
+ .ScaleTo(entry.MaxSize * 1.5f, getAnimationTime() * 0.2f, Easing.OutSine)
+ .FadeTo(0, getAnimationTime() * 0.2f, Easing.OutExpo);
- animateCircles(entry);
- }
+ colourBox.FadeColour(entry.IsHit ? entry.Colour : Colour4.Black, getAnimationTime() * 0.1f, Easing.OutSine)
+ .Then()
+ .FadeColour(entry.IsHit ? entry.Colour.Darken(0.4f) : Colour4.Black, getAnimationTime() * 0.9f, Easing.OutSine);
- private void animateCircles(BubbleLifeTimeEntry entry)
- {
innerCircle.FadeColour(entry.IsHit ? entry.Colour.Darken(0.2f) : Colour4.Black)
- .FadeColour(entry.IsHit ? entry.Colour.Lighten(0.2f) : Colour4.Black, entry.FadeTime * 7);
+ .FadeColour(entry.IsHit ? entry.Colour.Lighten(0.2f) : Colour4.Black, getAnimationTime());
- innerCircle.FadeTo(0.5f, entry.FadeTime * 7, Easing.InExpo)
- .ScaleTo(1.1f, entry.FadeTime * 7, Easing.InSine);
+ innerCircle.FadeTo(0.5f, getAnimationTime(), Easing.InExpo)
+ .ScaleTo(2.2f, getAnimationTime(), Easing.InSine);
- outerCircle
- .FadeColour(entry.IsHit ? entry.Colour : Colour4.Black, entry.FadeTime, Easing.OutSine)
- .Delay(entry.FadeTime)
- .FadeColour(entry.IsHit ? entry.Colour.Darken(.4f) : Colour4.Black, entry.FadeTime * 5, Easing.OutSine);
+ // The absolute length of the bubble's animation, can be used in fractions for animations of partial length
+ double getAnimationTime() => 2000 + 450 / (450 / entry.FadeTime);
}
}
From c3090dea5f7bea51e2662cd82fc292d65c56d7ca Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Sat, 28 Jan 2023 00:30:30 +0100
Subject: [PATCH 0055/1400] Simplify animations
---
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 28 +++++++++++++--------
1 file changed, 17 insertions(+), 11 deletions(-)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index 6613d84e0e..479741b5b9 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -214,23 +214,29 @@ namespace osu.Game.Rulesets.Osu.Mods
{
Size = entry.InitialSize;
- this.ScaleTo(entry.MaxSize, getAnimationTime() * 0.8f, Easing.OutSine)
+ //We want to fade to a darker colour to avoid colours such as white hiding the "ripple" effect.
+ var colourDarker = entry.Colour.Darken(0.1f);
+
+ this.ScaleTo(entry.MaxSize, getAnimationDuration() * 0.8f, Easing.OutSine)
.Then()
- .ScaleTo(entry.MaxSize * 1.5f, getAnimationTime() * 0.2f, Easing.OutSine)
- .FadeTo(0, getAnimationTime() * 0.2f, Easing.OutExpo);
+ .ScaleTo(entry.MaxSize * 1.5f, getAnimationDuration() * 0.2f, Easing.OutSine)
+ .FadeTo(0, getAnimationDuration() * 0.2f, Easing.OutExpo);
- colourBox.FadeColour(entry.IsHit ? entry.Colour : Colour4.Black, getAnimationTime() * 0.1f, Easing.OutSine)
- .Then()
- .FadeColour(entry.IsHit ? entry.Colour.Darken(0.4f) : Colour4.Black, getAnimationTime() * 0.9f, Easing.OutSine);
+ innerCircle.ScaleTo(2f, getAnimationDuration() * 0.8f, Easing.OutCubic);
- innerCircle.FadeColour(entry.IsHit ? entry.Colour.Darken(0.2f) : Colour4.Black)
- .FadeColour(entry.IsHit ? entry.Colour.Lighten(0.2f) : Colour4.Black, getAnimationTime());
+ if (!entry.IsHit)
+ {
+ colourBox.Colour = Colour4.Black;
+ innerCircle.Colour = Colour4.Black;
- innerCircle.FadeTo(0.5f, getAnimationTime(), Easing.InExpo)
- .ScaleTo(2.2f, getAnimationTime(), Easing.InSine);
+ return;
+ }
+
+ colourBox.FadeColour(colourDarker, getAnimationDuration() * 0.2f, Easing.OutQuint);
+ innerCircle.FadeColour(colourDarker);
// The absolute length of the bubble's animation, can be used in fractions for animations of partial length
- double getAnimationTime() => 2000 + 450 / (450 / entry.FadeTime);
+ double getAnimationDuration() => 1700 + Math.Pow(entry.FadeTime, 1.15f);
}
}
From 66da4c0288fd63d87fa7b4ea3547da39796e74e7 Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Sat, 28 Jan 2023 17:38:24 +0100
Subject: [PATCH 0056/1400] Add colouration to the sliders to better match the
vibrancy of the mod
---
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 27 +++++++++++++++------
1 file changed, 19 insertions(+), 8 deletions(-)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index 479741b5b9..0101427f7a 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -16,6 +16,7 @@ using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Objects.Pooling;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
+using osu.Game.Rulesets.Osu.Skinning.Default;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
using osu.Game.Scoring;
@@ -77,6 +78,12 @@ namespace osu.Game.Rulesets.Osu.Mods
private void applyBubbleState(DrawableHitObject drawableObject)
{
+ if (drawableObject is DrawableSlider slider)
+ {
+ slider.Body.OnSkinChanged += () => applySliderState(slider);
+ applySliderState(slider);
+ }
+
if (drawableObject is not DrawableOsuHitObject drawableOsuObject || !drawableObject.Judged) return;
OsuHitObject hitObject = drawableOsuObject.HitObject;
@@ -93,9 +100,9 @@ namespace osu.Game.Rulesets.Osu.Mods
addBubbleContainer(hitCircle.Position, drawableOsuObject);
break;
- case DrawableSpinnerTick:
case DrawableSlider:
- return;
+ case DrawableSpinnerTick:
+ break;
default:
addBubbleContainer(hitObject.Position, drawableOsuObject);
@@ -103,6 +110,9 @@ namespace osu.Game.Rulesets.Osu.Mods
}
}
+ private void applySliderState(DrawableSlider slider) =>
+ ((PlaySliderBody)slider.Body.Drawable).BorderColour = slider.AccentColour.Value;
+
private void addBubbleContainer(Vector2 position, DrawableHitObject hitObject)
{
bubbleContainer.Add
@@ -217,12 +227,12 @@ namespace osu.Game.Rulesets.Osu.Mods
//We want to fade to a darker colour to avoid colours such as white hiding the "ripple" effect.
var colourDarker = entry.Colour.Darken(0.1f);
- this.ScaleTo(entry.MaxSize, getAnimationDuration() * 0.8f, Easing.OutSine)
+ this.ScaleTo(entry.MaxSize, getAnimationDuration() * 0.8f)
.Then()
- .ScaleTo(entry.MaxSize * 1.5f, getAnimationDuration() * 0.2f, Easing.OutSine)
- .FadeTo(0, getAnimationDuration() * 0.2f, Easing.OutExpo);
+ .ScaleTo(entry.MaxSize * 1.5f, getAnimationDuration() * 0.2f, Easing.OutQuint)
+ .FadeTo(0, getAnimationDuration() * 0.2f, Easing.OutQuint);
- innerCircle.ScaleTo(2f, getAnimationDuration() * 0.8f, Easing.OutCubic);
+ innerCircle.ScaleTo(2f, getAnimationDuration() * 0.8f, Easing.OutQuint);
if (!entry.IsHit)
{
@@ -232,11 +242,12 @@ namespace osu.Game.Rulesets.Osu.Mods
return;
}
- colourBox.FadeColour(colourDarker, getAnimationDuration() * 0.2f, Easing.OutQuint);
+ colourBox.FadeColour(colourDarker, getAnimationDuration() * 0.2f, Easing.OutQuint
+ );
innerCircle.FadeColour(colourDarker);
// The absolute length of the bubble's animation, can be used in fractions for animations of partial length
- double getAnimationDuration() => 1700 + Math.Pow(entry.FadeTime, 1.15f);
+ double getAnimationDuration() => 1700 + Math.Pow(entry.FadeTime, 1.07f);
}
}
From 3bdf83bf44e63000d2a4c23c7467a1aa24b87724 Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Sat, 28 Jan 2023 22:44:57 +0100
Subject: [PATCH 0057/1400] Redo the drawable structure of bubbledrawable to
run and look better
---
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 50 ++++++++++-----------
1 file changed, 25 insertions(+), 25 deletions(-)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index 0101427f7a..2c90bfa399 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -5,6 +5,7 @@ using System;
using System.Linq;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
+using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Performance;
@@ -93,7 +94,7 @@ namespace osu.Game.Rulesets.Osu.Mods
//Needs to be done explicitly to avoid being handled by DrawableHitCircle below
case DrawableSliderHead:
addBubbleContainer(hitObject.Position, drawableOsuObject);
- break;
+ return;
//Stack leniency causes placement issues if this isn't handled as such.
case DrawableHitCircle hitCircle:
@@ -188,7 +189,6 @@ namespace osu.Game.Rulesets.Osu.Mods
private partial class BubbleDrawable : CircularContainer
{
- private readonly Circle innerCircle;
private readonly Box colourBox;
public BubbleDrawable()
@@ -196,55 +196,55 @@ namespace osu.Game.Rulesets.Osu.Mods
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
- Masking = true;
MaskingSmoothness = 2;
BorderThickness = 0;
- BorderColour = Colour4.Transparent;
+ BorderColour = Colour4.White;
+ Masking = true;
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Shadow,
Radius = 3,
Colour = Colour4.Black.Opacity(0.05f)
};
-
- Children = new Drawable[]
- {
- colourBox = new Box { RelativeSizeAxes = Axes.Both, },
- innerCircle = new Circle
- {
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- RelativeSizeAxes = Axes.Both,
- Size = new Vector2(0.5f),
- }
- };
+ Child = colourBox = new Box { RelativeSizeAxes = Axes.Both, };
}
public void Animate(BubbleLifeTimeEntry entry)
{
Size = entry.InitialSize;
+ BorderThickness = Width / 3.5f;
//We want to fade to a darker colour to avoid colours such as white hiding the "ripple" effect.
- var colourDarker = entry.Colour.Darken(0.1f);
+ ColourInfo colourDarker = entry.Colour.Darken(0.1f);
+ // Main bubble scaling based on combo
this.ScaleTo(entry.MaxSize, getAnimationDuration() * 0.8f)
.Then()
+ // Pop at the end of the bubbles life time
.ScaleTo(entry.MaxSize * 1.5f, getAnimationDuration() * 0.2f, Easing.OutQuint)
- .FadeTo(0, getAnimationDuration() * 0.2f, Easing.OutQuint);
-
- innerCircle.ScaleTo(2f, getAnimationDuration() * 0.8f, Easing.OutQuint);
+ .FadeTo(0, getAnimationDuration() * 0.2f, Easing.OutCirc);
if (!entry.IsHit)
{
- colourBox.Colour = Colour4.Black;
- innerCircle.Colour = Colour4.Black;
+ Colour = Colour4.Black;
+ BorderColour = Colour4.Black;
return;
}
- colourBox.FadeColour(colourDarker, getAnimationDuration() * 0.2f, Easing.OutQuint
- );
- innerCircle.FadeColour(colourDarker);
+ colourBox.FadeColour(colourDarker);
+
+ this.TransformTo(nameof(BorderColour), colourDarker, getAnimationDuration() * 0.3f, Easing.OutQuint);
+
+ // Ripple effect utilises the border to reduce drawable count
+ this.TransformTo(nameof(BorderThickness), 2f, getAnimationDuration() * 0.3f, Easing.OutQuint)
+
+ // Avoids transparency overlap issues during the bubble "pop"
+ .Then().Schedule(() =>
+ {
+ BorderThickness = 0;
+ BorderColour = Colour4.Transparent;
+ });
// The absolute length of the bubble's animation, can be used in fractions for animations of partial length
double getAnimationDuration() => 1700 + Math.Pow(entry.FadeTime, 1.07f);
From f58534f60c76e4b0f9874eb91be336a49cb62035 Mon Sep 17 00:00:00 2001
From: Terochi
Date: Sun, 5 Feb 2023 16:35:11 +0100
Subject: [PATCH 0058/1400] Extended the length of replay at the end of map
---
osu.Game/Screens/Play/Player.cs | 88 +++++++++++++++++++--------------
1 file changed, 52 insertions(+), 36 deletions(-)
diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs
index bf7f38cdd3..fda6bdaa8f 100644
--- a/osu.Game/Screens/Play/Player.cs
+++ b/osu.Game/Screens/Play/Player.cs
@@ -613,6 +613,8 @@ namespace osu.Game.Screens.Play
// if an exit has been requested, cancel any pending completion (the user has shown intention to exit).
resultsDisplayDelegate?.Cancel();
+ beginScoreImport();
+
// The actual exit is performed if
// - the pause / fail dialog was not requested
// - the pause / fail dialog was requested but is already displayed (user showing intention to exit).
@@ -735,14 +737,9 @@ namespace osu.Game.Screens.Play
// is no chance that a user could return to the (already completed) Player instance from a child screen.
ValidForResume = false;
- // Ensure we are not writing to the replay any more, as we are about to consume and store the score.
- DrawableRuleset.SetRecordTarget(null);
-
if (!Configuration.ShowResults)
return;
- prepareScoreForDisplayTask ??= Task.Run(prepareAndImportScore);
-
bool storyboardHasOutro = DimmableStoryboard.ContentDisplayed && !DimmableStoryboard.HasStoryboardEnded.Value;
if (storyboardHasOutro)
@@ -756,6 +753,56 @@ namespace osu.Game.Screens.Play
progressToResults(true);
}
+ ///
+ /// Queue the results screen for display.
+ ///
+ ///
+ /// A final display will only occur once all work is completed in . This means that even after calling this method, the results screen will never be shown until ScoreProcessor.HasCompleted becomes .
+ ///
+ /// Whether a minimum delay () should be added before the screen is displayed.
+ private void progressToResults(bool withDelay)
+ {
+ resultsDisplayDelegate?.Cancel();
+
+ double delay = withDelay ? RESULTS_DISPLAY_DELAY : 0;
+
+ resultsDisplayDelegate = new ScheduledDelegate(() =>
+ {
+ if (prepareScoreForDisplayTask == null)
+ {
+ beginScoreImport();
+ return;
+ }
+
+ if (!prepareScoreForDisplayTask.IsCompleted)
+ // If the asynchronous preparation has not completed, keep repeating this delegate.
+ return;
+
+ resultsDisplayDelegate?.Cancel();
+
+ if (!this.IsCurrentScreen())
+ // This player instance may already be in the process of exiting.
+ return;
+
+ this.Push(CreateResults(prepareScoreForDisplayTask.GetResultSafely()));
+ }, Time.Current + delay, 50);
+
+ Scheduler.Add(resultsDisplayDelegate);
+ }
+
+ private void beginScoreImport()
+ {
+ // We do not want to import the score in cases where we don't show results
+ bool canShowResults = Configuration.ShowResults && ScoreProcessor.HasCompleted.Value && GameplayState.HasPassed;
+ if (!canShowResults)
+ return;
+
+ // Ensure we are not writing to the replay any more, as we are about to consume and store the score.
+ DrawableRuleset.SetRecordTarget(null);
+
+ prepareScoreForDisplayTask ??= Task.Run(prepareAndImportScore);
+ }
+
///
/// Asynchronously run score preparation operations (database import, online submission etc.).
///
@@ -785,37 +832,6 @@ namespace osu.Game.Screens.Play
return scoreCopy.ScoreInfo;
}
- ///
- /// Queue the results screen for display.
- ///
- ///
- /// A final display will only occur once all work is completed in . This means that even after calling this method, the results screen will never be shown until ScoreProcessor.HasCompleted becomes .
- ///
- /// Whether a minimum delay () should be added before the screen is displayed.
- private void progressToResults(bool withDelay)
- {
- resultsDisplayDelegate?.Cancel();
-
- double delay = withDelay ? RESULTS_DISPLAY_DELAY : 0;
-
- resultsDisplayDelegate = new ScheduledDelegate(() =>
- {
- if (prepareScoreForDisplayTask?.IsCompleted != true)
- // If the asynchronous preparation has not completed, keep repeating this delegate.
- return;
-
- resultsDisplayDelegate?.Cancel();
-
- if (!this.IsCurrentScreen())
- // This player instance may already be in the process of exiting.
- return;
-
- this.Push(CreateResults(prepareScoreForDisplayTask.GetResultSafely()));
- }, Time.Current + delay, 50);
-
- Scheduler.Add(resultsDisplayDelegate);
- }
-
protected override bool OnScroll(ScrollEvent e)
{
// During pause, allow global volume adjust regardless of settings.
From 45981125860b331d5f5dbaa59966e6d354f2fd4c Mon Sep 17 00:00:00 2001
From: Cootz
Date: Sun, 5 Feb 2023 21:46:38 +0300
Subject: [PATCH 0059/1400] Add OriginalBeatmapHash to ScoreInfo. Update db
schema_version, migration
---
osu.Game/Beatmaps/BeatmapManager.cs | 8 ++++++++
osu.Game/Database/RealmAccess.cs | 15 +++++++++++++++
osu.Game/Scoring/ScoreInfo.cs | 2 ++
3 files changed, 25 insertions(+)
diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs
index ad56bbbc3a..e972f067ca 100644
--- a/osu.Game/Beatmaps/BeatmapManager.cs
+++ b/osu.Game/Beatmaps/BeatmapManager.cs
@@ -13,6 +13,7 @@ using System.Threading.Tasks;
using osu.Framework.Audio;
using osu.Framework.Audio.Track;
using osu.Framework.Extensions;
+using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.IO.Stores;
using osu.Framework.Platform;
using osu.Framework.Testing;
@@ -25,6 +26,7 @@ using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays.Notifications;
using osu.Game.Rulesets;
+using osu.Game.Scoring;
using osu.Game.Skinning;
using osu.Game.Utils;
@@ -454,6 +456,12 @@ namespace osu.Game.Beatmaps
if (transferCollections)
beatmapInfo.TransferCollectionReferences(r, oldMd5Hash);
+ //Unlinking all scores from this beatmap
+ r.All().Where(s => s.BeatmapInfoID == beatmapInfo.ID).ForEach(s => s.BeatmapInfo = new BeatmapInfo());
+
+ //Linking all the previos scores
+ r.All().Where(s => s.OriginalBeatmapHash == beatmapInfo.Hash).ForEach(s => s.BeatmapInfo = beatmapInfo);
+
ProcessBeatmap?.Invoke((liveBeatmapSet, false));
});
}
diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs
index 177c671bca..422ceb8af3 100644
--- a/osu.Game/Database/RealmAccess.cs
+++ b/osu.Game/Database/RealmAccess.cs
@@ -70,6 +70,7 @@ namespace osu.Game.Database
/// 23 2022-08-01 Added LastLocalUpdate to BeatmapInfo.
/// 24 2022-08-22 Added MaximumStatistics to ScoreInfo.
/// 25 2022-09-18 Remove skins to add with new naming.
+ /// 26 2023-02-05 Added OriginalBeatmapHash to ScoreInfo.
///
private const int schema_version = 25;
@@ -865,6 +866,20 @@ namespace osu.Game.Database
case 25:
// Remove the default skins so they can be added back by SkinManager with updated naming.
migration.NewRealm.RemoveRange(migration.NewRealm.All().Where(s => s.Protected));
+ break;
+ case 26:
+ // Adding origin beatmap hash property to ensure the score corresponds to the version of beatmap it should
+ // See: https://github.com/ppy/osu/issues/22062
+ string ScoreInfoName = getMappedOrOriginalName(typeof(ScoreInfo));
+
+ var oldScoreInfos = migration.OldRealm.DynamicApi.All(ScoreInfoName);
+ var newScoreInfos = migration.NewRealm.All();
+
+ for (int i = 0; i < newScoreInfos.Count(); i++)
+ {
+ newScoreInfos.ElementAt(i).OriginalBeatmapHash = oldScoreInfos.ElementAt(i).BeatmapInfo.Hash;
+ }
+
break;
}
}
diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs
index 1009474d89..2c029bbe68 100644
--- a/osu.Game/Scoring/ScoreInfo.cs
+++ b/osu.Game/Scoring/ScoreInfo.cs
@@ -66,6 +66,8 @@ namespace osu.Game.Scoring
[MapTo("MaximumStatistics")]
public string MaximumStatisticsJson { get; set; } = string.Empty;
+ public string OriginalBeatmapHash { get; set; } = string.Empty;
+
public ScoreInfo(BeatmapInfo? beatmap = null, RulesetInfo? ruleset = null, RealmUser? realmUser = null)
{
Ruleset = ruleset ?? new RulesetInfo();
From d23e787bc1f341ae41c3fa5a21467d0c9f320973 Mon Sep 17 00:00:00 2001
From: Cootz
Date: Sun, 5 Feb 2023 21:55:50 +0300
Subject: [PATCH 0060/1400] Update `schema_version`
---
osu.Game/Database/RealmAccess.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs
index 422ceb8af3..6f85b3f1be 100644
--- a/osu.Game/Database/RealmAccess.cs
+++ b/osu.Game/Database/RealmAccess.cs
@@ -72,7 +72,7 @@ namespace osu.Game.Database
/// 25 2022-09-18 Remove skins to add with new naming.
/// 26 2023-02-05 Added OriginalBeatmapHash to ScoreInfo.
///
- private const int schema_version = 25;
+ private const int schema_version = 26;
///
/// Lock object which is held during sections, blocking realm retrieval during blocking periods.
From 4f23e096d76e9ab33140b77472dd4fa6247d9b0c Mon Sep 17 00:00:00 2001
From: Terochi
Date: Mon, 6 Feb 2023 07:59:37 +0100
Subject: [PATCH 0061/1400] Improved readability
---
osu.Game/Screens/Play/Player.cs | 27 ++++++++++++++++++++-------
1 file changed, 20 insertions(+), 7 deletions(-)
diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs
index fda6bdaa8f..443108cf34 100644
--- a/osu.Game/Screens/Play/Player.cs
+++ b/osu.Game/Screens/Play/Player.cs
@@ -613,6 +613,7 @@ namespace osu.Game.Screens.Play
// if an exit has been requested, cancel any pending completion (the user has shown intention to exit).
resultsDisplayDelegate?.Cancel();
+ // import current score if possible.
beginScoreImport();
// The actual exit is performed if
@@ -770,7 +771,11 @@ namespace osu.Game.Screens.Play
{
if (prepareScoreForDisplayTask == null)
{
- beginScoreImport();
+ // Try importing score since the task hasn't been invoked yet.
+ if (!beginScoreImport())
+ // If the task hasn't started, the score will never be imported.
+ resultsDisplayDelegate?.Cancel();
+
return;
}
@@ -790,17 +795,25 @@ namespace osu.Game.Screens.Play
Scheduler.Add(resultsDisplayDelegate);
}
- private void beginScoreImport()
+ ///
+ /// Ends replay recording and runs only when results can be shown
+ ///
+ ///
+ /// Whether the task has been invoked
+ ///
+ private bool beginScoreImport()
{
- // We do not want to import the score in cases where we don't show results
- bool canShowResults = Configuration.ShowResults && ScoreProcessor.HasCompleted.Value && GameplayState.HasPassed;
- if (!canShowResults)
- return;
-
// Ensure we are not writing to the replay any more, as we are about to consume and store the score.
DrawableRuleset.SetRecordTarget(null);
+ // We do not want to import the score in cases where we don't show results
+ bool canShowResults = Configuration.ShowResults && ScoreProcessor.HasCompleted.Value && GameplayState.HasPassed;
+ if (!canShowResults)
+ return false;
+
prepareScoreForDisplayTask ??= Task.Run(prepareAndImportScore);
+
+ return true;
}
///
From abcb564a74efeb3bb9e43ee1686f402297d416b5 Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Mon, 6 Feb 2023 17:32:17 +0900
Subject: [PATCH 0062/1400] Code quality pass of `OsuModBubbles`
---
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 24 ++++++---------------
1 file changed, 6 insertions(+), 18 deletions(-)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index 2c90bfa399..3606434042 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -29,15 +29,15 @@ namespace osu.Game.Rulesets.Osu.Mods
{
public override string Name => "Bubbles";
- public override string Acronym => "BB";
+ public override string Acronym => "BU";
- public override LocalisableString Description => "Dont let their popping distract you!";
+ public override LocalisableString Description => "Don't let their popping distract you!";
public override double ScoreMultiplier => 1;
public override ModType Type => ModType.Fun;
- // Compatibility with these seems potentially feasible in the future, blocked for now because they dont work as one would expect
+ // Compatibility with these seems potentially feasible in the future, blocked for now because they don't work as one would expect
public override Type[] IncompatibleMods => new[] { typeof(OsuModBarrelRoll), typeof(OsuModMagnetised), typeof(OsuModRepel) };
private PlayfieldAdjustmentContainer adjustmentContainer = null!;
@@ -87,26 +87,14 @@ namespace osu.Game.Rulesets.Osu.Mods
if (drawableObject is not DrawableOsuHitObject drawableOsuObject || !drawableObject.Judged) return;
- OsuHitObject hitObject = drawableOsuObject.HitObject;
-
switch (drawableOsuObject)
{
- //Needs to be done explicitly to avoid being handled by DrawableHitCircle below
- case DrawableSliderHead:
- addBubbleContainer(hitObject.Position, drawableOsuObject);
- return;
-
- //Stack leniency causes placement issues if this isn't handled as such.
- case DrawableHitCircle hitCircle:
- addBubbleContainer(hitCircle.Position, drawableOsuObject);
- break;
-
case DrawableSlider:
case DrawableSpinnerTick:
break;
default:
- addBubbleContainer(hitObject.Position, drawableOsuObject);
+ addBubbleForObject(drawableOsuObject);
break;
}
}
@@ -114,7 +102,7 @@ namespace osu.Game.Rulesets.Osu.Mods
private void applySliderState(DrawableSlider slider) =>
((PlaySliderBody)slider.Body.Drawable).BorderColour = slider.AccentColour.Value;
- private void addBubbleContainer(Vector2 position, DrawableHitObject hitObject)
+ private void addBubbleForObject(DrawableOsuHitObject hitObject)
{
bubbleContainer.Add
(
@@ -122,7 +110,7 @@ namespace osu.Game.Rulesets.Osu.Mods
{
LifetimeStart = bubbleContainer.Time.Current,
Colour = hitObject.AccentColour.Value,
- Position = position,
+ Position = hitObject.HitObject.Position,
InitialSize = new Vector2(bubbleRadius),
MaxSize = maxSize,
FadeTime = bubbleFade,
From 43f7665c9eabe7105bb1a7c1c2ace3784214d28f Mon Sep 17 00:00:00 2001
From: Terochi
Date: Mon, 6 Feb 2023 09:49:42 +0100
Subject: [PATCH 0063/1400] Improved readability again
---
osu.Game/Screens/Play/Player.cs | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs
index 443108cf34..2f81b7154a 100644
--- a/osu.Game/Screens/Play/Player.cs
+++ b/osu.Game/Screens/Play/Player.cs
@@ -614,7 +614,7 @@ namespace osu.Game.Screens.Play
resultsDisplayDelegate?.Cancel();
// import current score if possible.
- beginScoreImport();
+ attemptScoreImport();
// The actual exit is performed if
// - the pause / fail dialog was not requested
@@ -772,8 +772,8 @@ namespace osu.Game.Screens.Play
if (prepareScoreForDisplayTask == null)
{
// Try importing score since the task hasn't been invoked yet.
- if (!beginScoreImport())
- // If the task hasn't started, the score will never be imported.
+ if (!attemptScoreImport())
+ // If attempt failed, trying again is unnecessary
resultsDisplayDelegate?.Cancel();
return;
@@ -796,12 +796,12 @@ namespace osu.Game.Screens.Play
}
///
- /// Ends replay recording and runs only when results can be shown
+ /// Attempts to run
///
///
- /// Whether the task has been invoked
+ /// Whether the attempt was successful
///
- private bool beginScoreImport()
+ private bool attemptScoreImport()
{
// Ensure we are not writing to the replay any more, as we are about to consume and store the score.
DrawableRuleset.SetRecordTarget(null);
From b00848e742d48ef08849d5115690909109c88de9 Mon Sep 17 00:00:00 2001
From: Cootz
Date: Mon, 6 Feb 2023 13:58:41 +0300
Subject: [PATCH 0064/1400] Fix realm error. Apply `OriginalBeatmapHash` on
import
---
osu.Game/Beatmaps/BeatmapManager.cs | 6 ------
osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs | 1 +
2 files changed, 1 insertion(+), 6 deletions(-)
diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs
index e972f067ca..b46859cc59 100644
--- a/osu.Game/Beatmaps/BeatmapManager.cs
+++ b/osu.Game/Beatmaps/BeatmapManager.cs
@@ -456,12 +456,6 @@ namespace osu.Game.Beatmaps
if (transferCollections)
beatmapInfo.TransferCollectionReferences(r, oldMd5Hash);
- //Unlinking all scores from this beatmap
- r.All().Where(s => s.BeatmapInfoID == beatmapInfo.ID).ForEach(s => s.BeatmapInfo = new BeatmapInfo());
-
- //Linking all the previos scores
- r.All().Where(s => s.OriginalBeatmapHash == beatmapInfo.Hash).ForEach(s => s.BeatmapInfo = beatmapInfo);
-
ProcessBeatmap?.Invoke((liveBeatmapSet, false));
});
}
diff --git a/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs b/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs
index 6f0b0c62f8..4bd068ca0f 100644
--- a/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs
+++ b/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs
@@ -123,6 +123,7 @@ namespace osu.Game.Scoring.Legacy
// before returning for database import, we must restore the database-sourced BeatmapInfo.
// if not, the clone operation in GetPlayableBeatmap will cause a dereference and subsequent database exception.
score.ScoreInfo.BeatmapInfo = workingBeatmap.BeatmapInfo;
+ score.ScoreInfo.OriginalBeatmapHash = workingBeatmap.BeatmapInfo.Hash;
return score;
}
From 2c7386db39d894cfa8ef335e7c58659399ed2e19 Mon Sep 17 00:00:00 2001
From: Cootz
Date: Mon, 6 Feb 2023 15:14:14 +0300
Subject: [PATCH 0065/1400] FIx score appearing on `BeatmapLeaderboard` and
`TopLocalRank`
---
osu.Game/Screens/Play/Player.cs | 1 +
osu.Game/Screens/Select/Carousel/TopLocalRank.cs | 1 +
osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs | 1 +
3 files changed, 3 insertions(+)
diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs
index 0d208e6d9b..7bd020db93 100644
--- a/osu.Game/Screens/Play/Player.cs
+++ b/osu.Game/Screens/Play/Player.cs
@@ -248,6 +248,7 @@ namespace osu.Game.Screens.Play
// ensure the score is in a consistent state with the current player.
Score.ScoreInfo.BeatmapInfo = Beatmap.Value.BeatmapInfo;
+ Score.ScoreInfo.OriginalBeatmapHash = Beatmap.Value.BeatmapInfo.Hash;
Score.ScoreInfo.Ruleset = ruleset.RulesetInfo;
Score.ScoreInfo.Mods = gameplayMods;
diff --git a/osu.Game/Screens/Select/Carousel/TopLocalRank.cs b/osu.Game/Screens/Select/Carousel/TopLocalRank.cs
index f1b773c831..3df72f7d3b 100644
--- a/osu.Game/Screens/Select/Carousel/TopLocalRank.cs
+++ b/osu.Game/Screens/Select/Carousel/TopLocalRank.cs
@@ -65,6 +65,7 @@ namespace osu.Game.Screens.Select.Carousel
r.All()
.Filter($"{nameof(ScoreInfo.User)}.{nameof(RealmUser.OnlineID)} == $0"
+ $" && {nameof(ScoreInfo.BeatmapInfo)}.{nameof(BeatmapInfo.ID)} == $1"
+ + $" && {nameof(ScoreInfo.BeatmapInfo)}.{nameof(BeatmapInfo.Hash)} == {nameof(ScoreInfo.OriginalBeatmapHash)}"
+ $" && {nameof(ScoreInfo.Ruleset)}.{nameof(RulesetInfo.ShortName)} == $2"
+ $" && {nameof(ScoreInfo.DeletePending)} == false", api.LocalUser.Value.Id, beatmapInfo.ID, ruleset.Value.ShortName),
localScoresChanged);
diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs
index 5c720c8491..3e90d2465b 100644
--- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs
+++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs
@@ -191,6 +191,7 @@ namespace osu.Game.Screens.Select.Leaderboards
scoreSubscription = realm.RegisterForNotifications(r =>
r.All().Filter($"{nameof(ScoreInfo.BeatmapInfo)}.{nameof(BeatmapInfo.ID)} == $0"
+ + $" AND {nameof(ScoreInfo.BeatmapInfo)}.{nameof(BeatmapInfo.Hash)} == {nameof(ScoreInfo.OriginalBeatmapHash)}"
+ $" AND {nameof(ScoreInfo.Ruleset)}.{nameof(RulesetInfo.ShortName)} == $1"
+ $" AND {nameof(ScoreInfo.DeletePending)} == false"
, beatmapInfo.ID, ruleset.Value.ShortName), localScoresChanged);
From f0d4b9f0ca339c79c74fba39f1d9a97de37f5f6e Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Mon, 6 Feb 2023 17:00:47 +0100
Subject: [PATCH 0066/1400] Add inline comment for colour border override
---
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 1 +
1 file changed, 1 insertion(+)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index 3606434042..41430bb323 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -99,6 +99,7 @@ namespace osu.Game.Rulesets.Osu.Mods
}
}
+ // Makes the slider border coloured on all skins
private void applySliderState(DrawableSlider slider) =>
((PlaySliderBody)slider.Body.Drawable).BorderColour = slider.AccentColour.Value;
From cb26601cb4be90a62d898d230a14ac9cb667ecc3 Mon Sep 17 00:00:00 2001
From: Cootz
Date: Tue, 7 Feb 2023 02:29:28 +0300
Subject: [PATCH 0067/1400] Fix test's score generation
---
osu.Game.Tests/Resources/TestResources.cs | 1 +
.../Visual/SongSelect/TestSceneBeatmapLeaderboard.cs | 10 ++++++++++
.../Visual/UserInterface/TestSceneDeleteLocalScore.cs | 1 +
3 files changed, 12 insertions(+)
diff --git a/osu.Game.Tests/Resources/TestResources.cs b/osu.Game.Tests/Resources/TestResources.cs
index adf28afc8e..f65d427649 100644
--- a/osu.Game.Tests/Resources/TestResources.cs
+++ b/osu.Game.Tests/Resources/TestResources.cs
@@ -176,6 +176,7 @@ namespace osu.Game.Tests.Resources
CoverUrl = "https://osu.ppy.sh/images/headers/profile-covers/c3.jpg",
},
BeatmapInfo = beatmap,
+ OriginalBeatmapHash = beatmap.Hash,
Ruleset = beatmap.Ruleset,
Mods = new Mod[] { new TestModHardRock(), new TestModDoubleTime() },
TotalScore = 2845370,
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
index ef0ad6c25c..7a578230d9 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
@@ -210,6 +210,7 @@ namespace osu.Game.Tests.Visual.SongSelect
},
Ruleset = new OsuRuleset().RulesetInfo,
BeatmapInfo = beatmapInfo,
+ OriginalBeatmapHash = beatmapInfo.Hash,
User = new APIUser
{
Id = 6602580,
@@ -226,6 +227,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Date = DateTime.Now.AddSeconds(-30),
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
+ OriginalBeatmapHash = beatmapInfo.Hash,
Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
{
@@ -243,6 +245,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Date = DateTime.Now.AddSeconds(-70),
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
+ OriginalBeatmapHash = beatmapInfo.Hash,
Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
@@ -261,6 +264,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Date = DateTime.Now.AddMinutes(-40),
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
+ OriginalBeatmapHash = beatmapInfo.Hash,
Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
@@ -279,6 +283,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Date = DateTime.Now.AddHours(-2),
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
+ OriginalBeatmapHash = beatmapInfo.Hash,
Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
@@ -297,6 +302,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Date = DateTime.Now.AddHours(-25),
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
+ OriginalBeatmapHash = beatmapInfo.Hash,
Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
@@ -315,6 +321,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Date = DateTime.Now.AddHours(-50),
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
+ OriginalBeatmapHash = beatmapInfo.Hash,
Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
@@ -333,6 +340,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Date = DateTime.Now.AddHours(-72),
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
+ OriginalBeatmapHash = beatmapInfo.Hash,
Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
@@ -351,6 +359,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Date = DateTime.Now.AddMonths(-3),
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
+ OriginalBeatmapHash = beatmapInfo.Hash,
Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
@@ -369,6 +378,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Date = DateTime.Now.AddYears(-2),
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
+ OriginalBeatmapHash = beatmapInfo.Hash,
Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs
index 7635c61867..14193b1ac8 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs
@@ -94,6 +94,7 @@ namespace osu.Game.Tests.Visual.UserInterface
{
OnlineID = i,
BeatmapInfo = beatmapInfo,
+ OriginalBeatmapHash = beatmapInfo.Hash,
Accuracy = RNG.NextDouble(),
TotalScore = RNG.Next(1, 1000000),
MaxCombo = RNG.Next(1, 1000),
From 723f13af259da2e022a5c25b61d84b67c8ad75a9 Mon Sep 17 00:00:00 2001
From: Cootz
Date: Tue, 7 Feb 2023 02:43:27 +0300
Subject: [PATCH 0068/1400] Add summary for `OriginalBeatmapHash`
---
osu.Game/Scoring/ScoreInfo.cs | 3 +++
1 file changed, 3 insertions(+)
diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs
index 2c029bbe68..7ad2d9203a 100644
--- a/osu.Game/Scoring/ScoreInfo.cs
+++ b/osu.Game/Scoring/ScoreInfo.cs
@@ -66,6 +66,9 @@ namespace osu.Game.Scoring
[MapTo("MaximumStatistics")]
public string MaximumStatisticsJson { get; set; } = string.Empty;
+ ///
+ /// Hash of the beatmap where it scored
+ ///
public string OriginalBeatmapHash { get; set; } = string.Empty;
public ScoreInfo(BeatmapInfo? beatmap = null, RulesetInfo? ruleset = null, RealmUser? realmUser = null)
From 1470ea0a311bec07ba3ba6525025939e51322a68 Mon Sep 17 00:00:00 2001
From: Cootz
Date: Tue, 7 Feb 2023 03:07:53 +0300
Subject: [PATCH 0069/1400] Remove unnecessary using directives
---
osu.Game/Beatmaps/BeatmapManager.cs | 2 --
1 file changed, 2 deletions(-)
diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs
index b46859cc59..ad56bbbc3a 100644
--- a/osu.Game/Beatmaps/BeatmapManager.cs
+++ b/osu.Game/Beatmaps/BeatmapManager.cs
@@ -13,7 +13,6 @@ using System.Threading.Tasks;
using osu.Framework.Audio;
using osu.Framework.Audio.Track;
using osu.Framework.Extensions;
-using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.IO.Stores;
using osu.Framework.Platform;
using osu.Framework.Testing;
@@ -26,7 +25,6 @@ using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays.Notifications;
using osu.Game.Rulesets;
-using osu.Game.Scoring;
using osu.Game.Skinning;
using osu.Game.Utils;
From a1ee3df453f46a271d7ba7450f791340119cc539 Mon Sep 17 00:00:00 2001
From: Cootz
Date: Tue, 7 Feb 2023 03:16:25 +0300
Subject: [PATCH 0070/1400] Improve local variable naming
---
osu.Game/Database/RealmAccess.cs | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs
index 6f85b3f1be..1ef904fbc3 100644
--- a/osu.Game/Database/RealmAccess.cs
+++ b/osu.Game/Database/RealmAccess.cs
@@ -867,12 +867,13 @@ namespace osu.Game.Database
// Remove the default skins so they can be added back by SkinManager with updated naming.
migration.NewRealm.RemoveRange(migration.NewRealm.All().Where(s => s.Protected));
break;
+
case 26:
// Adding origin beatmap hash property to ensure the score corresponds to the version of beatmap it should
// See: https://github.com/ppy/osu/issues/22062
- string ScoreInfoName = getMappedOrOriginalName(typeof(ScoreInfo));
+ string scoreInfoName = getMappedOrOriginalName(typeof(ScoreInfo));
- var oldScoreInfos = migration.OldRealm.DynamicApi.All(ScoreInfoName);
+ var oldScoreInfos = migration.OldRealm.DynamicApi.All(scoreInfoName);
var newScoreInfos = migration.NewRealm.All();
for (int i = 0; i < newScoreInfos.Count(); i++)
From 957c9e7e276037c9c0db101f5e77cbaf3ceda5da Mon Sep 17 00:00:00 2001
From: Cootz <50776304+Cootz@users.noreply.github.com>
Date: Tue, 7 Feb 2023 11:23:39 +0300
Subject: [PATCH 0071/1400] Update osu.Game/Scoring/ScoreInfo.cs
Co-authored-by: Dean Herbert
---
osu.Game/Scoring/ScoreInfo.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs
index 7ad2d9203a..2ea40df44d 100644
--- a/osu.Game/Scoring/ScoreInfo.cs
+++ b/osu.Game/Scoring/ScoreInfo.cs
@@ -67,9 +67,9 @@ namespace osu.Game.Scoring
public string MaximumStatisticsJson { get; set; } = string.Empty;
///
- /// Hash of the beatmap where it scored
+ /// The beatmap's at the point in time when the score was set.
///
- public string OriginalBeatmapHash { get; set; } = string.Empty;
+ public string BeatmapHash { get; set; } = string.Empty;
public ScoreInfo(BeatmapInfo? beatmap = null, RulesetInfo? ruleset = null, RealmUser? realmUser = null)
{
From 7e127dafe21a89f5059f59de5cff7904f34e9783 Mon Sep 17 00:00:00 2001
From: PC
Date: Tue, 7 Feb 2023 11:52:47 +0300
Subject: [PATCH 0072/1400] Update reference
---
osu.Game.Tests/Resources/TestResources.cs | 2 +-
.../SongSelect/TestSceneBeatmapLeaderboard.cs | 20 +++++++++----------
.../TestSceneDeleteLocalScore.cs | 2 +-
osu.Game/Database/RealmAccess.cs | 4 ++--
osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs | 2 +-
osu.Game/Scoring/ScoreInfo.cs | 2 +-
osu.Game/Screens/Play/Player.cs | 2 +-
.../Screens/Select/Carousel/TopLocalRank.cs | 2 +-
.../Select/Leaderboards/BeatmapLeaderboard.cs | 2 +-
9 files changed, 19 insertions(+), 19 deletions(-)
diff --git a/osu.Game.Tests/Resources/TestResources.cs b/osu.Game.Tests/Resources/TestResources.cs
index f65d427649..a2d81c0a75 100644
--- a/osu.Game.Tests/Resources/TestResources.cs
+++ b/osu.Game.Tests/Resources/TestResources.cs
@@ -176,7 +176,7 @@ namespace osu.Game.Tests.Resources
CoverUrl = "https://osu.ppy.sh/images/headers/profile-covers/c3.jpg",
},
BeatmapInfo = beatmap,
- OriginalBeatmapHash = beatmap.Hash,
+ BeatmapHash = beatmap.Hash,
Ruleset = beatmap.Ruleset,
Mods = new Mod[] { new TestModHardRock(), new TestModDoubleTime() },
TotalScore = 2845370,
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
index 7a578230d9..c4bca79480 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
@@ -210,7 +210,7 @@ namespace osu.Game.Tests.Visual.SongSelect
},
Ruleset = new OsuRuleset().RulesetInfo,
BeatmapInfo = beatmapInfo,
- OriginalBeatmapHash = beatmapInfo.Hash,
+ BeatmapHash = beatmapInfo.Hash,
User = new APIUser
{
Id = 6602580,
@@ -227,7 +227,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Date = DateTime.Now.AddSeconds(-30),
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
- OriginalBeatmapHash = beatmapInfo.Hash,
+ BeatmapHash = beatmapInfo.Hash,
Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
{
@@ -245,7 +245,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Date = DateTime.Now.AddSeconds(-70),
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
- OriginalBeatmapHash = beatmapInfo.Hash,
+ BeatmapHash = beatmapInfo.Hash,
Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
@@ -264,7 +264,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Date = DateTime.Now.AddMinutes(-40),
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
- OriginalBeatmapHash = beatmapInfo.Hash,
+ BeatmapHash = beatmapInfo.Hash,
Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
@@ -283,7 +283,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Date = DateTime.Now.AddHours(-2),
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
- OriginalBeatmapHash = beatmapInfo.Hash,
+ BeatmapHash = beatmapInfo.Hash,
Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
@@ -302,7 +302,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Date = DateTime.Now.AddHours(-25),
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
- OriginalBeatmapHash = beatmapInfo.Hash,
+ BeatmapHash = beatmapInfo.Hash,
Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
@@ -321,7 +321,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Date = DateTime.Now.AddHours(-50),
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
- OriginalBeatmapHash = beatmapInfo.Hash,
+ BeatmapHash = beatmapInfo.Hash,
Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
@@ -340,7 +340,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Date = DateTime.Now.AddHours(-72),
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
- OriginalBeatmapHash = beatmapInfo.Hash,
+ BeatmapHash = beatmapInfo.Hash,
Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
@@ -359,7 +359,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Date = DateTime.Now.AddMonths(-3),
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
- OriginalBeatmapHash = beatmapInfo.Hash,
+ BeatmapHash = beatmapInfo.Hash,
Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
@@ -378,7 +378,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Date = DateTime.Now.AddYears(-2),
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
- OriginalBeatmapHash = beatmapInfo.Hash,
+ BeatmapHash = beatmapInfo.Hash,
Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs
index 14193b1ac8..529874b71e 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs
@@ -94,7 +94,7 @@ namespace osu.Game.Tests.Visual.UserInterface
{
OnlineID = i,
BeatmapInfo = beatmapInfo,
- OriginalBeatmapHash = beatmapInfo.Hash,
+ BeatmapHash = beatmapInfo.Hash,
Accuracy = RNG.NextDouble(),
TotalScore = RNG.Next(1, 1000000),
MaxCombo = RNG.Next(1, 1000),
diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs
index 1ef904fbc3..b151fc6474 100644
--- a/osu.Game/Database/RealmAccess.cs
+++ b/osu.Game/Database/RealmAccess.cs
@@ -70,7 +70,7 @@ namespace osu.Game.Database
/// 23 2022-08-01 Added LastLocalUpdate to BeatmapInfo.
/// 24 2022-08-22 Added MaximumStatistics to ScoreInfo.
/// 25 2022-09-18 Remove skins to add with new naming.
- /// 26 2023-02-05 Added OriginalBeatmapHash to ScoreInfo.
+ /// 26 2023-02-05 Added BeatmapHash to ScoreInfo.
///
private const int schema_version = 26;
@@ -878,7 +878,7 @@ namespace osu.Game.Database
for (int i = 0; i < newScoreInfos.Count(); i++)
{
- newScoreInfos.ElementAt(i).OriginalBeatmapHash = oldScoreInfos.ElementAt(i).BeatmapInfo.Hash;
+ newScoreInfos.ElementAt(i).BeatmapHash = oldScoreInfos.ElementAt(i).BeatmapInfo.Hash;
}
break;
diff --git a/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs b/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs
index 4bd068ca0f..9b145ad56e 100644
--- a/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs
+++ b/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs
@@ -123,7 +123,7 @@ namespace osu.Game.Scoring.Legacy
// before returning for database import, we must restore the database-sourced BeatmapInfo.
// if not, the clone operation in GetPlayableBeatmap will cause a dereference and subsequent database exception.
score.ScoreInfo.BeatmapInfo = workingBeatmap.BeatmapInfo;
- score.ScoreInfo.OriginalBeatmapHash = workingBeatmap.BeatmapInfo.Hash;
+ score.ScoreInfo.BeatmapHash = workingBeatmap.BeatmapInfo.Hash;
return score;
}
diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs
index 2ea40df44d..62adcb9f94 100644
--- a/osu.Game/Scoring/ScoreInfo.cs
+++ b/osu.Game/Scoring/ScoreInfo.cs
@@ -67,7 +67,7 @@ namespace osu.Game.Scoring
public string MaximumStatisticsJson { get; set; } = string.Empty;
///
- /// The beatmap's at the point in time when the score was set.
+ /// The at the point in time when the score was set.
///
public string BeatmapHash { get; set; } = string.Empty;
diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs
index 7bd020db93..a3d8d3237c 100644
--- a/osu.Game/Screens/Play/Player.cs
+++ b/osu.Game/Screens/Play/Player.cs
@@ -248,7 +248,7 @@ namespace osu.Game.Screens.Play
// ensure the score is in a consistent state with the current player.
Score.ScoreInfo.BeatmapInfo = Beatmap.Value.BeatmapInfo;
- Score.ScoreInfo.OriginalBeatmapHash = Beatmap.Value.BeatmapInfo.Hash;
+ Score.ScoreInfo.BeatmapHash = Beatmap.Value.BeatmapInfo.Hash;
Score.ScoreInfo.Ruleset = ruleset.RulesetInfo;
Score.ScoreInfo.Mods = gameplayMods;
diff --git a/osu.Game/Screens/Select/Carousel/TopLocalRank.cs b/osu.Game/Screens/Select/Carousel/TopLocalRank.cs
index 3df72f7d3b..a57a8b0f27 100644
--- a/osu.Game/Screens/Select/Carousel/TopLocalRank.cs
+++ b/osu.Game/Screens/Select/Carousel/TopLocalRank.cs
@@ -65,7 +65,7 @@ namespace osu.Game.Screens.Select.Carousel
r.All()
.Filter($"{nameof(ScoreInfo.User)}.{nameof(RealmUser.OnlineID)} == $0"
+ $" && {nameof(ScoreInfo.BeatmapInfo)}.{nameof(BeatmapInfo.ID)} == $1"
- + $" && {nameof(ScoreInfo.BeatmapInfo)}.{nameof(BeatmapInfo.Hash)} == {nameof(ScoreInfo.OriginalBeatmapHash)}"
+ + $" && {nameof(ScoreInfo.BeatmapInfo)}.{nameof(BeatmapInfo.Hash)} == {nameof(ScoreInfo.BeatmapHash)}"
+ $" && {nameof(ScoreInfo.Ruleset)}.{nameof(RulesetInfo.ShortName)} == $2"
+ $" && {nameof(ScoreInfo.DeletePending)} == false", api.LocalUser.Value.Id, beatmapInfo.ID, ruleset.Value.ShortName),
localScoresChanged);
diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs
index 3e90d2465b..2b40b9faf8 100644
--- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs
+++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs
@@ -191,7 +191,7 @@ namespace osu.Game.Screens.Select.Leaderboards
scoreSubscription = realm.RegisterForNotifications(r =>
r.All().Filter($"{nameof(ScoreInfo.BeatmapInfo)}.{nameof(BeatmapInfo.ID)} == $0"
- + $" AND {nameof(ScoreInfo.BeatmapInfo)}.{nameof(BeatmapInfo.Hash)} == {nameof(ScoreInfo.OriginalBeatmapHash)}"
+ + $" AND {nameof(ScoreInfo.BeatmapInfo)}.{nameof(BeatmapInfo.Hash)} == {nameof(ScoreInfo.BeatmapHash)}"
+ $" AND {nameof(ScoreInfo.Ruleset)}.{nameof(RulesetInfo.ShortName)} == $1"
+ $" AND {nameof(ScoreInfo.DeletePending)} == false"
, beatmapInfo.ID, ruleset.Value.ShortName), localScoresChanged);
From 338d96534a2ad7b27d82eeeafb2c778fb67d0b67 Mon Sep 17 00:00:00 2001
From: Cootz
Date: Wed, 8 Feb 2023 05:01:54 +0300
Subject: [PATCH 0073/1400] Add leaderboard test on beatmap update
---
.../SongSelect/TestSceneBeatmapLeaderboard.cs | 46 +++++++++++++++++++
1 file changed, 46 insertions(+)
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
index c4bca79480..13a24cd490 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
@@ -96,6 +96,37 @@ namespace osu.Game.Tests.Visual.SongSelect
checkCount(0);
}
+ [Test]
+ public void TestLocalScoresDisplayOnBeatmapEdit()
+ {
+ BeatmapInfo beatmapInfo = null!;
+
+ AddStep(@"Set scope", () => leaderboard.Scope = BeatmapLeaderboardScope.Local);
+
+ AddStep(@"Set beatmap", () =>
+ {
+ beatmapManager.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
+ beatmapInfo = beatmapManager.GetAllUsableBeatmapSets().First().Beatmaps.First();
+
+ leaderboard.BeatmapInfo = beatmapInfo;
+ });
+
+ clearScores();
+ checkCount(0);
+
+ loadMoreScores(() => beatmapInfo);
+ checkCount(10);
+
+ beatmapEdit(() => beatmapInfo);
+ checkCount(0);
+
+ loadMoreScores(() => beatmapInfo);
+ checkCount(10);
+
+ clearScores();
+ checkCount(0);
+ }
+
[Test]
public void TestGlobalScoresDisplay()
{
@@ -123,6 +154,21 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep(@"None selected", () => leaderboard.SetErrorState(LeaderboardState.NoneSelected));
}
+ private void beatmapEdit(Func beatmapInfo)
+ {
+ AddStep(@"Update beatmap via BeatmapManager", () =>
+ {
+ BeatmapInfo info = beatmapInfo();
+ IBeatmap beatmap = beatmapManager.GetWorkingBeatmap(info).Beatmap;
+
+ beatmap.Difficulty.ApproachRate = 11;
+ beatmap.Difficulty.DrainRate = 11;
+ beatmap.Difficulty.OverallDifficulty = 11;
+
+ beatmapManager.Save(info, beatmap);
+ });
+ }
+
private void showPersonalBestWithNullPosition()
{
leaderboard.SetScores(leaderboard.Scores, new ScoreInfo
From 391af2791b875a9928bba1d92dbcbae2128c0dd0 Mon Sep 17 00:00:00 2001
From: Cootz
Date: Wed, 8 Feb 2023 05:23:42 +0300
Subject: [PATCH 0074/1400] Fix CSharpWarnings::CS1574,CS1584,CS1581,CS1580
---
osu.Game/Scoring/ScoreInfo.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs
index 62adcb9f94..8c912ef32a 100644
--- a/osu.Game/Scoring/ScoreInfo.cs
+++ b/osu.Game/Scoring/ScoreInfo.cs
@@ -67,7 +67,7 @@ namespace osu.Game.Scoring
public string MaximumStatisticsJson { get; set; } = string.Empty;
///
- /// The at the point in time when the score was set.
+ /// The .Hash at the point in time when the score was set.
///
public string BeatmapHash { get; set; } = string.Empty;
From 6bf56aff73e07b7cd92241b251ae0ea0d9787b99 Mon Sep 17 00:00:00 2001
From: Cootz
Date: Wed, 8 Feb 2023 05:40:20 +0300
Subject: [PATCH 0075/1400] Add warning for `ScoreInfo`
---
osu.Game/Scoring/ScoreInfo.cs | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs
index 8c912ef32a..c57e06bee5 100644
--- a/osu.Game/Scoring/ScoreInfo.cs
+++ b/osu.Game/Scoring/ScoreInfo.cs
@@ -22,6 +22,13 @@ using Realms;
namespace osu.Game.Scoring
{
+
+ ///
+ /// Store information about the score
+ ///
+ ///
+ /// If you work on inporting/adding score please ensure you provide both BeatmapInfo and BeatmapHash
+ ///
[ExcludeFromDynamicCompile]
[MapTo("Score")]
public class ScoreInfo : RealmObject, IHasGuidPrimaryKey, IHasRealmFiles, ISoftDelete, IEquatable, IScoreInfo
From ab7c9a200bdcc7804927ca68b9c59da58d22d49f Mon Sep 17 00:00:00 2001
From: Cootz
Date: Wed, 8 Feb 2023 05:42:06 +0300
Subject: [PATCH 0076/1400] Fix a typo
---
osu.Game/Scoring/ScoreInfo.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs
index c57e06bee5..85452ede17 100644
--- a/osu.Game/Scoring/ScoreInfo.cs
+++ b/osu.Game/Scoring/ScoreInfo.cs
@@ -27,7 +27,7 @@ namespace osu.Game.Scoring
/// Store information about the score
///
///
- /// If you work on inporting/adding score please ensure you provide both BeatmapInfo and BeatmapHash
+ /// Warning: If you work on importing/adding score please ensure you provide both BeatmapInfo and BeatmapHash
///
[ExcludeFromDynamicCompile]
[MapTo("Score")]
From 4ba915268c5e0a34824d2a03cb501a12574707a4 Mon Sep 17 00:00:00 2001
From: Cootz
Date: Wed, 8 Feb 2023 05:46:47 +0300
Subject: [PATCH 0077/1400] Change a comment into `RealmAccess`
---
osu.Game/Database/RealmAccess.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs
index b151fc6474..861a74e163 100644
--- a/osu.Game/Database/RealmAccess.cs
+++ b/osu.Game/Database/RealmAccess.cs
@@ -869,7 +869,7 @@ namespace osu.Game.Database
break;
case 26:
- // Adding origin beatmap hash property to ensure the score corresponds to the version of beatmap it should
+ // Add ScoreInfo.BeatmapHash property to ensure the score corresponds to the version of beatmap it should
// See: https://github.com/ppy/osu/issues/22062
string scoreInfoName = getMappedOrOriginalName(typeof(ScoreInfo));
From 086b3eb542348048da062fde8234239e8d7d3ef6 Mon Sep 17 00:00:00 2001
From: Cootz
Date: Wed, 8 Feb 2023 05:50:52 +0300
Subject: [PATCH 0078/1400] Fix minor formating issues
---
osu.Game/Scoring/ScoreInfo.cs | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs
index 85452ede17..d2ec4ebd5f 100644
--- a/osu.Game/Scoring/ScoreInfo.cs
+++ b/osu.Game/Scoring/ScoreInfo.cs
@@ -22,10 +22,9 @@ using Realms;
namespace osu.Game.Scoring
{
-
///
/// Store information about the score
- ///
+ ///
///
/// Warning: If you work on importing/adding score please ensure you provide both BeatmapInfo and BeatmapHash
///
From 5c113ddb030445c5099fdd2334d6b2608f5851ef Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Wed, 8 Feb 2023 14:20:58 +0900
Subject: [PATCH 0079/1400] Reword xmldoc to read better
---
osu.Game/Scoring/ScoreInfo.cs | 21 ++++++++++++---------
1 file changed, 12 insertions(+), 9 deletions(-)
diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs
index d2ec4ebd5f..6213c65c75 100644
--- a/osu.Game/Scoring/ScoreInfo.cs
+++ b/osu.Game/Scoring/ScoreInfo.cs
@@ -23,11 +23,8 @@ using Realms;
namespace osu.Game.Scoring
{
///
- /// Store information about the score
+ /// A realm model containing metadata for a single score.
///
- ///
- /// Warning: If you work on importing/adding score please ensure you provide both BeatmapInfo and BeatmapHash
- ///
[ExcludeFromDynamicCompile]
[MapTo("Score")]
public class ScoreInfo : RealmObject, IHasGuidPrimaryKey, IHasRealmFiles, ISoftDelete, IEquatable, IScoreInfo
@@ -35,8 +32,19 @@ namespace osu.Game.Scoring
[PrimaryKey]
public Guid ID { get; set; }
+ ///
+ /// The this score was made against.
+ ///
+ ///
+ /// When setting this, make sure to also set to allow relational consistency when a beatmap is potentially changed.
+ ///
public BeatmapInfo BeatmapInfo { get; set; } = null!;
+ ///
+ /// The at the point in time when the score was set.
+ ///
+ public string BeatmapHash { get; set; } = string.Empty;
+
public RulesetInfo Ruleset { get; set; } = null!;
public IList Files { get; } = null!;
@@ -72,11 +80,6 @@ namespace osu.Game.Scoring
[MapTo("MaximumStatistics")]
public string MaximumStatisticsJson { get; set; } = string.Empty;
- ///
- /// The .Hash at the point in time when the score was set.
- ///
- public string BeatmapHash { get; set; } = string.Empty;
-
public ScoreInfo(BeatmapInfo? beatmap = null, RulesetInfo? ruleset = null, RealmUser? realmUser = null)
{
Ruleset = ruleset ?? new RulesetInfo();
From c50ea89bc99f3dc142e85ecec3bf2504d3fd5f32 Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Wed, 8 Feb 2023 14:24:06 +0900
Subject: [PATCH 0080/1400] Simplify migration to not rely on old/dynamic
schema
---
osu.Game/Database/RealmAccess.cs | 14 ++++----------
1 file changed, 4 insertions(+), 10 deletions(-)
diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs
index 861a74e163..831e328439 100644
--- a/osu.Game/Database/RealmAccess.cs
+++ b/osu.Game/Database/RealmAccess.cs
@@ -869,17 +869,11 @@ namespace osu.Game.Database
break;
case 26:
- // Add ScoreInfo.BeatmapHash property to ensure the score corresponds to the version of beatmap it should
- // See: https://github.com/ppy/osu/issues/22062
- string scoreInfoName = getMappedOrOriginalName(typeof(ScoreInfo));
+ // Add ScoreInfo.BeatmapHash property to ensure scores correspond to the correct version of beatmap.
+ var scores = migration.NewRealm.All();
- var oldScoreInfos = migration.OldRealm.DynamicApi.All(scoreInfoName);
- var newScoreInfos = migration.NewRealm.All();
-
- for (int i = 0; i < newScoreInfos.Count(); i++)
- {
- newScoreInfos.ElementAt(i).BeatmapHash = oldScoreInfos.ElementAt(i).BeatmapInfo.Hash;
- }
+ foreach (var score in scores)
+ score.BeatmapHash = score.BeatmapInfo.Hash;
break;
}
From c7eec371f52dd403a0bfaeea6f645d4a56dd3857 Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Wed, 8 Feb 2023 15:22:17 +0900
Subject: [PATCH 0081/1400] Clean up tests somewhat
---
.../SongSelect/TestSceneBeatmapLeaderboard.cs | 41 ++++++++-----------
1 file changed, 18 insertions(+), 23 deletions(-)
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
index 13a24cd490..83bb58804d 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
@@ -86,10 +86,10 @@ namespace osu.Game.Tests.Visual.SongSelect
clearScores();
checkCount(0);
- loadMoreScores(() => beatmapInfo);
+ importMoreScores(() => beatmapInfo);
checkCount(10);
- loadMoreScores(() => beatmapInfo);
+ importMoreScores(() => beatmapInfo);
checkCount(20);
clearScores();
@@ -114,13 +114,23 @@ namespace osu.Game.Tests.Visual.SongSelect
clearScores();
checkCount(0);
- loadMoreScores(() => beatmapInfo);
+ importMoreScores(() => beatmapInfo);
checkCount(10);
- beatmapEdit(() => beatmapInfo);
+ AddStep(@"Save beatmap with changes", () =>
+ {
+ IBeatmap beatmap = beatmapManager.GetWorkingBeatmap(beatmapInfo).Beatmap;
+
+ beatmap.Difficulty.ApproachRate = 11;
+ beatmap.Difficulty.DrainRate = 11;
+ beatmap.Difficulty.OverallDifficulty = 11;
+
+ beatmapManager.Save(beatmapInfo, beatmap);
+ });
+
checkCount(0);
- loadMoreScores(() => beatmapInfo);
+ importMoreScores(() => beatmapInfo);
checkCount(10);
clearScores();
@@ -154,21 +164,6 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep(@"None selected", () => leaderboard.SetErrorState(LeaderboardState.NoneSelected));
}
- private void beatmapEdit(Func beatmapInfo)
- {
- AddStep(@"Update beatmap via BeatmapManager", () =>
- {
- BeatmapInfo info = beatmapInfo();
- IBeatmap beatmap = beatmapManager.GetWorkingBeatmap(info).Beatmap;
-
- beatmap.Difficulty.ApproachRate = 11;
- beatmap.Difficulty.DrainRate = 11;
- beatmap.Difficulty.OverallDifficulty = 11;
-
- beatmapManager.Save(info, beatmap);
- });
- }
-
private void showPersonalBestWithNullPosition()
{
leaderboard.SetScores(leaderboard.Scores, new ScoreInfo
@@ -208,9 +203,9 @@ namespace osu.Game.Tests.Visual.SongSelect
});
}
- private void loadMoreScores(Func beatmapInfo)
+ private void importMoreScores(Func beatmapInfo)
{
- AddStep(@"Load new scores via manager", () =>
+ AddStep(@"Import new scores", () =>
{
foreach (var score in generateSampleScores(beatmapInfo()))
scoreManager.Import(score);
@@ -223,7 +218,7 @@ namespace osu.Game.Tests.Visual.SongSelect
}
private void checkCount(int expected) =>
- AddUntilStep("Correct count displayed", () => leaderboard.ChildrenOfType().Count() == expected);
+ AddUntilStep($"{expected} scores displayed", () => leaderboard.ChildrenOfType().Count(), () => Is.EqualTo(expected));
private static ScoreInfo[] generateSampleScores(BeatmapInfo beatmapInfo)
{
From d4d985ba0f0378d3c93a71b17e5cfcb793a7b41b Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Wed, 8 Feb 2023 15:34:46 +0900
Subject: [PATCH 0082/1400] Improve test to also check that reverting hash
restores old scores
---
.../SongSelect/TestSceneBeatmapLeaderboard.cs | 31 ++++++++++++++-----
1 file changed, 24 insertions(+), 7 deletions(-)
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
index 83bb58804d..01397563fd 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
@@ -100,10 +100,11 @@ namespace osu.Game.Tests.Visual.SongSelect
public void TestLocalScoresDisplayOnBeatmapEdit()
{
BeatmapInfo beatmapInfo = null!;
+ string originalHash = string.Empty;
AddStep(@"Set scope", () => leaderboard.Scope = BeatmapLeaderboardScope.Local);
- AddStep(@"Set beatmap", () =>
+ AddStep(@"Import beatmap", () =>
{
beatmapManager.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
beatmapInfo = beatmapManager.GetAllUsableBeatmapSets().First().Beatmaps.First();
@@ -114,23 +115,39 @@ namespace osu.Game.Tests.Visual.SongSelect
clearScores();
checkCount(0);
+ AddStep(@"Perform initial save to guarantee stable hash", () =>
+ {
+ IBeatmap beatmap = beatmapManager.GetWorkingBeatmap(beatmapInfo).Beatmap;
+ beatmapManager.Save(beatmapInfo, beatmap);
+
+ originalHash = beatmapInfo.Hash;
+ });
+
importMoreScores(() => beatmapInfo);
checkCount(10);
- AddStep(@"Save beatmap with changes", () =>
+ AddStep(@"Save with changes", () =>
{
IBeatmap beatmap = beatmapManager.GetWorkingBeatmap(beatmapInfo).Beatmap;
-
- beatmap.Difficulty.ApproachRate = 11;
- beatmap.Difficulty.DrainRate = 11;
- beatmap.Difficulty.OverallDifficulty = 11;
-
+ beatmap.Difficulty.ApproachRate = 12;
beatmapManager.Save(beatmapInfo, beatmap);
});
+ AddAssert("Hash changed", () => beatmapInfo.Hash, () => Is.Not.EqualTo(originalHash));
checkCount(0);
importMoreScores(() => beatmapInfo);
+ importMoreScores(() => beatmapInfo);
+ checkCount(20);
+
+ AddStep(@"Revert changes", () =>
+ {
+ IBeatmap beatmap = beatmapManager.GetWorkingBeatmap(beatmapInfo).Beatmap;
+ beatmap.Difficulty.ApproachRate = 8;
+ beatmapManager.Save(beatmapInfo, beatmap);
+ });
+
+ AddAssert("Hash restored", () => beatmapInfo.Hash, () => Is.EqualTo(originalHash));
checkCount(10);
clearScores();
From 38031fdf2327cb50705cd14fa55c4cb1cb058a9d Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Wed, 8 Feb 2023 15:38:07 +0900
Subject: [PATCH 0083/1400] Add test coverage of stores stored in database as
well
---
.../SongSelect/TestSceneBeatmapLeaderboard.cs | 31 ++++++++++++-------
1 file changed, 20 insertions(+), 11 deletions(-)
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
index 01397563fd..c234cc8a9c 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
@@ -84,16 +84,16 @@ namespace osu.Game.Tests.Visual.SongSelect
});
clearScores();
- checkCount(0);
+ checkDisplayedCount(0);
importMoreScores(() => beatmapInfo);
- checkCount(10);
+ checkDisplayedCount(10);
importMoreScores(() => beatmapInfo);
- checkCount(20);
+ checkDisplayedCount(20);
clearScores();
- checkCount(0);
+ checkDisplayedCount(0);
}
[Test]
@@ -113,7 +113,7 @@ namespace osu.Game.Tests.Visual.SongSelect
});
clearScores();
- checkCount(0);
+ checkDisplayedCount(0);
AddStep(@"Perform initial save to guarantee stable hash", () =>
{
@@ -124,7 +124,9 @@ namespace osu.Game.Tests.Visual.SongSelect
});
importMoreScores(() => beatmapInfo);
- checkCount(10);
+
+ checkDisplayedCount(10);
+ checkStoredCount(10);
AddStep(@"Save with changes", () =>
{
@@ -134,11 +136,13 @@ namespace osu.Game.Tests.Visual.SongSelect
});
AddAssert("Hash changed", () => beatmapInfo.Hash, () => Is.Not.EqualTo(originalHash));
- checkCount(0);
+ checkDisplayedCount(0);
+ checkStoredCount(10);
importMoreScores(() => beatmapInfo);
importMoreScores(() => beatmapInfo);
- checkCount(20);
+ checkDisplayedCount(20);
+ checkStoredCount(30);
AddStep(@"Revert changes", () =>
{
@@ -148,10 +152,12 @@ namespace osu.Game.Tests.Visual.SongSelect
});
AddAssert("Hash restored", () => beatmapInfo.Hash, () => Is.EqualTo(originalHash));
- checkCount(10);
+ checkDisplayedCount(10);
+ checkStoredCount(30);
clearScores();
- checkCount(0);
+ checkDisplayedCount(0);
+ checkStoredCount(0);
}
[Test]
@@ -234,9 +240,12 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep("Clear all scores", () => scoreManager.Delete());
}
- private void checkCount(int expected) =>
+ private void checkDisplayedCount(int expected) =>
AddUntilStep($"{expected} scores displayed", () => leaderboard.ChildrenOfType().Count(), () => Is.EqualTo(expected));
+ private void checkStoredCount(int expected) =>
+ AddUntilStep($"Total scores stored is {expected}", () => Realm.Run(r => r.All().Count(s => !s.DeletePending)), () => Is.EqualTo(expected));
+
private static ScoreInfo[] generateSampleScores(BeatmapInfo beatmapInfo)
{
return new[]
From 4fdba880b1efc2dcb49a2f3c64585f2e896a64ba Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Wed, 8 Feb 2023 15:39:18 +0900
Subject: [PATCH 0084/1400] Fix xmldoc reference fail at CI
---
osu.Game/Scoring/ScoreInfo.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs
index 6213c65c75..02c7acf350 100644
--- a/osu.Game/Scoring/ScoreInfo.cs
+++ b/osu.Game/Scoring/ScoreInfo.cs
@@ -41,7 +41,7 @@ namespace osu.Game.Scoring
public BeatmapInfo BeatmapInfo { get; set; } = null!;
///
- /// The at the point in time when the score was set.
+ /// The at the point in time when the score was set.
///
public string BeatmapHash { get; set; } = string.Empty;
From 5e0c4aa904f28435bb2ffad3967f2f4fe2b08802 Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Wed, 8 Feb 2023 11:12:14 +0100
Subject: [PATCH 0085/1400] Refactor pooling for bubbles, tweak the animations
a tad, add some clarifying comments
---
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 231 ++++++++++----------
1 file changed, 114 insertions(+), 117 deletions(-)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index 41430bb323..8cf9c619d7 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -8,13 +8,11 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
-using osu.Framework.Graphics.Performance;
using osu.Framework.Graphics.Pooling;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Localisation;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables;
-using osu.Game.Rulesets.Objects.Pooling;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Rulesets.Osu.Skinning.Default;
@@ -41,7 +39,7 @@ namespace osu.Game.Rulesets.Osu.Mods
public override Type[] IncompatibleMods => new[] { typeof(OsuModBarrelRoll), typeof(OsuModMagnetised), typeof(OsuModRepel) };
private PlayfieldAdjustmentContainer adjustmentContainer = null!;
- private BubbleContainer bubbleContainer = null!;
+ private Container bubbleContainer = null!;
private readonly Bindable currentCombo = new BindableInt();
@@ -49,6 +47,10 @@ namespace osu.Game.Rulesets.Osu.Mods
private float bubbleRadius;
private double bubbleFade;
+ private readonly DrawablePool bubblePool = new DrawablePool(100);
+
+ private DrawableOsuHitObject lastJudgedHitobject = null!;
+
public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank;
public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor)
@@ -56,6 +58,63 @@ namespace osu.Game.Rulesets.Osu.Mods
currentCombo.BindTo(scoreProcessor.Combo);
currentCombo.BindValueChanged(combo =>
maxSize = Math.Min(1.75f, (float)(1.25 + 0.005 * combo.NewValue)), true);
+
+ scoreProcessor.NewJudgement += result =>
+ {
+ if (result.HitObject is not OsuHitObject osuHitObject) return;
+
+ DrawableOsuHitObject drawableOsuHitObject = lastJudgedHitobject;
+
+ switch (result.HitObject)
+ {
+ case Slider:
+ case SpinnerTick:
+ break;
+
+ default:
+ addBubble();
+ break;
+ }
+
+ void addBubble()
+ {
+ BubbleDrawable bubble = bubblePool.Get();
+ bubble.Info = new BubbleInfo
+ {
+ InitialSize = new Vector2(bubbleRadius),
+ MaxSize = maxSize,
+ Position = getPosition(),
+ FadeTime = bubbleFade,
+ Colour = drawableOsuHitObject.AccentColour.Value,
+ IsHit = drawableOsuHitObject.IsHit,
+ };
+ bubbleContainer.Add(bubble);
+ }
+
+ Vector2 getPosition()
+ {
+ switch (drawableOsuHitObject)
+ {
+ // SliderHeads are derived from HitCircles,
+ // so we must handle them before to avoid them using the wrong positioning logic
+ case DrawableSliderHead:
+ return osuHitObject.Position;
+
+ // Using hitobject position will cause issues with HitCircle placement due to stack leniency.
+ case DrawableHitCircle:
+ return drawableOsuHitObject.Position;
+
+ default:
+ return osuHitObject.Position;
+ }
+ }
+ };
+
+ scoreProcessor.JudgementReverted += _ =>
+ {
+ bubbleContainer.LastOrDefault()?.FinishTransforms();
+ bubbleContainer.LastOrDefault()?.Expire();
+ };
}
public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset)
@@ -69,178 +128,116 @@ namespace osu.Game.Rulesets.Osu.Mods
adjustmentContainer = drawableRuleset.CreatePlayfieldAdjustmentContainer();
- adjustmentContainer.Add(bubbleContainer = new BubbleContainer());
+ adjustmentContainer.Add(bubbleContainer = new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ });
drawableRuleset.KeyBindingInputManager.Add(adjustmentContainer);
}
protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state) => applyBubbleState(hitObject);
-
protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject, ArmedState state) => applyBubbleState(hitObject);
private void applyBubbleState(DrawableHitObject drawableObject)
{
+ DrawableOsuHitObject osuHitObject = (DrawableOsuHitObject)drawableObject;
+
if (drawableObject is DrawableSlider slider)
{
slider.Body.OnSkinChanged += () => applySliderState(slider);
applySliderState(slider);
}
- if (drawableObject is not DrawableOsuHitObject drawableOsuObject || !drawableObject.Judged) return;
+ if (osuHitObject == lastJudgedHitobject || !osuHitObject.Judged) return;
- switch (drawableOsuObject)
+ switch (osuHitObject)
{
case DrawableSlider:
case DrawableSpinnerTick:
break;
default:
- addBubbleForObject(drawableOsuObject);
+ lastJudgedHitobject = osuHitObject;
break;
}
}
- // Makes the slider border coloured on all skins
+ // Makes the slider border coloured on all skins (for aesthetics)
private void applySliderState(DrawableSlider slider) =>
((PlaySliderBody)slider.Body.Drawable).BorderColour = slider.AccentColour.Value;
- private void addBubbleForObject(DrawableOsuHitObject hitObject)
- {
- bubbleContainer.Add
- (
- new BubbleLifeTimeEntry
- {
- LifetimeStart = bubbleContainer.Time.Current,
- Colour = hitObject.AccentColour.Value,
- Position = hitObject.HitObject.Position,
- InitialSize = new Vector2(bubbleRadius),
- MaxSize = maxSize,
- FadeTime = bubbleFade,
- IsHit = hitObject.IsHit
- }
- );
- }
-
#region Pooled Bubble drawable
- // LifetimeEntry flow is necessary to allow for correct rewind behaviour, can probably be made generic later if more mods are made requiring it
- // Todo: find solution to bubbles rewinding in "groups"
- private sealed partial class BubbleContainer : PooledDrawableWithLifetimeContainer
- {
- protected override bool RemoveRewoundEntry => true;
-
- private readonly DrawablePool pool;
-
- public BubbleContainer()
- {
- RelativeSizeAxes = Axes.Both;
- AddInternal(pool = new DrawablePool(10, 1000));
- }
-
- protected override BubbleObject GetDrawable(BubbleLifeTimeEntry entry) => pool.Get(d => d.Apply(entry));
- }
-
- private sealed partial class BubbleObject : PoolableDrawableWithLifetime
- {
- private readonly BubbleDrawable bubbleDrawable;
-
- public BubbleObject()
- {
- InternalChild = bubbleDrawable = new BubbleDrawable();
- }
-
- protected override void OnApply(BubbleLifeTimeEntry entry)
- {
- base.OnApply(entry);
- if (IsLoaded)
- apply(entry);
- }
-
- protected override void LoadComplete()
- {
- base.LoadComplete();
- apply(Entry);
- }
-
- private void apply(BubbleLifeTimeEntry? entry)
- {
- if (entry == null) return;
-
- ApplyTransformsAt(float.MinValue, true);
- ClearTransforms(true);
-
- Position = entry.Position;
-
- bubbleDrawable.Animate(entry);
-
- LifetimeEnd = bubbleDrawable.LatestTransformEndTime;
- }
- }
-
- private partial class BubbleDrawable : CircularContainer
+ private partial class BubbleDrawable : PoolableDrawable
{
private readonly Box colourBox;
+ private readonly CircularContainer content;
+
+ public BubbleInfo Info { get; set; }
public BubbleDrawable()
{
- Anchor = Anchor.Centre;
Origin = Anchor.Centre;
-
- MaskingSmoothness = 2;
- BorderThickness = 0;
- BorderColour = Colour4.White;
- Masking = true;
- EdgeEffect = new EdgeEffectParameters
+ InternalChild = content = new CircularContainer
{
- Type = EdgeEffectType.Shadow,
- Radius = 3,
- Colour = Colour4.Black.Opacity(0.05f)
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.Both,
+ MaskingSmoothness = 2,
+ BorderThickness = 0,
+ BorderColour = Colour4.White,
+ Masking = true,
+ EdgeEffect = new EdgeEffectParameters
+ {
+ Type = EdgeEffectType.Shadow,
+ Radius = 3,
+ Colour = Colour4.Black.Opacity(0.05f),
+ },
+ Child = colourBox = new Box { RelativeSizeAxes = Axes.Both, }
};
- Child = colourBox = new Box { RelativeSizeAxes = Axes.Both, };
}
- public void Animate(BubbleLifeTimeEntry entry)
+ protected override void PrepareForUse()
{
- Size = entry.InitialSize;
- BorderThickness = Width / 3.5f;
+ Alpha = 1;
+ Colour = Colour4.White;
+ Scale = new Vector2(1);
+ Position = Info.Position;
+ Size = Info.InitialSize;
+ content.BorderThickness = Info.InitialSize.X / 3.5f;
+ content.BorderColour = Colour4.White;
//We want to fade to a darker colour to avoid colours such as white hiding the "ripple" effect.
- ColourInfo colourDarker = entry.Colour.Darken(0.1f);
+ ColourInfo colourDarker = Info.Colour.Darken(0.1f);
// Main bubble scaling based on combo
- this.ScaleTo(entry.MaxSize, getAnimationDuration() * 0.8f)
+ this.ScaleTo(Info.MaxSize, getAnimationDuration() * 0.8f)
.Then()
// Pop at the end of the bubbles life time
- .ScaleTo(entry.MaxSize * 1.5f, getAnimationDuration() * 0.2f, Easing.OutQuint)
- .FadeTo(0, getAnimationDuration() * 0.2f, Easing.OutCirc);
+ .ScaleTo(Info.MaxSize * 1.5f, getAnimationDuration() * 0.2f, Easing.OutQuint)
+ .FadeOutFromOne(getAnimationDuration() * 0.2f, Easing.OutCirc).Expire();
- if (!entry.IsHit)
+ if (Info.IsHit)
{
- Colour = Colour4.Black;
- BorderColour = Colour4.Black;
+ colourBox.FadeColour(colourDarker);
+
+ content.TransformTo(nameof(BorderColour), colourDarker, getAnimationDuration() * 0.3f, Easing.OutQuint);
+ // Ripple effect utilises the border to reduce drawable count
+ content.TransformTo(nameof(BorderThickness), 2f, getAnimationDuration() * 0.3f, Easing.OutQuint)
+ // Avoids transparency overlap issues during the bubble "pop"
+ .Then().Schedule(() => content.BorderThickness = 0);
return;
}
- colourBox.FadeColour(colourDarker);
-
- this.TransformTo(nameof(BorderColour), colourDarker, getAnimationDuration() * 0.3f, Easing.OutQuint);
-
- // Ripple effect utilises the border to reduce drawable count
- this.TransformTo(nameof(BorderThickness), 2f, getAnimationDuration() * 0.3f, Easing.OutQuint)
-
- // Avoids transparency overlap issues during the bubble "pop"
- .Then().Schedule(() =>
- {
- BorderThickness = 0;
- BorderColour = Colour4.Transparent;
- });
+ Colour = Colour4.Black;
// The absolute length of the bubble's animation, can be used in fractions for animations of partial length
- double getAnimationDuration() => 1700 + Math.Pow(entry.FadeTime, 1.07f);
+ double getAnimationDuration() => 1700 + Math.Pow(Info.FadeTime, 1.07f);
}
}
- private class BubbleLifeTimeEntry : LifetimeEntry
+ private struct BubbleInfo
{
public Vector2 InitialSize { get; set; }
From 6ff6e06a69256987d7a409a154c021df9988df30 Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Sun, 12 Feb 2023 11:37:07 +0100
Subject: [PATCH 0086/1400] Simplify bubble container structure, modify some
comments
---
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 16 ++++++----------
1 file changed, 6 insertions(+), 10 deletions(-)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index 8cf9c619d7..3e3fce5c27 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -38,8 +38,7 @@ namespace osu.Game.Rulesets.Osu.Mods
// Compatibility with these seems potentially feasible in the future, blocked for now because they don't work as one would expect
public override Type[] IncompatibleMods => new[] { typeof(OsuModBarrelRoll), typeof(OsuModMagnetised), typeof(OsuModRepel) };
- private PlayfieldAdjustmentContainer adjustmentContainer = null!;
- private Container bubbleContainer = null!;
+ private PlayfieldAdjustmentContainer bubbleContainer = null!;
private readonly Bindable currentCombo = new BindableInt();
@@ -119,20 +118,17 @@ namespace osu.Game.Rulesets.Osu.Mods
public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset)
{
- // Multiplying by 2 results in an initial size that is too large, hence 1.85 has been chosen
- bubbleRadius = (float)(drawableRuleset.Beatmap.HitObjects.OfType().First().Radius * 1.85f);
+ // Multiplying by 2 results in an initial size that is too large, hence 1.90 has been chosen
+ // Also avoids the HitObject bleeding around the edges of the bubble drawable at minimum size
+ bubbleRadius = (float)(drawableRuleset.Beatmap.HitObjects.OfType().First().Radius * 1.90f);
bubbleFade = drawableRuleset.Beatmap.HitObjects.OfType().First().TimePreempt * 2;
// We want to hide the judgements since they are obscured by the BubbleDrawable (due to layering)
drawableRuleset.Playfield.DisplayJudgements.Value = false;
- adjustmentContainer = drawableRuleset.CreatePlayfieldAdjustmentContainer();
+ bubbleContainer = drawableRuleset.CreatePlayfieldAdjustmentContainer();
- adjustmentContainer.Add(bubbleContainer = new Container
- {
- RelativeSizeAxes = Axes.Both,
- });
- drawableRuleset.KeyBindingInputManager.Add(adjustmentContainer);
+ drawableRuleset.KeyBindingInputManager.Add(bubbleContainer);
}
protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state) => applyBubbleState(hitObject);
From 74a58fb674945a5ec82f20ca2bffff91b6de776c Mon Sep 17 00:00:00 2001
From: tsrk
Date: Mon, 13 Feb 2023 01:24:27 +0000
Subject: [PATCH 0087/1400] refactor: separate things in KeyCounter
To implement different different sources of input for KeyCounter, it
is now possible to create a Trigger class (to inherit) instead of
inheriting KeyCounter. This eases the creation of more input sources
(like for tests) while allowing to implement different UI variants.
That way, if another variant of the key counter needs to implemented
(for whathever reason), this can be done by only inheriting KeyCounter
and changing how things are arranged visually.
---
osu.Game/Rulesets/UI/RulesetInputManager.cs | 9 +-
osu.Game/Screens/Play/DefaultKeyCounter.cs | 105 +++++++++++++
osu.Game/Screens/Play/KeyCounter.cs | 157 +++++++-------------
osu.Game/Screens/Play/KeyCounterAction.cs | 10 +-
osu.Game/Screens/Play/KeyCounterKeyboard.cs | 11 +-
osu.Game/Screens/Play/KeyCounterMouse.cs | 11 +-
6 files changed, 177 insertions(+), 126 deletions(-)
create mode 100644 osu.Game/Screens/Play/DefaultKeyCounter.cs
diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs
index a5e442b7de..0fa1f0b332 100644
--- a/osu.Game/Rulesets/UI/RulesetInputManager.cs
+++ b/osu.Game/Rulesets/UI/RulesetInputManager.cs
@@ -166,7 +166,7 @@ namespace osu.Game.Rulesets.UI
.Select(b => b.GetAction())
.Distinct()
.OrderBy(action => action)
- .Select(action => new KeyCounterAction(action)));
+ .Select(action => keyCounter.CreateKeyCounter(new KeyCounterAction(action))));
}
private partial class ActionReceptor : KeyCounterDisplay.Receptor, IKeyBindingHandler
@@ -176,11 +176,14 @@ namespace osu.Game.Rulesets.UI
{
}
- public bool OnPressed(KeyBindingPressEvent e) => Target.Children.OfType>().Any(c => c.OnPressed(e.Action, Clock.Rate >= 0));
+ public bool OnPressed(KeyBindingPressEvent e) => Target.Children.Where(c => c.CounterTrigger is KeyCounterAction)
+ .Select(c => (KeyCounterAction)c.CounterTrigger)
+ .Any(c => c.OnPressed(e.Action, Clock.Rate >= 0));
public void OnReleased(KeyBindingReleaseEvent e)
{
- foreach (var c in Target.Children.OfType>())
+ foreach (var c
+ in Target.Children.Where(c => c.CounterTrigger is KeyCounterAction).Select(c => (KeyCounterAction)c.CounterTrigger))
c.OnReleased(e.Action, Clock.Rate >= 0);
}
}
diff --git a/osu.Game/Screens/Play/DefaultKeyCounter.cs b/osu.Game/Screens/Play/DefaultKeyCounter.cs
new file mode 100644
index 0000000000..dcb425ae1d
--- /dev/null
+++ b/osu.Game/Screens/Play/DefaultKeyCounter.cs
@@ -0,0 +1,105 @@
+// Copyright (c) ppy Pty Ltd . 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.Framework.Graphics.Sprites;
+using osu.Framework.Graphics.Textures;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Sprites;
+using osuTK;
+using osuTK.Graphics;
+
+namespace osu.Game.Screens.Play
+{
+ public partial class DefaultKeyCounter : KeyCounter
+ {
+ private Sprite buttonSprite = null!;
+ private Sprite glowSprite = null!;
+ private Container textLayer = null!;
+ private SpriteText countSpriteText = null!;
+
+ //further: change default values here and in KeyCounterCollection if needed, instead of passing them in every constructor
+ public Color4 KeyDownTextColor { get; set; } = Color4.DarkGray;
+ public Color4 KeyUpTextColor { get; set; } = Color4.White;
+ public double FadeTime { get; set; }
+
+ public DefaultKeyCounter(Trigger trigger)
+ : base(trigger)
+ {
+ }
+
+ [BackgroundDependencyLoader(true)]
+ private void load(TextureStore textures)
+ {
+ Children = new Drawable[]
+ {
+ buttonSprite = new Sprite
+ {
+ Texture = textures.Get(@"KeyCounter/key-up"),
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ },
+ glowSprite = new Sprite
+ {
+ Texture = textures.Get(@"KeyCounter/key-glow"),
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Alpha = 0
+ },
+ textLayer = new Container
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.Both,
+ Children = new Drawable[]
+ {
+ new OsuSpriteText
+ {
+ Text = Name,
+ Font = OsuFont.Numeric.With(size: 12),
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ RelativePositionAxes = Axes.Both,
+ Position = new Vector2(0, -0.25f),
+ Colour = KeyUpTextColor
+ },
+ countSpriteText = new OsuSpriteText
+ {
+ Text = CountPresses.ToString(@"#,0"),
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ RelativePositionAxes = Axes.Both,
+ Position = new Vector2(0, 0.25f),
+ Colour = KeyUpTextColor
+ }
+ }
+ }
+ };
+ // Set this manually because an element with Alpha=0 won't take it size to AutoSizeContainer,
+ // so the size can be changing between buttonSprite and glowSprite.
+ Height = buttonSprite.DrawHeight;
+ Width = buttonSprite.DrawWidth;
+
+ IsLit.BindValueChanged(e => updateGlowSprite(e.NewValue), true);
+ PressesCount.BindValueChanged(e => countSpriteText.Text = e.NewValue.ToString(@"#,0"), true);
+ }
+
+ private void updateGlowSprite(bool show)
+ {
+ if (show)
+ {
+ double remainingFadeTime = FadeTime * (1 - glowSprite.Alpha);
+ glowSprite.FadeIn(remainingFadeTime, Easing.OutQuint);
+ textLayer.FadeColour(KeyDownTextColor, remainingFadeTime, Easing.OutQuint);
+ }
+ else
+ {
+ double remainingFadeTime = 8 * FadeTime * glowSprite.Alpha;
+ glowSprite.FadeOut(remainingFadeTime, Easing.OutQuint);
+ textLayer.FadeColour(KeyUpTextColor, remainingFadeTime, Easing.OutQuint);
+ }
+ }
+ }
+}
diff --git a/osu.Game/Screens/Play/KeyCounter.cs b/osu.Game/Screens/Play/KeyCounter.cs
index 4405542b3b..a612edbace 100644
--- a/osu.Game/Screens/Play/KeyCounter.cs
+++ b/osu.Game/Screens/Play/KeyCounter.cs
@@ -1,57 +1,37 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
-using osu.Framework.Allocation;
+using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
-using osu.Framework.Graphics.Textures;
-using osu.Game.Graphics;
-using osu.Game.Graphics.Sprites;
-using osuTK;
-using osuTK.Graphics;
+using osu.Framework.Input.Events;
namespace osu.Game.Screens.Play
{
public abstract partial class KeyCounter : Container
{
- private Sprite buttonSprite;
- private Sprite glowSprite;
- private Container textLayer;
- private SpriteText countSpriteText;
+ public readonly Trigger CounterTrigger;
- public bool IsCounting { get; set; } = true;
- private int countPresses;
+ protected Bindable IsCountingBindable = new BindableBool(true);
+
+ protected Bindable PressesCount = new BindableInt
+ {
+ MinValue = 0
+ };
+
+ public bool IsCounting
+ {
+ get => IsCountingBindable.Value;
+ set => IsCountingBindable.Value = value;
+ }
public int CountPresses
{
- get => countPresses;
- private set
- {
- if (countPresses != value)
- {
- countPresses = value;
- countSpriteText.Text = value.ToString(@"#,0");
- }
- }
+ get => PressesCount.Value;
+ private set => PressesCount.Value = value;
}
- private bool isLit;
-
- public bool IsLit
- {
- get => isLit;
- protected set
- {
- if (isLit != value)
- {
- isLit = value;
- updateGlowSprite(value);
- }
- }
- }
+ protected Bindable IsLit = new BindableBool();
public void Increment()
{
@@ -69,82 +49,51 @@ namespace osu.Game.Screens.Play
CountPresses--;
}
- //further: change default values here and in KeyCounterCollection if needed, instead of passing them in every constructor
- public Color4 KeyDownTextColor { get; set; } = Color4.DarkGray;
- public Color4 KeyUpTextColor { get; set; } = Color4.White;
- public double FadeTime { get; set; }
-
- protected KeyCounter(string name)
+ protected override void LoadComplete()
{
- Name = name;
+ Add(CounterTrigger);
+ base.LoadComplete();
}
- [BackgroundDependencyLoader(true)]
- private void load(TextureStore textures)
+ protected override bool Handle(UIEvent e) => CounterTrigger.TriggerEvent(e);
+
+ protected KeyCounter(Trigger trigger)
{
- Children = new Drawable[]
- {
- buttonSprite = new Sprite
- {
- Texture = textures.Get(@"KeyCounter/key-up"),
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- },
- glowSprite = new Sprite
- {
- Texture = textures.Get(@"KeyCounter/key-glow"),
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- Alpha = 0
- },
- textLayer = new Container
- {
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- RelativeSizeAxes = Axes.Both,
- Children = new Drawable[]
- {
- new OsuSpriteText
- {
- Text = Name,
- Font = OsuFont.Numeric.With(size: 12),
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- RelativePositionAxes = Axes.Both,
- Position = new Vector2(0, -0.25f),
- Colour = KeyUpTextColor
- },
- countSpriteText = new OsuSpriteText
- {
- Text = CountPresses.ToString(@"#,0"),
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- RelativePositionAxes = Axes.Both,
- Position = new Vector2(0, 0.25f),
- Colour = KeyUpTextColor
- }
- }
- }
- };
- // Set this manually because an element with Alpha=0 won't take it size to AutoSizeContainer,
- // so the size can be changing between buttonSprite and glowSprite.
- Height = buttonSprite.DrawHeight;
- Width = buttonSprite.DrawWidth;
+ CounterTrigger = trigger;
+ trigger.Target = this;
+ Name = trigger.Name;
}
- private void updateGlowSprite(bool show)
+ public abstract partial class Trigger : Component
{
- if (show)
+ private KeyCounter? target;
+
+ public KeyCounter Target
{
- double remainingFadeTime = FadeTime * (1 - glowSprite.Alpha);
- glowSprite.FadeIn(remainingFadeTime, Easing.OutQuint);
- textLayer.FadeColour(KeyDownTextColor, remainingFadeTime, Easing.OutQuint);
+ set => target = value;
}
- else
+
+ protected Trigger(string name)
{
- double remainingFadeTime = 8 * FadeTime * glowSprite.Alpha;
- glowSprite.FadeOut(remainingFadeTime, Easing.OutQuint);
- textLayer.FadeColour(KeyUpTextColor, remainingFadeTime, Easing.OutQuint);
+ Name = name;
+ }
+
+ protected void Lit(bool increment = true)
+ {
+ if (target == null) return;
+
+ target.IsLit.Value = true;
+ if (increment)
+ target.Increment();
+ }
+
+ protected void Unlit(bool preserve = true)
+ {
+ if (target == null) return;
+
+ target.IsLit.Value = false;
+ if (!preserve)
+ target.Decrement();
}
}
}
diff --git a/osu.Game/Screens/Play/KeyCounterAction.cs b/osu.Game/Screens/Play/KeyCounterAction.cs
index 900d9bcd0e..058dbb1480 100644
--- a/osu.Game/Screens/Play/KeyCounterAction.cs
+++ b/osu.Game/Screens/Play/KeyCounterAction.cs
@@ -7,7 +7,7 @@ using System.Collections.Generic;
namespace osu.Game.Screens.Play
{
- public partial class KeyCounterAction : KeyCounter
+ public partial class KeyCounterAction : KeyCounter.Trigger
where T : struct
{
public T Action { get; }
@@ -23,9 +23,7 @@ namespace osu.Game.Screens.Play
if (!EqualityComparer.Default.Equals(action, Action))
return false;
- IsLit = true;
- if (forwards)
- Increment();
+ Lit(forwards);
return false;
}
@@ -34,9 +32,7 @@ namespace osu.Game.Screens.Play
if (!EqualityComparer.Default.Equals(action, Action))
return;
- IsLit = false;
- if (!forwards)
- Decrement();
+ Unlit(forwards);
}
}
}
diff --git a/osu.Game/Screens/Play/KeyCounterKeyboard.cs b/osu.Game/Screens/Play/KeyCounterKeyboard.cs
index c5c8b7eeae..4306efd360 100644
--- a/osu.Game/Screens/Play/KeyCounterKeyboard.cs
+++ b/osu.Game/Screens/Play/KeyCounterKeyboard.cs
@@ -8,7 +8,7 @@ using osuTK.Input;
namespace osu.Game.Screens.Play
{
- public partial class KeyCounterKeyboard : KeyCounter
+ public partial class KeyCounterKeyboard : KeyCounter.Trigger
{
public Key Key { get; }
@@ -21,17 +21,16 @@ namespace osu.Game.Screens.Play
protected override bool OnKeyDown(KeyDownEvent e)
{
if (e.Key == Key)
- {
- IsLit = true;
- Increment();
- }
+ Lit();
return base.OnKeyDown(e);
}
protected override void OnKeyUp(KeyUpEvent e)
{
- if (e.Key == Key) IsLit = false;
+ if (e.Key == Key)
+ Unlit();
+
base.OnKeyUp(e);
}
}
diff --git a/osu.Game/Screens/Play/KeyCounterMouse.cs b/osu.Game/Screens/Play/KeyCounterMouse.cs
index cf9c7c029f..00fca47ba2 100644
--- a/osu.Game/Screens/Play/KeyCounterMouse.cs
+++ b/osu.Game/Screens/Play/KeyCounterMouse.cs
@@ -9,7 +9,7 @@ using osuTK;
namespace osu.Game.Screens.Play
{
- public partial class KeyCounterMouse : KeyCounter
+ public partial class KeyCounterMouse : KeyCounter.Trigger
{
public MouseButton Button { get; }
@@ -39,17 +39,16 @@ namespace osu.Game.Screens.Play
protected override bool OnMouseDown(MouseDownEvent e)
{
if (e.Button == Button)
- {
- IsLit = true;
- Increment();
- }
+ Lit();
return base.OnMouseDown(e);
}
protected override void OnMouseUp(MouseUpEvent e)
{
- if (e.Button == Button) IsLit = false;
+ if (e.Button == Button)
+ Unlit();
+
base.OnMouseUp(e);
}
}
From 11d0e185b8188d0986f4520131a14ba95ab2322f Mon Sep 17 00:00:00 2001
From: tsrk
Date: Mon, 13 Feb 2023 01:33:09 +0000
Subject: [PATCH 0088/1400] refactor: separate impl of KeyCounterDisplay
This allows for different layouts of display. Idk, maybe someone would
want to mix both variants? (don't do this please). This commit is mostly
prep for further changes.
---
.../TestSceneOsuTouchInput.cs | 16 ++--
.../Visual/Gameplay/TestSceneHUDOverlay.cs | 2 +-
.../Visual/Gameplay/TestSceneKeyCounter.cs | 18 ++--
.../TestSceneSkinEditorMultipleSkins.cs | 2 +-
.../Gameplay/TestSceneSkinnableHUDOverlay.cs | 2 +-
.../Screens/Play/DefaultKeyCounterDisplay.cs | 91 +++++++++++++++++++
osu.Game/Screens/Play/HUDOverlay.cs | 2 +-
osu.Game/Screens/Play/KeyCounterDisplay.cs | 76 ++--------------
8 files changed, 121 insertions(+), 88 deletions(-)
create mode 100644 osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
index 72bcec6045..cd30d8df83 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
@@ -34,9 +34,9 @@ namespace osu.Game.Rulesets.Osu.Tests
[Resolved]
private OsuConfigManager config { get; set; } = null!;
- private TestActionKeyCounter leftKeyCounter = null!;
+ private DefaultKeyCounter leftKeyCounter = null!;
- private TestActionKeyCounter rightKeyCounter = null!;
+ private DefaultKeyCounter rightKeyCounter = null!;
private OsuInputManager osuInputManager = null!;
@@ -59,14 +59,14 @@ namespace osu.Game.Rulesets.Osu.Tests
Origin = Anchor.Centre,
Children = new Drawable[]
{
- leftKeyCounter = new TestActionKeyCounter(OsuAction.LeftButton)
+ leftKeyCounter = new DefaultKeyCounter(new TestActionKeyCounter(OsuAction.LeftButton))
{
Anchor = Anchor.Centre,
Origin = Anchor.CentreRight,
Depth = float.MinValue,
X = -100,
},
- rightKeyCounter = new TestActionKeyCounter(OsuAction.RightButton)
+ rightKeyCounter = new DefaultKeyCounter(new TestActionKeyCounter(OsuAction.RightButton))
{
Anchor = Anchor.Centre,
Origin = Anchor.CentreLeft,
@@ -579,7 +579,7 @@ namespace osu.Game.Rulesets.Osu.Tests
private void checkNotPressed(OsuAction action) => AddAssert($"Not pressing {action}", () => !osuInputManager.PressedActions.Contains(action));
private void checkPressed(OsuAction action) => AddAssert($"Is pressing {action}", () => osuInputManager.PressedActions.Contains(action));
- public partial class TestActionKeyCounter : KeyCounter, IKeyBindingHandler
+ public partial class TestActionKeyCounter : KeyCounter.Trigger, IKeyBindingHandler
{
public OsuAction Action { get; }
@@ -593,8 +593,7 @@ namespace osu.Game.Rulesets.Osu.Tests
{
if (e.Action == Action)
{
- IsLit = true;
- Increment();
+ Lit();
}
return false;
@@ -602,7 +601,8 @@ namespace osu.Game.Rulesets.Osu.Tests
public void OnReleased(KeyBindingReleaseEvent e)
{
- if (e.Action == Action) IsLit = false;
+ if (e.Action == Action)
+ Unlit();
}
}
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs
index 5e1412d79b..4055ef9d3a 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs
@@ -267,7 +267,7 @@ namespace osu.Game.Tests.Visual.Gameplay
hudOverlay = new HUDOverlay(null, Array.Empty());
// Add any key just to display the key counter visually.
- hudOverlay.KeyCounter.Add(new KeyCounterKeyboard(Key.Space));
+ hudOverlay.KeyCounter.Add(hudOverlay.KeyCounter.CreateKeyCounter(new KeyCounterKeyboard(Key.Space)));
scoreProcessor.Combo.Value = 1;
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs
index 890ac21b40..60ebce4f52 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs
@@ -17,28 +17,28 @@ namespace osu.Game.Tests.Visual.Gameplay
{
public TestSceneKeyCounter()
{
- KeyCounterKeyboard testCounter;
+ DefaultKeyCounter testCounter;
- KeyCounterDisplay kc = new KeyCounterDisplay
+ KeyCounterDisplay kc = new DefaultKeyCounterDisplay
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
- Children = new KeyCounter[]
+ Children = new[]
{
- testCounter = new KeyCounterKeyboard(Key.X),
- new KeyCounterKeyboard(Key.X),
- new KeyCounterMouse(MouseButton.Left),
- new KeyCounterMouse(MouseButton.Right),
+ testCounter = new DefaultKeyCounter(new KeyCounterKeyboard(Key.X)),
+ new DefaultKeyCounter(new KeyCounterKeyboard(Key.X)),
+ new DefaultKeyCounter(new KeyCounterMouse(MouseButton.Left)),
+ new DefaultKeyCounter(new KeyCounterMouse(MouseButton.Right)),
},
};
AddStep("Add random", () =>
{
Key key = (Key)((int)Key.A + RNG.Next(26));
- kc.Add(new KeyCounterKeyboard(key));
+ kc.Add(kc.CreateKeyCounter(new KeyCounterKeyboard(key)));
});
- Key testKey = ((KeyCounterKeyboard)kc.Children.First()).Key;
+ Key testKey = ((KeyCounterKeyboard)kc.Children.First().CounterTrigger).Key;
void addPressKeyStep()
{
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs
index d5b6ac38cb..56cf56efd9 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs
@@ -53,7 +53,7 @@ namespace osu.Game.Tests.Visual.Gameplay
};
// Add any key just to display the key counter visually.
- hudOverlay.KeyCounter.Add(new KeyCounterKeyboard(Key.Space));
+ hudOverlay.KeyCounter.Add(hudOverlay.KeyCounter.CreateKeyCounter(new KeyCounterKeyboard(Key.Space)));
scoreProcessor.Combo.Value = 1;
return new Container
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs
index 1f2329af4a..f713bca081 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs
@@ -88,7 +88,7 @@ namespace osu.Game.Tests.Visual.Gameplay
hudOverlay = new HUDOverlay(null, Array.Empty());
// Add any key just to display the key counter visually.
- hudOverlay.KeyCounter.Add(new KeyCounterKeyboard(Key.Space));
+ hudOverlay.KeyCounter.Add(hudOverlay.KeyCounter.CreateKeyCounter(new KeyCounterKeyboard(Key.Space)));
action?.Invoke(hudOverlay);
diff --git a/osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs b/osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs
new file mode 100644
index 0000000000..d643070e06
--- /dev/null
+++ b/osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs
@@ -0,0 +1,91 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osuTK.Graphics;
+
+namespace osu.Game.Screens.Play
+{
+ public partial class DefaultKeyCounterDisplay : KeyCounterDisplay
+ {
+ private const int duration = 100;
+ private const double key_fade_time = 80;
+
+ protected override Container Content => KeyFlow;
+
+ public new IReadOnlyList Children
+ {
+ get => (IReadOnlyList)base.Children;
+ set => base.Children = value;
+ }
+
+ public DefaultKeyCounterDisplay()
+ {
+ InternalChild = KeyFlow = new FillFlowContainer
+ {
+ Direction = FillDirection.Horizontal,
+ AutoSizeAxes = Axes.Both,
+ Alpha = 0,
+ };
+ }
+
+ protected override void Update()
+ {
+ base.Update();
+
+ // Don't use autosize as it will shrink to zero when KeyFlow is hidden.
+ // In turn this can cause the display to be masked off screen and never become visible again.
+ Size = KeyFlow.Size;
+ }
+
+ public override void Add(KeyCounter key)
+ {
+ base.Add(key);
+ if (key is not DefaultKeyCounter defaultKey)
+ throw new ArgumentException($"{key.GetType()} is not a supported {nameof(KeyCounter)}.", nameof(key));
+
+ defaultKey.FadeTime = key_fade_time;
+ defaultKey.KeyDownTextColor = KeyDownTextColor;
+ defaultKey.KeyUpTextColor = KeyUpTextColor;
+ }
+
+ protected override void UpdateVisibility() =>
+ // Isolate changing visibility of the key counters from fading this component.
+ KeyFlow.FadeTo(AlwaysVisible.Value || ConfigVisibility.Value ? 1 : 0, duration);
+
+ private Color4 keyDownTextColor = Color4.DarkGray;
+
+ public Color4 KeyDownTextColor
+ {
+ get => keyDownTextColor;
+ set
+ {
+ if (value != keyDownTextColor)
+ {
+ keyDownTextColor = value;
+ foreach (var child in Children)
+ child.KeyDownTextColor = value;
+ }
+ }
+ }
+
+ private Color4 keyUpTextColor = Color4.White;
+
+ public Color4 KeyUpTextColor
+ {
+ get => keyUpTextColor;
+ set
+ {
+ if (value != keyUpTextColor)
+ {
+ keyUpTextColor = value;
+ foreach (var child in Children)
+ child.KeyUpTextColor = value;
+ }
+ }
+ }
+ }
+}
diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs
index 4d1f0b96b6..a09da14132 100644
--- a/osu.Game/Screens/Play/HUDOverlay.cs
+++ b/osu.Game/Screens/Play/HUDOverlay.cs
@@ -327,7 +327,7 @@ namespace osu.Game.Screens.Play
ShowHealth = { BindTarget = ShowHealthBar }
};
- protected KeyCounterDisplay CreateKeyCounter() => new KeyCounterDisplay
+ protected KeyCounterDisplay CreateKeyCounter() => new DefaultKeyCounterDisplay
{
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight,
diff --git a/osu.Game/Screens/Play/KeyCounterDisplay.cs b/osu.Game/Screens/Play/KeyCounterDisplay.cs
index bb50d4a539..b06d1adfa0 100644
--- a/osu.Game/Screens/Play/KeyCounterDisplay.cs
+++ b/osu.Game/Screens/Play/KeyCounterDisplay.cs
@@ -12,18 +12,14 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Events;
using osu.Game.Configuration;
using osuTK;
-using osuTK.Graphics;
namespace osu.Game.Screens.Play
{
- public partial class KeyCounterDisplay : Container
+ public abstract partial class KeyCounterDisplay : Container
{
- private const int duration = 100;
- private const double key_fade_time = 80;
+ protected readonly Bindable ConfigVisibility = new Bindable();
- private readonly Bindable configVisibility = new Bindable();
-
- protected readonly FillFlowContainer KeyFlow;
+ protected FillFlowContainer KeyFlow;
protected override Container Content => KeyFlow;
@@ -33,48 +29,26 @@ namespace osu.Game.Screens.Play
///
public readonly Bindable AlwaysVisible = new Bindable(true);
- public KeyCounterDisplay()
- {
- InternalChild = KeyFlow = new FillFlowContainer
- {
- Direction = FillDirection.Horizontal,
- AutoSizeAxes = Axes.Both,
- Alpha = 0,
- };
- }
-
- protected override void Update()
- {
- base.Update();
-
- // Don't use autosize as it will shrink to zero when KeyFlow is hidden.
- // In turn this can cause the display to be masked off screen and never become visible again.
- Size = KeyFlow.Size;
- }
-
public override void Add(KeyCounter key)
{
ArgumentNullException.ThrowIfNull(key);
base.Add(key);
key.IsCounting = IsCounting;
- key.FadeTime = key_fade_time;
- key.KeyDownTextColor = KeyDownTextColor;
- key.KeyUpTextColor = KeyUpTextColor;
}
[BackgroundDependencyLoader]
private void load(OsuConfigManager config)
{
- config.BindWith(OsuSetting.KeyOverlay, configVisibility);
+ config.BindWith(OsuSetting.KeyOverlay, ConfigVisibility);
}
protected override void LoadComplete()
{
base.LoadComplete();
- AlwaysVisible.BindValueChanged(_ => updateVisibility());
- configVisibility.BindValueChanged(_ => updateVisibility(), true);
+ AlwaysVisible.BindValueChanged(_ => UpdateVisibility());
+ ConfigVisibility.BindValueChanged(_ => UpdateVisibility(), true);
}
private bool isCounting = true;
@@ -92,41 +66,7 @@ namespace osu.Game.Screens.Play
}
}
- private Color4 keyDownTextColor = Color4.DarkGray;
-
- public Color4 KeyDownTextColor
- {
- get => keyDownTextColor;
- set
- {
- if (value != keyDownTextColor)
- {
- keyDownTextColor = value;
- foreach (var child in Children)
- child.KeyDownTextColor = value;
- }
- }
- }
-
- private Color4 keyUpTextColor = Color4.White;
-
- public Color4 KeyUpTextColor
- {
- get => keyUpTextColor;
- set
- {
- if (value != keyUpTextColor)
- {
- keyUpTextColor = value;
- foreach (var child in Children)
- child.KeyUpTextColor = value;
- }
- }
- }
-
- private void updateVisibility() =>
- // Isolate changing visibility of the key counters from fading this component.
- KeyFlow.FadeTo(AlwaysVisible.Value || configVisibility.Value ? 1 : 0, duration);
+ protected abstract void UpdateVisibility();
public override bool HandleNonPositionalInput => receptor == null;
public override bool HandlePositionalInput => receptor == null;
@@ -141,6 +81,8 @@ namespace osu.Game.Screens.Play
this.receptor = receptor;
}
+ public virtual KeyCounter CreateKeyCounter(KeyCounter.Trigger trigger) => new DefaultKeyCounter(trigger);
+
public partial class Receptor : Drawable
{
protected readonly KeyCounterDisplay Target;
From aa2e0028ab3c20cb4e0afe412e12670e3b14f96f Mon Sep 17 00:00:00 2001
From: tsrk
Date: Mon, 13 Feb 2023 10:59:10 +0000
Subject: [PATCH 0089/1400] refactor: hide trigger presence from content
---
osu.Game/Screens/Play/KeyCounter.cs | 32 +++++++++++++++++------------
1 file changed, 19 insertions(+), 13 deletions(-)
diff --git a/osu.Game/Screens/Play/KeyCounter.cs b/osu.Game/Screens/Play/KeyCounter.cs
index a612edbace..b111305b22 100644
--- a/osu.Game/Screens/Play/KeyCounter.cs
+++ b/osu.Game/Screens/Play/KeyCounter.cs
@@ -14,6 +14,10 @@ namespace osu.Game.Screens.Play
protected Bindable IsCountingBindable = new BindableBool(true);
+ private readonly Container content;
+
+ protected override Container Content => content;
+
protected Bindable PressesCount = new BindableInt
{
MinValue = 0
@@ -31,6 +35,21 @@ namespace osu.Game.Screens.Play
private set => PressesCount.Value = value;
}
+ protected KeyCounter(Trigger trigger)
+ {
+ InternalChildren = new Drawable[]
+ {
+ content = new Container
+ {
+ RelativeSizeAxes = Axes.Both
+ },
+ CounterTrigger = trigger,
+ };
+
+ CounterTrigger.Target = this;
+ Name = trigger.Name;
+ }
+
protected Bindable IsLit = new BindableBool();
public void Increment()
@@ -49,21 +68,8 @@ namespace osu.Game.Screens.Play
CountPresses--;
}
- protected override void LoadComplete()
- {
- Add(CounterTrigger);
- base.LoadComplete();
- }
-
protected override bool Handle(UIEvent e) => CounterTrigger.TriggerEvent(e);
- protected KeyCounter(Trigger trigger)
- {
- CounterTrigger = trigger;
- trigger.Target = this;
- Name = trigger.Name;
- }
-
public abstract partial class Trigger : Component
{
private KeyCounter? target;
From 7aaaf7fca2d598998d7c407a3b259db985484b06 Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Tue, 14 Feb 2023 16:55:35 +0900
Subject: [PATCH 0090/1400] Combine and attempt to simplify the score import /
preparation process further
---
osu.Game/Rulesets/UI/RulesetInputManager.cs | 3 +
osu.Game/Screens/Play/Player.cs | 82 ++++++++++-----------
2 files changed, 43 insertions(+), 42 deletions(-)
diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs
index a5e442b7de..7bf0482673 100644
--- a/osu.Game/Rulesets/UI/RulesetInputManager.cs
+++ b/osu.Game/Rulesets/UI/RulesetInputManager.cs
@@ -39,6 +39,9 @@ namespace osu.Game.Rulesets.UI
{
set
{
+ if (value == recorder)
+ return;
+
if (value != null && recorder != null)
throw new InvalidOperationException("Cannot attach more than one recorder");
diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs
index 0825f36a0a..bc453d2151 100644
--- a/osu.Game/Screens/Play/Player.cs
+++ b/osu.Game/Screens/Play/Player.cs
@@ -276,7 +276,7 @@ namespace osu.Game.Screens.Play
},
FailOverlay = new FailOverlay
{
- SaveReplay = prepareAndImportScore,
+ SaveReplay = async () => await prepareAndImportScoreAsync(true).ConfigureAwait(false),
OnRetry = () => Restart(),
OnQuit = () => PerformExit(true),
},
@@ -614,7 +614,7 @@ namespace osu.Game.Screens.Play
resultsDisplayDelegate?.Cancel();
// import current score if possible.
- attemptScoreImport();
+ prepareAndImportScoreAsync();
// The actual exit is performed if
// - the pause / fail dialog was not requested
@@ -772,10 +772,7 @@ namespace osu.Game.Screens.Play
if (prepareScoreForDisplayTask == null)
{
// Try importing score since the task hasn't been invoked yet.
- if (!attemptScoreImport())
- // If attempt failed, trying again is unnecessary
- resultsDisplayDelegate?.Cancel();
-
+ prepareAndImportScoreAsync();
return;
}
@@ -785,6 +782,12 @@ namespace osu.Game.Screens.Play
resultsDisplayDelegate?.Cancel();
+ if (prepareScoreForDisplayTask.GetResultSafely() == null)
+ {
+ // If score import did not occur, we do not want to show the results screen.
+ return;
+ }
+
if (!this.IsCurrentScreen())
// This player instance may already be in the process of exiting.
return;
@@ -796,53 +799,48 @@ namespace osu.Game.Screens.Play
}
///
- /// Attempts to run
+ /// Asynchronously run score preparation operations (database import, online submission etc.).
///
- ///
- /// Whether the attempt was successful
- ///
- private bool attemptScoreImport()
+ /// Whether the score should be imported even if non-passing (or the current configuration doesn't allow for it).
+ /// The final score.
+ [ItemCanBeNull]
+ private Task prepareAndImportScoreAsync(bool forceImport = false)
{
// Ensure we are not writing to the replay any more, as we are about to consume and store the score.
DrawableRuleset.SetRecordTarget(null);
+ if (prepareScoreForDisplayTask != null)
+ return prepareScoreForDisplayTask;
+
// We do not want to import the score in cases where we don't show results
bool canShowResults = Configuration.ShowResults && ScoreProcessor.HasCompleted.Value && GameplayState.HasPassed;
- if (!canShowResults)
- return false;
+ if (!canShowResults && !forceImport)
+ return Task.FromResult(null);
- prepareScoreForDisplayTask ??= Task.Run(prepareAndImportScore);
-
- return true;
- }
-
- ///
- /// Asynchronously run score preparation operations (database import, online submission etc.).
- ///
- /// The final score.
- private async Task prepareAndImportScore()
- {
- var scoreCopy = Score.DeepClone();
-
- try
+ return prepareScoreForDisplayTask = Task.Run(async () =>
{
- await PrepareScoreForResultsAsync(scoreCopy).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- Logger.Error(ex, @"Score preparation failed!");
- }
+ var scoreCopy = Score.DeepClone();
- try
- {
- await ImportScore(scoreCopy).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- Logger.Error(ex, @"Score import failed!");
- }
+ try
+ {
+ await PrepareScoreForResultsAsync(scoreCopy).ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ Logger.Error(ex, @"Score preparation failed!");
+ }
- return scoreCopy.ScoreInfo;
+ try
+ {
+ await ImportScore(scoreCopy).ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ Logger.Error(ex, @"Score import failed!");
+ }
+
+ return scoreCopy.ScoreInfo;
+ });
}
protected override bool OnScroll(ScrollEvent e)
From d100a4a4915b3c67c48cf790822e93da90dc02be Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Tue, 14 Feb 2023 10:12:37 +0100
Subject: [PATCH 0091/1400] Make `lastJudgedHitObject` nullable, and fix typo
in name.
---
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 23 ++++++++-------------
1 file changed, 9 insertions(+), 14 deletions(-)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index 3e3fce5c27..40c235911c 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -2,8 +2,10 @@
// See the LICENCE file in the repository root for full licence text.
using System;
+using System.Diagnostics;
using System.Linq;
using osu.Framework.Bindables;
+using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
@@ -48,7 +50,7 @@ namespace osu.Game.Rulesets.Osu.Mods
private readonly DrawablePool bubblePool = new DrawablePool(100);
- private DrawableOsuHitObject lastJudgedHitobject = null!;
+ private DrawableOsuHitObject? lastJudgedHitObject;
public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank;
@@ -60,9 +62,11 @@ namespace osu.Game.Rulesets.Osu.Mods
scoreProcessor.NewJudgement += result =>
{
- if (result.HitObject is not OsuHitObject osuHitObject) return;
+ if (result.HitObject is not OsuHitObject osuHitObject || lastJudgedHitObject.IsNull()) return;
- DrawableOsuHitObject drawableOsuHitObject = lastJudgedHitobject;
+ Debug.Assert(result.HitObject == lastJudgedHitObject.HitObject);
+
+ DrawableOsuHitObject drawableOsuHitObject = lastJudgedHitObject;
switch (result.HitObject)
{
@@ -144,18 +148,9 @@ namespace osu.Game.Rulesets.Osu.Mods
applySliderState(slider);
}
- if (osuHitObject == lastJudgedHitobject || !osuHitObject.Judged) return;
+ if (osuHitObject == lastJudgedHitObject || !osuHitObject.Judged) return;
- switch (osuHitObject)
- {
- case DrawableSlider:
- case DrawableSpinnerTick:
- break;
-
- default:
- lastJudgedHitobject = osuHitObject;
- break;
- }
+ lastJudgedHitObject = osuHitObject;
}
// Makes the slider border coloured on all skins (for aesthetics)
From 2d49b5f9d66150598260451250c11736bdad87bc Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Tue, 14 Feb 2023 14:03:48 +0100
Subject: [PATCH 0092/1400] Move bubbles to ruleset overlays container
---
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index 40c235911c..732626b177 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -132,7 +132,7 @@ namespace osu.Game.Rulesets.Osu.Mods
bubbleContainer = drawableRuleset.CreatePlayfieldAdjustmentContainer();
- drawableRuleset.KeyBindingInputManager.Add(bubbleContainer);
+ drawableRuleset.Overlays.Add(bubbleContainer);
}
protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state) => applyBubbleState(hitObject);
From 92c61c73396939363b3c6bd7ffffb083e3c74116 Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Tue, 14 Feb 2023 16:31:34 +0100
Subject: [PATCH 0093/1400] move logic for bubble invoking to
`ApplyToDrawableHitobject()`` method
---
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 85 +++++++++------------
1 file changed, 34 insertions(+), 51 deletions(-)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index 732626b177..4a8c11e7ff 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -2,10 +2,8 @@
// See the LICENCE file in the repository root for full licence text.
using System;
-using System.Diagnostics;
using System.Linq;
using osu.Framework.Bindables;
-using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
@@ -25,7 +23,7 @@ using osuTK;
namespace osu.Game.Rulesets.Osu.Mods
{
- public partial class OsuModBubbles : ModWithVisibilityAdjustment, IApplicableToDrawableRuleset, IApplicableToScoreProcessor
+ public partial class OsuModBubbles : Mod, IApplicableToDrawableRuleset, IApplicableToDrawableHitObject, IApplicableToScoreProcessor
{
public override string Name => "Bubbles";
@@ -50,8 +48,6 @@ namespace osu.Game.Rulesets.Osu.Mods
private readonly DrawablePool bubblePool = new DrawablePool(100);
- private DrawableOsuHitObject? lastJudgedHitObject;
-
public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank;
public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor)
@@ -60,15 +56,41 @@ namespace osu.Game.Rulesets.Osu.Mods
currentCombo.BindValueChanged(combo =>
maxSize = Math.Min(1.75f, (float)(1.25 + 0.005 * combo.NewValue)), true);
- scoreProcessor.NewJudgement += result =>
+ scoreProcessor.JudgementReverted += _ =>
{
- if (result.HitObject is not OsuHitObject osuHitObject || lastJudgedHitObject.IsNull()) return;
+ bubbleContainer.LastOrDefault()?.ClearTransforms();
+ bubbleContainer.LastOrDefault()?.Expire();
+ };
+ }
- Debug.Assert(result.HitObject == lastJudgedHitObject.HitObject);
+ public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset)
+ {
+ // Multiplying by 2 results in an initial size that is too large, hence 1.90 has been chosen
+ // Also avoids the HitObject bleeding around the edges of the bubble drawable at minimum size
+ bubbleRadius = (float)(drawableRuleset.Beatmap.HitObjects.OfType().First().Radius * 1.90f);
+ bubbleFade = drawableRuleset.Beatmap.HitObjects.OfType().First().TimePreempt * 2;
- DrawableOsuHitObject drawableOsuHitObject = lastJudgedHitObject;
+ // We want to hide the judgements since they are obscured by the BubbleDrawable (due to layering)
+ drawableRuleset.Playfield.DisplayJudgements.Value = false;
- switch (result.HitObject)
+ bubbleContainer = drawableRuleset.CreatePlayfieldAdjustmentContainer();
+
+ drawableRuleset.Overlays.Add(bubbleContainer);
+ }
+
+ public void ApplyToDrawableHitObject(DrawableHitObject drawableObject)
+ {
+ if (drawableObject is DrawableSlider slider)
+ {
+ applySliderState(slider);
+ slider.Body.OnSkinChanged += () => applySliderState(slider);
+ }
+
+ drawableObject.OnNewResult += (drawable, _) =>
+ {
+ if (drawable is not DrawableOsuHitObject drawableOsuHitObject) return;
+
+ switch (drawableOsuHitObject.HitObject)
{
case Slider:
case SpinnerTick:
@@ -101,56 +123,17 @@ namespace osu.Game.Rulesets.Osu.Mods
// SliderHeads are derived from HitCircles,
// so we must handle them before to avoid them using the wrong positioning logic
case DrawableSliderHead:
- return osuHitObject.Position;
+ return drawableOsuHitObject.HitObject.Position;
// Using hitobject position will cause issues with HitCircle placement due to stack leniency.
case DrawableHitCircle:
return drawableOsuHitObject.Position;
default:
- return osuHitObject.Position;
+ return drawableOsuHitObject.HitObject.Position;
}
}
};
-
- scoreProcessor.JudgementReverted += _ =>
- {
- bubbleContainer.LastOrDefault()?.FinishTransforms();
- bubbleContainer.LastOrDefault()?.Expire();
- };
- }
-
- public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset)
- {
- // Multiplying by 2 results in an initial size that is too large, hence 1.90 has been chosen
- // Also avoids the HitObject bleeding around the edges of the bubble drawable at minimum size
- bubbleRadius = (float)(drawableRuleset.Beatmap.HitObjects.OfType().First().Radius * 1.90f);
- bubbleFade = drawableRuleset.Beatmap.HitObjects.OfType().First().TimePreempt * 2;
-
- // We want to hide the judgements since they are obscured by the BubbleDrawable (due to layering)
- drawableRuleset.Playfield.DisplayJudgements.Value = false;
-
- bubbleContainer = drawableRuleset.CreatePlayfieldAdjustmentContainer();
-
- drawableRuleset.Overlays.Add(bubbleContainer);
- }
-
- protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state) => applyBubbleState(hitObject);
- protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject, ArmedState state) => applyBubbleState(hitObject);
-
- private void applyBubbleState(DrawableHitObject drawableObject)
- {
- DrawableOsuHitObject osuHitObject = (DrawableOsuHitObject)drawableObject;
-
- if (drawableObject is DrawableSlider slider)
- {
- slider.Body.OnSkinChanged += () => applySliderState(slider);
- applySliderState(slider);
- }
-
- if (osuHitObject == lastJudgedHitObject || !osuHitObject.Judged) return;
-
- lastJudgedHitObject = osuHitObject;
}
// Makes the slider border coloured on all skins (for aesthetics)
From 5db624159b1230e7ca522e9ab6cdec8194e8a0fa Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Tue, 14 Feb 2023 18:06:43 +0100
Subject: [PATCH 0094/1400] Change bubble rewind removal to be in
`ApplyToDrawableHitObject` method.
---
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index 4a8c11e7ff..f521dfb1f8 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -55,12 +55,6 @@ namespace osu.Game.Rulesets.Osu.Mods
currentCombo.BindTo(scoreProcessor.Combo);
currentCombo.BindValueChanged(combo =>
maxSize = Math.Min(1.75f, (float)(1.25 + 0.005 * combo.NewValue)), true);
-
- scoreProcessor.JudgementReverted += _ =>
- {
- bubbleContainer.LastOrDefault()?.ClearTransforms();
- bubbleContainer.LastOrDefault()?.Expire();
- };
}
public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset)
@@ -134,6 +128,16 @@ namespace osu.Game.Rulesets.Osu.Mods
}
}
};
+
+ drawableObject.OnRevertResult += (drawable, _) =>
+ {
+ if (drawable.HitObject is SpinnerTick or Slider) return;
+
+ BubbleDrawable? lastBubble = bubbleContainer.OfType().LastOrDefault();
+
+ lastBubble?.ClearTransforms();
+ lastBubble?.Expire();
+ };
}
// Makes the slider border coloured on all skins (for aesthetics)
From 82292d61621e49a158c576879ae56f47a9e52a84 Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Wed, 15 Feb 2023 09:30:12 +0100
Subject: [PATCH 0095/1400] Make colouring for bubble more intuitive and remove
unnecessary alpha assignment
---
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index f521dfb1f8..2a4208065d 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -177,8 +177,7 @@ namespace osu.Game.Rulesets.Osu.Mods
protected override void PrepareForUse()
{
- Alpha = 1;
- Colour = Colour4.White;
+ Colour = Info.IsHit ? Colour4.White : Colour4.Black;
Scale = new Vector2(1);
Position = Info.Position;
Size = Info.InitialSize;
@@ -204,12 +203,8 @@ namespace osu.Game.Rulesets.Osu.Mods
content.TransformTo(nameof(BorderThickness), 2f, getAnimationDuration() * 0.3f, Easing.OutQuint)
// Avoids transparency overlap issues during the bubble "pop"
.Then().Schedule(() => content.BorderThickness = 0);
-
- return;
}
- Colour = Colour4.Black;
-
// The absolute length of the bubble's animation, can be used in fractions for animations of partial length
double getAnimationDuration() => 1700 + Math.Pow(Info.FadeTime, 1.07f);
}
From e9a7d90273c57dbd7dfb30ff32b9ca21dc9b6d39 Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Wed, 15 Feb 2023 09:33:18 +0100
Subject: [PATCH 0096/1400] make transform duration for bubble a method instead
of a variable
---
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index 2a4208065d..a88bf6b813 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -187,26 +187,26 @@ namespace osu.Game.Rulesets.Osu.Mods
//We want to fade to a darker colour to avoid colours such as white hiding the "ripple" effect.
ColourInfo colourDarker = Info.Colour.Darken(0.1f);
+ // The absolute length of the bubble's animation, can be used in fractions for animations of partial length
+ double getAnimationDuration = 1700 + Math.Pow(Info.FadeTime, 1.07f);
+
// Main bubble scaling based on combo
- this.ScaleTo(Info.MaxSize, getAnimationDuration() * 0.8f)
+ this.ScaleTo(Info.MaxSize, getAnimationDuration * 0.8f)
.Then()
// Pop at the end of the bubbles life time
- .ScaleTo(Info.MaxSize * 1.5f, getAnimationDuration() * 0.2f, Easing.OutQuint)
- .FadeOutFromOne(getAnimationDuration() * 0.2f, Easing.OutCirc).Expire();
+ .ScaleTo(Info.MaxSize * 1.5f, getAnimationDuration * 0.2f, Easing.OutQuint)
+ .FadeOutFromOne(getAnimationDuration * 0.2f, Easing.OutCirc).Expire();
if (Info.IsHit)
{
colourBox.FadeColour(colourDarker);
- content.TransformTo(nameof(BorderColour), colourDarker, getAnimationDuration() * 0.3f, Easing.OutQuint);
+ content.TransformTo(nameof(BorderColour), colourDarker, getAnimationDuration * 0.3f, Easing.OutQuint);
// Ripple effect utilises the border to reduce drawable count
- content.TransformTo(nameof(BorderThickness), 2f, getAnimationDuration() * 0.3f, Easing.OutQuint)
+ content.TransformTo(nameof(BorderThickness), 2f, getAnimationDuration * 0.3f, Easing.OutQuint)
// Avoids transparency overlap issues during the bubble "pop"
.Then().Schedule(() => content.BorderThickness = 0);
}
-
- // The absolute length of the bubble's animation, can be used in fractions for animations of partial length
- double getAnimationDuration() => 1700 + Math.Pow(Info.FadeTime, 1.07f);
}
}
From 1d1c794ccfde23743574d8579da648cf42f4e4d4 Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Wed, 15 Feb 2023 09:37:47 +0100
Subject: [PATCH 0097/1400] Invert pointless nested `if` statement
---
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 17 ++++++++---------
1 file changed, 8 insertions(+), 9 deletions(-)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index a88bf6b813..d75c82dc85 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -197,16 +197,15 @@ namespace osu.Game.Rulesets.Osu.Mods
.ScaleTo(Info.MaxSize * 1.5f, getAnimationDuration * 0.2f, Easing.OutQuint)
.FadeOutFromOne(getAnimationDuration * 0.2f, Easing.OutCirc).Expire();
- if (Info.IsHit)
- {
- colourBox.FadeColour(colourDarker);
+ if (!Info.IsHit) return;
- content.TransformTo(nameof(BorderColour), colourDarker, getAnimationDuration * 0.3f, Easing.OutQuint);
- // Ripple effect utilises the border to reduce drawable count
- content.TransformTo(nameof(BorderThickness), 2f, getAnimationDuration * 0.3f, Easing.OutQuint)
- // Avoids transparency overlap issues during the bubble "pop"
- .Then().Schedule(() => content.BorderThickness = 0);
- }
+ colourBox.FadeColour(colourDarker);
+
+ content.TransformTo(nameof(BorderColour), colourDarker, getAnimationDuration * 0.3f, Easing.OutQuint);
+ // Ripple effect utilises the border to reduce drawable count
+ content.TransformTo(nameof(BorderThickness), 2f, getAnimationDuration * 0.3f, Easing.OutQuint)
+ // Avoids transparency overlap issues during the bubble "pop"
+ .Then().Schedule(() => content.BorderThickness = 0);
}
}
From 297963b461cfdfd6083784ab0c4561c43c1d4a93 Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Wed, 15 Feb 2023 10:00:46 +0100
Subject: [PATCH 0098/1400] Remove BubbleInfo struct and consume
`DrawableOsuHitObject`s directly
---
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 102 +++++++++-----------
1 file changed, 46 insertions(+), 56 deletions(-)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index d75c82dc85..981932c580 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -2,8 +2,11 @@
// See the LICENCE file in the repository root for full licence text.
using System;
+using System.Diagnostics;
using System.Linq;
using osu.Framework.Bindables;
+using osu.Framework.Extensions.Color4Extensions;
+using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
@@ -98,35 +101,14 @@ namespace osu.Game.Rulesets.Osu.Mods
void addBubble()
{
BubbleDrawable bubble = bubblePool.Get();
- bubble.Info = new BubbleInfo
- {
- InitialSize = new Vector2(bubbleRadius),
- MaxSize = maxSize,
- Position = getPosition(),
- FadeTime = bubbleFade,
- Colour = drawableOsuHitObject.AccentColour.Value,
- IsHit = drawableOsuHitObject.IsHit,
- };
+
+ bubble.DrawableOsuHitObject = drawableOsuHitObject;
+ bubble.InitialSize = new Vector2(bubbleRadius);
+ bubble.FadeTime = bubbleFade;
+ bubble.MaxSize = maxSize;
+
bubbleContainer.Add(bubble);
}
-
- Vector2 getPosition()
- {
- switch (drawableOsuHitObject)
- {
- // SliderHeads are derived from HitCircles,
- // so we must handle them before to avoid them using the wrong positioning logic
- case DrawableSliderHead:
- return drawableOsuHitObject.HitObject.Position;
-
- // Using hitobject position will cause issues with HitCircle placement due to stack leniency.
- case DrawableHitCircle:
- return drawableOsuHitObject.Position;
-
- default:
- return drawableOsuHitObject.HitObject.Position;
- }
- }
};
drawableObject.OnRevertResult += (drawable, _) =>
@@ -148,11 +130,15 @@ namespace osu.Game.Rulesets.Osu.Mods
private partial class BubbleDrawable : PoolableDrawable
{
+ public DrawableOsuHitObject? DrawableOsuHitObject { get; set; }
+
+ public Vector2 InitialSize { get; set; }
+ public double FadeTime { get; set; }
+ public float MaxSize { get; set; }
+
private readonly Box colourBox;
private readonly CircularContainer content;
- public BubbleInfo Info { get; set; }
-
public BubbleDrawable()
{
Origin = Anchor.Centre;
@@ -177,27 +163,30 @@ namespace osu.Game.Rulesets.Osu.Mods
protected override void PrepareForUse()
{
- Colour = Info.IsHit ? Colour4.White : Colour4.Black;
+ Debug.Assert(DrawableOsuHitObject.IsNotNull());
+
+ Colour = DrawableOsuHitObject.IsHit ? Colour4.White : Colour4.Black;
+ Alpha = 1;
Scale = new Vector2(1);
- Position = Info.Position;
- Size = Info.InitialSize;
- content.BorderThickness = Info.InitialSize.X / 3.5f;
+ Position = getPosition();
+ Size = InitialSize;
+ content.BorderThickness = InitialSize.X / 3.5f;
content.BorderColour = Colour4.White;
//We want to fade to a darker colour to avoid colours such as white hiding the "ripple" effect.
- ColourInfo colourDarker = Info.Colour.Darken(0.1f);
+ ColourInfo colourDarker = DrawableOsuHitObject.AccentColour.Value.Darken(0.1f);
// The absolute length of the bubble's animation, can be used in fractions for animations of partial length
- double getAnimationDuration = 1700 + Math.Pow(Info.FadeTime, 1.07f);
+ double getAnimationDuration = 1700 + Math.Pow(FadeTime, 1.07f);
// Main bubble scaling based on combo
- this.ScaleTo(Info.MaxSize, getAnimationDuration * 0.8f)
+ this.ScaleTo(MaxSize, getAnimationDuration * 0.8f)
.Then()
// Pop at the end of the bubbles life time
- .ScaleTo(Info.MaxSize * 1.5f, getAnimationDuration * 0.2f, Easing.OutQuint)
- .FadeOutFromOne(getAnimationDuration * 0.2f, Easing.OutCirc).Expire();
+ .ScaleTo(MaxSize * 1.5f, getAnimationDuration * 0.2f, Easing.OutQuint)
+ .FadeOut(getAnimationDuration * 0.2f, Easing.OutCirc).Expire();
- if (!Info.IsHit) return;
+ if (!DrawableOsuHitObject.IsHit) return;
colourBox.FadeColour(colourDarker);
@@ -206,26 +195,27 @@ namespace osu.Game.Rulesets.Osu.Mods
content.TransformTo(nameof(BorderThickness), 2f, getAnimationDuration * 0.3f, Easing.OutQuint)
// Avoids transparency overlap issues during the bubble "pop"
.Then().Schedule(() => content.BorderThickness = 0);
+
+ Vector2 getPosition()
+ {
+ switch (DrawableOsuHitObject)
+ {
+ // SliderHeads are derived from HitCircles,
+ // so we must handle them before to avoid them using the wrong positioning logic
+ case DrawableSliderHead:
+ return DrawableOsuHitObject.HitObject.Position;
+
+ // Using hitobject position will cause issues with HitCircle placement due to stack leniency.
+ case DrawableHitCircle:
+ return DrawableOsuHitObject.Position;
+
+ default:
+ return DrawableOsuHitObject.HitObject.Position;
+ }
+ }
}
}
- private struct BubbleInfo
- {
- public Vector2 InitialSize { get; set; }
-
- public float MaxSize { get; set; }
-
- public Vector2 Position { get; set; }
-
- public Colour4 Colour { get; set; }
-
- // FadeTime is based on the approach rate of the beatmap.
- public double FadeTime { get; set; }
-
- // Whether the corresponding HitObject was hit
- public bool IsHit { get; set; }
- }
-
#endregion
}
}
From 8fc35b159f87a10a087c79c469d981ff9750bc95 Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Wed, 15 Feb 2023 10:04:50 +0100
Subject: [PATCH 0099/1400] Remove dysfunctional slider colouring
---
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 11 -----------
1 file changed, 11 deletions(-)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index 981932c580..4edf726f26 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -18,7 +18,6 @@ using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
-using osu.Game.Rulesets.Osu.Skinning.Default;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
using osu.Game.Scoring;
@@ -77,12 +76,6 @@ namespace osu.Game.Rulesets.Osu.Mods
public void ApplyToDrawableHitObject(DrawableHitObject drawableObject)
{
- if (drawableObject is DrawableSlider slider)
- {
- applySliderState(slider);
- slider.Body.OnSkinChanged += () => applySliderState(slider);
- }
-
drawableObject.OnNewResult += (drawable, _) =>
{
if (drawable is not DrawableOsuHitObject drawableOsuHitObject) return;
@@ -122,10 +115,6 @@ namespace osu.Game.Rulesets.Osu.Mods
};
}
- // Makes the slider border coloured on all skins (for aesthetics)
- private void applySliderState(DrawableSlider slider) =>
- ((PlaySliderBody)slider.Body.Drawable).BorderColour = slider.AccentColour.Value;
-
#region Pooled Bubble drawable
private partial class BubbleDrawable : PoolableDrawable
From 1f586c129c1b27fee148db26846e69eb6febc1d8 Mon Sep 17 00:00:00 2001
From: Cootz
Date: Wed, 15 Feb 2023 22:15:44 +0300
Subject: [PATCH 0100/1400] fix applied
---
osu.Game/Database/LegacyExporter.cs | 20 +++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs
index 09d6913dd9..c56c17222d 100644
--- a/osu.Game/Database/LegacyExporter.cs
+++ b/osu.Game/Database/LegacyExporter.cs
@@ -3,6 +3,7 @@
#nullable disable
+using System;
using System.Collections.Generic;
using System.IO;
using osu.Framework.Platform;
@@ -18,6 +19,14 @@ namespace osu.Game.Database
public abstract class LegacyExporter
where TModel : class, IHasNamedFiles
{
+ ///
+ /// Max length of filename (including extension)
+ ///
+ ///
+ /// This constant is smaller 256 because adds additional "_" to the end of the path
+ ///
+ private const int max_path = 255 - (32 + 4 + 2); //max path - (Guid + Guid "D" format chars + Storage.CreateFileSafely chars)
+
///
/// The file extension for exports (including the leading '.').
///
@@ -33,7 +42,16 @@ namespace osu.Game.Database
UserFileStorage = storage.GetStorageForDirectory(@"files");
}
- protected virtual string GetFilename(TModel item) => item.GetDisplayString();
+ protected virtual string GetFilename(TModel item)
+ {
+ string fileName = item.GetDisplayString();
+
+ int fileNameLength = fileName.Length - FileExtension.Length;
+ if (fileNameLength > max_path)
+ fileName = fileName.Remove(max_path - FileExtension.Length); //Truncating the name to fit the path limit
+
+ return fileName;
+ }
///
/// Exports an item to a legacy (.zip based) package.
From 387a6f1330b3e22360565dd07a4a7048eae3e4d8 Mon Sep 17 00:00:00 2001
From: Cootz
Date: Wed, 15 Feb 2023 22:43:43 +0300
Subject: [PATCH 0101/1400] Move logic to `Export` method
---
osu.Game/Database/LegacyExporter.cs | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs
index cd0b50c109..483c3cbd5c 100644
--- a/osu.Game/Database/LegacyExporter.cs
+++ b/osu.Game/Database/LegacyExporter.cs
@@ -43,16 +43,7 @@ namespace osu.Game.Database
UserFileStorage = storage.GetStorageForDirectory(@"files");
}
- protected virtual string GetFilename(TModel item)
- {
- string fileName = item.GetDisplayString();
-
- int fileNameLength = fileName.Length - FileExtension.Length;
- if (fileNameLength > max_path)
- fileName = fileName.Remove(max_path - FileExtension.Length); //Truncating the name to fit the path limit
-
- return fileName;
- }
+ protected virtual string GetFilename(TModel item) => item.GetDisplayString();
///
/// Exports an item to a legacy (.zip based) package.
@@ -68,6 +59,15 @@ namespace osu.Game.Database
.Concat(exportStorage.GetDirectories(string.Empty));
string filename = NamingUtils.GetNextBestFilename(existingExports, $"{itemFilename}{FileExtension}");
+
+ if (filename.Length > max_path)
+ {
+ string filenameWithoutExtension = Path.GetFileNameWithoutExtension(filename);
+
+ filenameWithoutExtension = filenameWithoutExtension.Remove(max_path - FileExtension.Length); //Truncating the name to fit the path limit
+ filename = $"{filenameWithoutExtension}{FileExtension}";
+ }
+
using (var stream = exportStorage.CreateFileSafely(filename))
ExportModelTo(item, stream);
From 157bba78305b3474fecc5a529b95c954b994e9e9 Mon Sep 17 00:00:00 2001
From: tsrk
Date: Mon, 13 Feb 2023 21:59:17 +0000
Subject: [PATCH 0102/1400] refactor: rename `Trigger` class to `InputTrigger`
---
.../TestSceneOsuTouchInput.cs | 2 +-
.../Visual/Gameplay/TestSceneKeyCounter.cs | 2 +-
osu.Game/Rulesets/UI/RulesetInputManager.cs | 6 +++---
osu.Game/Screens/Play/DefaultKeyCounter.cs | 2 +-
osu.Game/Screens/Play/KeyCounter.cs | 14 +++++++-------
osu.Game/Screens/Play/KeyCounterAction.cs | 2 +-
osu.Game/Screens/Play/KeyCounterDisplay.cs | 2 +-
osu.Game/Screens/Play/KeyCounterKeyboard.cs | 2 +-
osu.Game/Screens/Play/KeyCounterMouse.cs | 2 +-
9 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
index cd30d8df83..1a273153bd 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
@@ -579,7 +579,7 @@ namespace osu.Game.Rulesets.Osu.Tests
private void checkNotPressed(OsuAction action) => AddAssert($"Not pressing {action}", () => !osuInputManager.PressedActions.Contains(action));
private void checkPressed(OsuAction action) => AddAssert($"Is pressing {action}", () => osuInputManager.PressedActions.Contains(action));
- public partial class TestActionKeyCounter : KeyCounter.Trigger, IKeyBindingHandler
+ public partial class TestActionKeyCounter : KeyCounter.InputTrigger, IKeyBindingHandler
{
public OsuAction Action { get; }
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs
index 60ebce4f52..f652a62489 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs
@@ -38,7 +38,7 @@ namespace osu.Game.Tests.Visual.Gameplay
kc.Add(kc.CreateKeyCounter(new KeyCounterKeyboard(key)));
});
- Key testKey = ((KeyCounterKeyboard)kc.Children.First().CounterTrigger).Key;
+ Key testKey = ((KeyCounterKeyboard)kc.Children.First().Trigger).Key;
void addPressKeyStep()
{
diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs
index 0fa1f0b332..22dc6567eb 100644
--- a/osu.Game/Rulesets/UI/RulesetInputManager.cs
+++ b/osu.Game/Rulesets/UI/RulesetInputManager.cs
@@ -176,14 +176,14 @@ namespace osu.Game.Rulesets.UI
{
}
- public bool OnPressed(KeyBindingPressEvent e) => Target.Children.Where(c => c.CounterTrigger is KeyCounterAction)
- .Select(c => (KeyCounterAction)c.CounterTrigger)
+ public bool OnPressed(KeyBindingPressEvent e) => Target.Children.Where(c => c.Trigger is KeyCounterAction)
+ .Select(c => (KeyCounterAction)c.Trigger)
.Any(c => c.OnPressed(e.Action, Clock.Rate >= 0));
public void OnReleased(KeyBindingReleaseEvent e)
{
foreach (var c
- in Target.Children.Where(c => c.CounterTrigger is KeyCounterAction).Select(c => (KeyCounterAction)c.CounterTrigger))
+ in Target.Children.Where(c => c.Trigger is KeyCounterAction).Select(c => (KeyCounterAction)c.Trigger))
c.OnReleased(e.Action, Clock.Rate >= 0);
}
}
diff --git a/osu.Game/Screens/Play/DefaultKeyCounter.cs b/osu.Game/Screens/Play/DefaultKeyCounter.cs
index dcb425ae1d..93dc4abcb5 100644
--- a/osu.Game/Screens/Play/DefaultKeyCounter.cs
+++ b/osu.Game/Screens/Play/DefaultKeyCounter.cs
@@ -25,7 +25,7 @@ namespace osu.Game.Screens.Play
public Color4 KeyUpTextColor { get; set; } = Color4.White;
public double FadeTime { get; set; }
- public DefaultKeyCounter(Trigger trigger)
+ public DefaultKeyCounter(InputTrigger trigger)
: base(trigger)
{
}
diff --git a/osu.Game/Screens/Play/KeyCounter.cs b/osu.Game/Screens/Play/KeyCounter.cs
index b111305b22..a1950a49f4 100644
--- a/osu.Game/Screens/Play/KeyCounter.cs
+++ b/osu.Game/Screens/Play/KeyCounter.cs
@@ -10,7 +10,7 @@ namespace osu.Game.Screens.Play
{
public abstract partial class KeyCounter : Container
{
- public readonly Trigger CounterTrigger;
+ public readonly InputTrigger Trigger;
protected Bindable IsCountingBindable = new BindableBool(true);
@@ -35,7 +35,7 @@ namespace osu.Game.Screens.Play
private set => PressesCount.Value = value;
}
- protected KeyCounter(Trigger trigger)
+ protected KeyCounter(InputTrigger trigger)
{
InternalChildren = new Drawable[]
{
@@ -43,10 +43,10 @@ namespace osu.Game.Screens.Play
{
RelativeSizeAxes = Axes.Both
},
- CounterTrigger = trigger,
+ Trigger = trigger,
};
- CounterTrigger.Target = this;
+ Trigger.Target = this;
Name = trigger.Name;
}
@@ -68,9 +68,9 @@ namespace osu.Game.Screens.Play
CountPresses--;
}
- protected override bool Handle(UIEvent e) => CounterTrigger.TriggerEvent(e);
+ protected override bool Handle(UIEvent e) => Trigger.TriggerEvent(e);
- public abstract partial class Trigger : Component
+ public abstract partial class InputTrigger : Component
{
private KeyCounter? target;
@@ -79,7 +79,7 @@ namespace osu.Game.Screens.Play
set => target = value;
}
- protected Trigger(string name)
+ protected InputTrigger(string name)
{
Name = name;
}
diff --git a/osu.Game/Screens/Play/KeyCounterAction.cs b/osu.Game/Screens/Play/KeyCounterAction.cs
index 058dbb1480..4926970960 100644
--- a/osu.Game/Screens/Play/KeyCounterAction.cs
+++ b/osu.Game/Screens/Play/KeyCounterAction.cs
@@ -7,7 +7,7 @@ using System.Collections.Generic;
namespace osu.Game.Screens.Play
{
- public partial class KeyCounterAction : KeyCounter.Trigger
+ public partial class KeyCounterAction : KeyCounter.InputTrigger
where T : struct
{
public T Action { get; }
diff --git a/osu.Game/Screens/Play/KeyCounterDisplay.cs b/osu.Game/Screens/Play/KeyCounterDisplay.cs
index b06d1adfa0..fc6fa12f10 100644
--- a/osu.Game/Screens/Play/KeyCounterDisplay.cs
+++ b/osu.Game/Screens/Play/KeyCounterDisplay.cs
@@ -81,7 +81,7 @@ namespace osu.Game.Screens.Play
this.receptor = receptor;
}
- public virtual KeyCounter CreateKeyCounter(KeyCounter.Trigger trigger) => new DefaultKeyCounter(trigger);
+ public virtual KeyCounter CreateKeyCounter(KeyCounter.InputTrigger trigger) => new DefaultKeyCounter(trigger);
public partial class Receptor : Drawable
{
diff --git a/osu.Game/Screens/Play/KeyCounterKeyboard.cs b/osu.Game/Screens/Play/KeyCounterKeyboard.cs
index 4306efd360..6ae1a2c5bc 100644
--- a/osu.Game/Screens/Play/KeyCounterKeyboard.cs
+++ b/osu.Game/Screens/Play/KeyCounterKeyboard.cs
@@ -8,7 +8,7 @@ using osuTK.Input;
namespace osu.Game.Screens.Play
{
- public partial class KeyCounterKeyboard : KeyCounter.Trigger
+ public partial class KeyCounterKeyboard : KeyCounter.InputTrigger
{
public Key Key { get; }
diff --git a/osu.Game/Screens/Play/KeyCounterMouse.cs b/osu.Game/Screens/Play/KeyCounterMouse.cs
index 00fca47ba2..40674cdbcd 100644
--- a/osu.Game/Screens/Play/KeyCounterMouse.cs
+++ b/osu.Game/Screens/Play/KeyCounterMouse.cs
@@ -9,7 +9,7 @@ using osuTK;
namespace osu.Game.Screens.Play
{
- public partial class KeyCounterMouse : KeyCounter.Trigger
+ public partial class KeyCounterMouse : KeyCounter.InputTrigger
{
public MouseButton Button { get; }
From df0633858cb9aa0734a95e5f67fc284313571485 Mon Sep 17 00:00:00 2001
From: tsrk
Date: Mon, 13 Feb 2023 23:20:23 +0000
Subject: [PATCH 0103/1400] fix(KeyCounter): don't override Handle
This caused the Keyboard inputs to register twice, which is not what we
want.
---
osu.Game/Screens/Play/KeyCounter.cs | 3 ---
1 file changed, 3 deletions(-)
diff --git a/osu.Game/Screens/Play/KeyCounter.cs b/osu.Game/Screens/Play/KeyCounter.cs
index a1950a49f4..cd306dfb9b 100644
--- a/osu.Game/Screens/Play/KeyCounter.cs
+++ b/osu.Game/Screens/Play/KeyCounter.cs
@@ -4,7 +4,6 @@
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Input.Events;
namespace osu.Game.Screens.Play
{
@@ -68,8 +67,6 @@ namespace osu.Game.Screens.Play
CountPresses--;
}
- protected override bool Handle(UIEvent e) => Trigger.TriggerEvent(e);
-
public abstract partial class InputTrigger : Component
{
private KeyCounter? target;
From a644fae3649f29eacf612b2bd920fc4ad0a8ec48 Mon Sep 17 00:00:00 2001
From: tsrk
Date: Mon, 13 Feb 2023 23:22:50 +0000
Subject: [PATCH 0104/1400] style(KeyCounter): rename `(Un)lit` methods to
`(Un)light`
---
osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs | 4 ++--
osu.Game/Screens/Play/KeyCounter.cs | 4 ++--
osu.Game/Screens/Play/KeyCounterAction.cs | 4 ++--
osu.Game/Screens/Play/KeyCounterKeyboard.cs | 6 ++++--
osu.Game/Screens/Play/KeyCounterMouse.cs | 4 ++--
5 files changed, 12 insertions(+), 10 deletions(-)
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
index 1a273153bd..6068cf50b6 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
@@ -593,7 +593,7 @@ namespace osu.Game.Rulesets.Osu.Tests
{
if (e.Action == Action)
{
- Lit();
+ Light();
}
return false;
@@ -602,7 +602,7 @@ namespace osu.Game.Rulesets.Osu.Tests
public void OnReleased(KeyBindingReleaseEvent e)
{
if (e.Action == Action)
- Unlit();
+ Unlight();
}
}
diff --git a/osu.Game/Screens/Play/KeyCounter.cs b/osu.Game/Screens/Play/KeyCounter.cs
index cd306dfb9b..4a7203870c 100644
--- a/osu.Game/Screens/Play/KeyCounter.cs
+++ b/osu.Game/Screens/Play/KeyCounter.cs
@@ -81,7 +81,7 @@ namespace osu.Game.Screens.Play
Name = name;
}
- protected void Lit(bool increment = true)
+ protected void Light(bool increment = true)
{
if (target == null) return;
@@ -90,7 +90,7 @@ namespace osu.Game.Screens.Play
target.Increment();
}
- protected void Unlit(bool preserve = true)
+ protected void Unlight(bool preserve = true)
{
if (target == null) return;
diff --git a/osu.Game/Screens/Play/KeyCounterAction.cs b/osu.Game/Screens/Play/KeyCounterAction.cs
index 4926970960..65a0bc2ca7 100644
--- a/osu.Game/Screens/Play/KeyCounterAction.cs
+++ b/osu.Game/Screens/Play/KeyCounterAction.cs
@@ -23,7 +23,7 @@ namespace osu.Game.Screens.Play
if (!EqualityComparer.Default.Equals(action, Action))
return false;
- Lit(forwards);
+ Light(forwards);
return false;
}
@@ -32,7 +32,7 @@ namespace osu.Game.Screens.Play
if (!EqualityComparer.Default.Equals(action, Action))
return;
- Unlit(forwards);
+ Unlight(forwards);
}
}
}
diff --git a/osu.Game/Screens/Play/KeyCounterKeyboard.cs b/osu.Game/Screens/Play/KeyCounterKeyboard.cs
index 6ae1a2c5bc..ef1f207556 100644
--- a/osu.Game/Screens/Play/KeyCounterKeyboard.cs
+++ b/osu.Game/Screens/Play/KeyCounterKeyboard.cs
@@ -21,7 +21,9 @@ namespace osu.Game.Screens.Play
protected override bool OnKeyDown(KeyDownEvent e)
{
if (e.Key == Key)
- Lit();
+ {
+ Light();
+ }
return base.OnKeyDown(e);
}
@@ -29,7 +31,7 @@ namespace osu.Game.Screens.Play
protected override void OnKeyUp(KeyUpEvent e)
{
if (e.Key == Key)
- Unlit();
+ Unlight();
base.OnKeyUp(e);
}
diff --git a/osu.Game/Screens/Play/KeyCounterMouse.cs b/osu.Game/Screens/Play/KeyCounterMouse.cs
index 40674cdbcd..cf0e0a394f 100644
--- a/osu.Game/Screens/Play/KeyCounterMouse.cs
+++ b/osu.Game/Screens/Play/KeyCounterMouse.cs
@@ -39,7 +39,7 @@ namespace osu.Game.Screens.Play
protected override bool OnMouseDown(MouseDownEvent e)
{
if (e.Button == Button)
- Lit();
+ Light();
return base.OnMouseDown(e);
}
@@ -47,7 +47,7 @@ namespace osu.Game.Screens.Play
protected override void OnMouseUp(MouseUpEvent e)
{
if (e.Button == Button)
- Unlit();
+ Unlight();
base.OnMouseUp(e);
}
From 076eb81b212caaa61546ad3d3d0605b5e072eb46 Mon Sep 17 00:00:00 2001
From: tsrk
Date: Mon, 13 Feb 2023 23:49:57 +0000
Subject: [PATCH 0105/1400] refactor: rename trigger classes
Makes it better to understand their purpose
---
.../TestSceneOsuTouchInput.cs | 8 ++++----
.../Visual/Gameplay/TestSceneHUDOverlay.cs | 2 +-
.../Visual/Gameplay/TestSceneKeyCounter.cs | 12 ++++++------
.../Gameplay/TestSceneSkinEditorMultipleSkins.cs | 2 +-
.../Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs | 2 +-
osu.Game/Rulesets/UI/RulesetInputManager.cs | 8 ++++----
...eyCounterAction.cs => KeyCounterActionTrigger.cs} | 4 ++--
...unterKeyboard.cs => KeyCounterKeyboardTrigger.cs} | 4 ++--
...{KeyCounterMouse.cs => KeyCounterMouseTrigger.cs} | 4 ++--
9 files changed, 23 insertions(+), 23 deletions(-)
rename osu.Game/Screens/Play/{KeyCounterAction.cs => KeyCounterActionTrigger.cs} (86%)
rename osu.Game/Screens/Play/{KeyCounterKeyboard.cs => KeyCounterKeyboardTrigger.cs} (85%)
rename osu.Game/Screens/Play/{KeyCounterMouse.cs => KeyCounterMouseTrigger.cs} (90%)
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
index 6068cf50b6..950e034d8f 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
@@ -59,14 +59,14 @@ namespace osu.Game.Rulesets.Osu.Tests
Origin = Anchor.Centre,
Children = new Drawable[]
{
- leftKeyCounter = new DefaultKeyCounter(new TestActionKeyCounter(OsuAction.LeftButton))
+ leftKeyCounter = new DefaultKeyCounter(new TestActionKeyCounterTrigger(OsuAction.LeftButton))
{
Anchor = Anchor.Centre,
Origin = Anchor.CentreRight,
Depth = float.MinValue,
X = -100,
},
- rightKeyCounter = new DefaultKeyCounter(new TestActionKeyCounter(OsuAction.RightButton))
+ rightKeyCounter = new DefaultKeyCounter(new TestActionKeyCounterTrigger(OsuAction.RightButton))
{
Anchor = Anchor.Centre,
Origin = Anchor.CentreLeft,
@@ -579,11 +579,11 @@ namespace osu.Game.Rulesets.Osu.Tests
private void checkNotPressed(OsuAction action) => AddAssert($"Not pressing {action}", () => !osuInputManager.PressedActions.Contains(action));
private void checkPressed(OsuAction action) => AddAssert($"Is pressing {action}", () => osuInputManager.PressedActions.Contains(action));
- public partial class TestActionKeyCounter : KeyCounter.InputTrigger, IKeyBindingHandler
+ public partial class TestActionKeyCounterTrigger : KeyCounter.InputTrigger, IKeyBindingHandler
{
public OsuAction Action { get; }
- public TestActionKeyCounter(OsuAction action)
+ public TestActionKeyCounterTrigger(OsuAction action)
: base(action.ToString())
{
Action = action;
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs
index 4055ef9d3a..af79650d29 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs
@@ -267,7 +267,7 @@ namespace osu.Game.Tests.Visual.Gameplay
hudOverlay = new HUDOverlay(null, Array.Empty());
// Add any key just to display the key counter visually.
- hudOverlay.KeyCounter.Add(hudOverlay.KeyCounter.CreateKeyCounter(new KeyCounterKeyboard(Key.Space)));
+ hudOverlay.KeyCounter.Add(hudOverlay.KeyCounter.CreateKeyCounter(new KeyCounterKeyboardTrigger(Key.Space)));
scoreProcessor.Combo.Value = 1;
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs
index f652a62489..975a5c9465 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs
@@ -25,20 +25,20 @@ namespace osu.Game.Tests.Visual.Gameplay
Anchor = Anchor.Centre,
Children = new[]
{
- testCounter = new DefaultKeyCounter(new KeyCounterKeyboard(Key.X)),
- new DefaultKeyCounter(new KeyCounterKeyboard(Key.X)),
- new DefaultKeyCounter(new KeyCounterMouse(MouseButton.Left)),
- new DefaultKeyCounter(new KeyCounterMouse(MouseButton.Right)),
+ testCounter = new DefaultKeyCounter(new KeyCounterKeyboardTrigger(Key.X)),
+ new DefaultKeyCounter(new KeyCounterKeyboardTrigger(Key.X)),
+ new DefaultKeyCounter(new KeyCounterMouseTrigger(MouseButton.Left)),
+ new DefaultKeyCounter(new KeyCounterMouseTrigger(MouseButton.Right)),
},
};
AddStep("Add random", () =>
{
Key key = (Key)((int)Key.A + RNG.Next(26));
- kc.Add(kc.CreateKeyCounter(new KeyCounterKeyboard(key)));
+ kc.Add(kc.CreateKeyCounter(new KeyCounterKeyboardTrigger(key)));
});
- Key testKey = ((KeyCounterKeyboard)kc.Children.First().Trigger).Key;
+ Key testKey = ((KeyCounterKeyboardTrigger)kc.Children.First().Trigger).Key;
void addPressKeyStep()
{
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs
index 56cf56efd9..432ff2fc7e 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs
@@ -53,7 +53,7 @@ namespace osu.Game.Tests.Visual.Gameplay
};
// Add any key just to display the key counter visually.
- hudOverlay.KeyCounter.Add(hudOverlay.KeyCounter.CreateKeyCounter(new KeyCounterKeyboard(Key.Space)));
+ hudOverlay.KeyCounter.Add(hudOverlay.KeyCounter.CreateKeyCounter(new KeyCounterKeyboardTrigger(Key.Space)));
scoreProcessor.Combo.Value = 1;
return new Container
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs
index f713bca081..24de29fa03 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs
@@ -88,7 +88,7 @@ namespace osu.Game.Tests.Visual.Gameplay
hudOverlay = new HUDOverlay(null, Array.Empty());
// Add any key just to display the key counter visually.
- hudOverlay.KeyCounter.Add(hudOverlay.KeyCounter.CreateKeyCounter(new KeyCounterKeyboard(Key.Space)));
+ hudOverlay.KeyCounter.Add(hudOverlay.KeyCounter.CreateKeyCounter(new KeyCounterKeyboardTrigger(Key.Space)));
action?.Invoke(hudOverlay);
diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs
index 22dc6567eb..6a38fa4824 100644
--- a/osu.Game/Rulesets/UI/RulesetInputManager.cs
+++ b/osu.Game/Rulesets/UI/RulesetInputManager.cs
@@ -166,7 +166,7 @@ namespace osu.Game.Rulesets.UI
.Select(b => b.GetAction())
.Distinct()
.OrderBy(action => action)
- .Select(action => keyCounter.CreateKeyCounter(new KeyCounterAction(action))));
+ .Select(action => keyCounter.CreateKeyCounter(new KeyCounterActionTrigger(action))));
}
private partial class ActionReceptor : KeyCounterDisplay.Receptor, IKeyBindingHandler
@@ -176,14 +176,14 @@ namespace osu.Game.Rulesets.UI
{
}
- public bool OnPressed(KeyBindingPressEvent e) => Target.Children.Where(c => c.Trigger is KeyCounterAction)
- .Select(c => (KeyCounterAction)c.Trigger)
+ public bool OnPressed(KeyBindingPressEvent e) => Target.Children.Where(c => c.Trigger is KeyCounterActionTrigger)
+ .Select(c => (KeyCounterActionTrigger)c.Trigger)
.Any(c => c.OnPressed(e.Action, Clock.Rate >= 0));
public void OnReleased(KeyBindingReleaseEvent e)
{
foreach (var c
- in Target.Children.Where(c => c.Trigger is KeyCounterAction).Select(c => (KeyCounterAction)c.Trigger))
+ in Target.Children.Where(c => c.Trigger is KeyCounterActionTrigger).Select(c => (KeyCounterActionTrigger)c.Trigger))
c.OnReleased(e.Action, Clock.Rate >= 0);
}
}
diff --git a/osu.Game/Screens/Play/KeyCounterAction.cs b/osu.Game/Screens/Play/KeyCounterActionTrigger.cs
similarity index 86%
rename from osu.Game/Screens/Play/KeyCounterAction.cs
rename to osu.Game/Screens/Play/KeyCounterActionTrigger.cs
index 65a0bc2ca7..51b82ac5e5 100644
--- a/osu.Game/Screens/Play/KeyCounterAction.cs
+++ b/osu.Game/Screens/Play/KeyCounterActionTrigger.cs
@@ -7,12 +7,12 @@ using System.Collections.Generic;
namespace osu.Game.Screens.Play
{
- public partial class KeyCounterAction : KeyCounter.InputTrigger
+ public partial class KeyCounterActionTrigger : KeyCounter.InputTrigger
where T : struct
{
public T Action { get; }
- public KeyCounterAction(T action)
+ public KeyCounterActionTrigger(T action)
: base($"B{(int)(object)action + 1}")
{
Action = action;
diff --git a/osu.Game/Screens/Play/KeyCounterKeyboard.cs b/osu.Game/Screens/Play/KeyCounterKeyboardTrigger.cs
similarity index 85%
rename from osu.Game/Screens/Play/KeyCounterKeyboard.cs
rename to osu.Game/Screens/Play/KeyCounterKeyboardTrigger.cs
index ef1f207556..fee716abf4 100644
--- a/osu.Game/Screens/Play/KeyCounterKeyboard.cs
+++ b/osu.Game/Screens/Play/KeyCounterKeyboardTrigger.cs
@@ -8,11 +8,11 @@ using osuTK.Input;
namespace osu.Game.Screens.Play
{
- public partial class KeyCounterKeyboard : KeyCounter.InputTrigger
+ public partial class KeyCounterKeyboardTrigger : KeyCounter.InputTrigger
{
public Key Key { get; }
- public KeyCounterKeyboard(Key key)
+ public KeyCounterKeyboardTrigger(Key key)
: base(key.ToString())
{
Key = key;
diff --git a/osu.Game/Screens/Play/KeyCounterMouse.cs b/osu.Game/Screens/Play/KeyCounterMouseTrigger.cs
similarity index 90%
rename from osu.Game/Screens/Play/KeyCounterMouse.cs
rename to osu.Game/Screens/Play/KeyCounterMouseTrigger.cs
index cf0e0a394f..a693db9b19 100644
--- a/osu.Game/Screens/Play/KeyCounterMouse.cs
+++ b/osu.Game/Screens/Play/KeyCounterMouseTrigger.cs
@@ -9,11 +9,11 @@ using osuTK;
namespace osu.Game.Screens.Play
{
- public partial class KeyCounterMouse : KeyCounter.InputTrigger
+ public partial class KeyCounterMouseTrigger : KeyCounter.InputTrigger
{
public MouseButton Button { get; }
- public KeyCounterMouse(MouseButton button)
+ public KeyCounterMouseTrigger(MouseButton button)
: base(getStringRepresentation(button))
{
Button = button;
From b0a2e69f951910907559d16fc2392a4d9867cd99 Mon Sep 17 00:00:00 2001
From: tsrk
Date: Wed, 15 Feb 2023 22:06:10 +0000
Subject: [PATCH 0106/1400] style: nullable pass on `KeyCounterDisplay`
---
osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs | 11 +++++------
osu.Game/Screens/Play/KeyCounterDisplay.cs | 6 ++----
2 files changed, 7 insertions(+), 10 deletions(-)
diff --git a/osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs b/osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs
index d643070e06..332474a517 100644
--- a/osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs
+++ b/osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs
@@ -24,12 +24,11 @@ namespace osu.Game.Screens.Play
public DefaultKeyCounterDisplay()
{
- InternalChild = KeyFlow = new FillFlowContainer
- {
- Direction = FillDirection.Horizontal,
- AutoSizeAxes = Axes.Both,
- Alpha = 0,
- };
+ KeyFlow.Direction = FillDirection.Horizontal;
+ KeyFlow.AutoSizeAxes = Axes.Both;
+ KeyFlow.Alpha = 0;
+
+ InternalChild = KeyFlow;
}
protected override void Update()
diff --git a/osu.Game/Screens/Play/KeyCounterDisplay.cs b/osu.Game/Screens/Play/KeyCounterDisplay.cs
index fc6fa12f10..f5af67caea 100644
--- a/osu.Game/Screens/Play/KeyCounterDisplay.cs
+++ b/osu.Game/Screens/Play/KeyCounterDisplay.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Linq;
using osu.Framework.Allocation;
@@ -19,7 +17,7 @@ namespace osu.Game.Screens.Play
{
protected readonly Bindable ConfigVisibility = new Bindable();
- protected FillFlowContainer KeyFlow;
+ protected FillFlowContainer KeyFlow = new FillFlowContainer();
protected override Container Content => KeyFlow;
@@ -71,7 +69,7 @@ namespace osu.Game.Screens.Play
public override bool HandleNonPositionalInput => receptor == null;
public override bool HandlePositionalInput => receptor == null;
- private Receptor receptor;
+ private Receptor? receptor;
public void SetReceptor(Receptor receptor)
{
From e9dcc257b48ae26302c598df7d433e09007a40ba Mon Sep 17 00:00:00 2001
From: tsrk
Date: Wed, 15 Feb 2023 22:06:35 +0000
Subject: [PATCH 0107/1400] reafactor: simplify type checking
---
osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs | 6 +++---
osu.Game/Screens/Play/KeyCounterDisplay.cs | 5 ++++-
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs b/osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs
index 332474a517..b69ecfd7ae 100644
--- a/osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs
+++ b/osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs
@@ -1,7 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using System;
using System.Collections.Generic;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@@ -43,14 +42,15 @@ namespace osu.Game.Screens.Play
public override void Add(KeyCounter key)
{
base.Add(key);
- if (key is not DefaultKeyCounter defaultKey)
- throw new ArgumentException($"{key.GetType()} is not a supported {nameof(KeyCounter)}.", nameof(key));
+ DefaultKeyCounter defaultKey = (DefaultKeyCounter)key;
defaultKey.FadeTime = key_fade_time;
defaultKey.KeyDownTextColor = KeyDownTextColor;
defaultKey.KeyUpTextColor = KeyUpTextColor;
}
+ protected override bool CheckType(KeyCounter key) => key is DefaultKeyCounter;
+
protected override void UpdateVisibility() =>
// Isolate changing visibility of the key counters from fading this component.
KeyFlow.FadeTo(AlwaysVisible.Value || ConfigVisibility.Value ? 1 : 0, duration);
diff --git a/osu.Game/Screens/Play/KeyCounterDisplay.cs b/osu.Game/Screens/Play/KeyCounterDisplay.cs
index f5af67caea..ed47af11a3 100644
--- a/osu.Game/Screens/Play/KeyCounterDisplay.cs
+++ b/osu.Game/Screens/Play/KeyCounterDisplay.cs
@@ -29,12 +29,15 @@ namespace osu.Game.Screens.Play
public override void Add(KeyCounter key)
{
- ArgumentNullException.ThrowIfNull(key);
+ if (!CheckType(key))
+ throw new ArgumentException($"{key.GetType()} is not a supported {nameof(KeyCounter)}.", nameof(key));
base.Add(key);
key.IsCounting = IsCounting;
}
+ protected virtual bool CheckType(KeyCounter key) => true;
+
[BackgroundDependencyLoader]
private void load(OsuConfigManager config)
{
From 74e7cc205601bc4edb9d88e12afb8c63f8e967d2 Mon Sep 17 00:00:00 2001
From: tsrk
Date: Wed, 15 Feb 2023 22:18:02 +0000
Subject: [PATCH 0108/1400] feat: implement new design of key counter
---
.../Visual/Gameplay/TestSceneKeyCounter.cs | 39 +++++++---
osu.Game/Screens/Play/ArgonKeyCounter.cs | 76 +++++++++++++++++++
.../Screens/Play/ArgonKeyCounterDisplay.cs | 42 ++++++++++
3 files changed, 147 insertions(+), 10 deletions(-)
create mode 100644 osu.Game/Screens/Play/ArgonKeyCounter.cs
create mode 100644 osu.Game/Screens/Play/ArgonKeyCounterDisplay.cs
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs
index 975a5c9465..41add82245 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs
@@ -8,6 +8,7 @@ using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Utils;
using osu.Game.Screens.Play;
+using osuTK;
using osuTK.Input;
namespace osu.Game.Tests.Visual.Gameplay
@@ -18,24 +19,44 @@ namespace osu.Game.Tests.Visual.Gameplay
public TestSceneKeyCounter()
{
DefaultKeyCounter testCounter;
+ KeyCounterDisplay kc;
+ KeyCounterDisplay argonKc;
- KeyCounterDisplay kc = new DefaultKeyCounterDisplay
+ Children = new Drawable[]
{
- Origin = Anchor.Centre,
- Anchor = Anchor.Centre,
- Children = new[]
+ kc = new DefaultKeyCounterDisplay
{
- testCounter = new DefaultKeyCounter(new KeyCounterKeyboardTrigger(Key.X)),
- new DefaultKeyCounter(new KeyCounterKeyboardTrigger(Key.X)),
- new DefaultKeyCounter(new KeyCounterMouseTrigger(MouseButton.Left)),
- new DefaultKeyCounter(new KeyCounterMouseTrigger(MouseButton.Right)),
+ Origin = Anchor.Centre,
+ Anchor = Anchor.Centre,
+ Position = new Vector2(0, -50),
+ Children = new[]
+ {
+ testCounter = new DefaultKeyCounter(new KeyCounterKeyboardTrigger(Key.X)),
+ new DefaultKeyCounter(new KeyCounterKeyboardTrigger(Key.X)),
+ new DefaultKeyCounter(new KeyCounterMouseTrigger(MouseButton.Left)),
+ new DefaultKeyCounter(new KeyCounterMouseTrigger(MouseButton.Right)),
+ },
},
+ argonKc = new ArgonKeyCounterDisplay
+ {
+ Origin = Anchor.Centre,
+ Anchor = Anchor.Centre,
+ Position = new Vector2(0, 50),
+ Children = new[]
+ {
+ new ArgonKeyCounter(new KeyCounterKeyboardTrigger(Key.X)),
+ new ArgonKeyCounter(new KeyCounterKeyboardTrigger(Key.X)),
+ new ArgonKeyCounter(new KeyCounterMouseTrigger(MouseButton.Left)),
+ new ArgonKeyCounter(new KeyCounterMouseTrigger(MouseButton.Right)),
+ },
+ }
};
AddStep("Add random", () =>
{
Key key = (Key)((int)Key.A + RNG.Next(26));
kc.Add(kc.CreateKeyCounter(new KeyCounterKeyboardTrigger(key)));
+ argonKc.Add(argonKc.CreateKeyCounter(new KeyCounterKeyboardTrigger(key)));
});
Key testKey = ((KeyCounterKeyboardTrigger)kc.Children.First().Trigger).Key;
@@ -52,8 +73,6 @@ namespace osu.Game.Tests.Visual.Gameplay
AddStep("Disable counting", () => testCounter.IsCounting = false);
addPressKeyStep();
AddAssert($"Check {testKey} count has not changed", () => testCounter.CountPresses == 2);
-
- Add(kc);
}
}
}
diff --git a/osu.Game/Screens/Play/ArgonKeyCounter.cs b/osu.Game/Screens/Play/ArgonKeyCounter.cs
new file mode 100644
index 0000000000..a275a7e017
--- /dev/null
+++ b/osu.Game/Screens/Play/ArgonKeyCounter.cs
@@ -0,0 +1,76 @@
+// Copyright (c) ppy Pty Ltd . 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.Shapes;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Sprites;
+using osuTK;
+
+namespace osu.Game.Screens.Play
+{
+ public partial class ArgonKeyCounter : KeyCounter
+ {
+ private Circle inputIndicator = null!;
+ private OsuSpriteText countText = null!;
+
+ // These values were taken from Figma
+ private const float line_height = 3;
+ private const float name_font_size = 10;
+ private const float count_font_size = 14;
+
+ // Make things look bigger without using Scale
+ private const float scale_factor = 1.5f;
+
+ public ArgonKeyCounter(InputTrigger trigger)
+ : base(trigger)
+ {
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours)
+ {
+ Children = new Drawable[]
+ {
+ inputIndicator = new Circle
+ {
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre,
+ RelativeSizeAxes = Axes.X,
+ Height = line_height * scale_factor,
+ Alpha = 0.5f
+ },
+ new OsuSpriteText
+ {
+ Anchor = Anchor.BottomLeft,
+ Origin = Anchor.BottomLeft,
+ Position = new Vector2(0, -13) * scale_factor,
+ Font = OsuFont.Torus.With(size: name_font_size * scale_factor, weight: FontWeight.Bold),
+ Colour = colours.Blue0,
+ Text = Name
+ },
+ countText = new OsuSpriteText
+ {
+ Anchor = Anchor.BottomLeft,
+ Origin = Anchor.BottomLeft,
+ Font = OsuFont.Torus.With(size: count_font_size * scale_factor, weight: FontWeight.Bold),
+ Text = "0"
+ },
+ };
+
+ // Values from Figma didn't match visually
+ // So these were just eyeballed
+ Height = 30 * scale_factor;
+ Width = 35 * scale_factor;
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ IsLit.BindValueChanged(e => inputIndicator.Alpha = e.NewValue ? 1 : 0.5f, true);
+ PressesCount.BindValueChanged(e => countText.Text = e.NewValue.ToString(@"#,0"), true);
+ }
+ }
+}
diff --git a/osu.Game/Screens/Play/ArgonKeyCounterDisplay.cs b/osu.Game/Screens/Play/ArgonKeyCounterDisplay.cs
new file mode 100644
index 0000000000..da34a64a4c
--- /dev/null
+++ b/osu.Game/Screens/Play/ArgonKeyCounterDisplay.cs
@@ -0,0 +1,42 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Collections.Generic;
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osuTK;
+
+namespace osu.Game.Screens.Play
+{
+ public partial class ArgonKeyCounterDisplay : KeyCounterDisplay
+ {
+ private const int duration = 100;
+
+ public new IReadOnlyList Children
+ {
+ get => (IReadOnlyList)base.Children;
+ set => base.Children = value;
+ }
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ KeyFlow.Direction = FillDirection.Horizontal;
+ KeyFlow.AutoSizeAxes = Axes.Both;
+ KeyFlow.Spacing = new Vector2(2);
+
+ InternalChildren = new[]
+ {
+ KeyFlow
+ };
+ }
+
+ protected override bool CheckType(KeyCounter key) => key is ArgonKeyCounter;
+
+ protected override void UpdateVisibility()
+ => KeyFlow.FadeTo(AlwaysVisible.Value || ConfigVisibility.Value ? 1 : 0, duration);
+
+ public override KeyCounter CreateKeyCounter(KeyCounter.InputTrigger trigger) => new ArgonKeyCounter(trigger);
+ }
+}
From d5bc8e2941fc0a6d948fda24546cc976b12165fa Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Thu, 16 Feb 2023 11:12:30 +0100
Subject: [PATCH 0109/1400] Code cleanup pass:
Make bubble transform logic more sane.
Extract bubble `getPosition()` method.
Address poorly named variables.
---
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 47 +++++++++++----------
1 file changed, 25 insertions(+), 22 deletions(-)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index 4edf726f26..0fc27c8f1d 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -45,7 +45,7 @@ namespace osu.Game.Rulesets.Osu.Mods
private readonly Bindable currentCombo = new BindableInt();
private float maxSize;
- private float bubbleRadius;
+ private float bubbleSize;
private double bubbleFade;
private readonly DrawablePool bubblePool = new DrawablePool(100);
@@ -63,7 +63,7 @@ namespace osu.Game.Rulesets.Osu.Mods
{
// Multiplying by 2 results in an initial size that is too large, hence 1.90 has been chosen
// Also avoids the HitObject bleeding around the edges of the bubble drawable at minimum size
- bubbleRadius = (float)(drawableRuleset.Beatmap.HitObjects.OfType().First().Radius * 1.90f);
+ bubbleSize = (float)(drawableRuleset.Beatmap.HitObjects.OfType().First().Radius * 1.90f);
bubbleFade = drawableRuleset.Beatmap.HitObjects.OfType().First().TimePreempt * 2;
// We want to hide the judgements since they are obscured by the BubbleDrawable (due to layering)
@@ -96,7 +96,7 @@ namespace osu.Game.Rulesets.Osu.Mods
BubbleDrawable bubble = bubblePool.Get();
bubble.DrawableOsuHitObject = drawableOsuHitObject;
- bubble.InitialSize = new Vector2(bubbleRadius);
+ bubble.InitialSize = new Vector2(bubbleSize);
bubble.FadeTime = bubbleFade;
bubble.MaxSize = maxSize;
@@ -122,9 +122,11 @@ namespace osu.Game.Rulesets.Osu.Mods
public DrawableOsuHitObject? DrawableOsuHitObject { get; set; }
public Vector2 InitialSize { get; set; }
- public double FadeTime { get; set; }
+
public float MaxSize { get; set; }
+ public double FadeTime { get; set; }
+
private readonly Box colourBox;
private readonly CircularContainer content;
@@ -155,12 +157,9 @@ namespace osu.Game.Rulesets.Osu.Mods
Debug.Assert(DrawableOsuHitObject.IsNotNull());
Colour = DrawableOsuHitObject.IsHit ? Colour4.White : Colour4.Black;
- Alpha = 1;
Scale = new Vector2(1);
- Position = getPosition();
+ Position = getPosition(DrawableOsuHitObject);
Size = InitialSize;
- content.BorderThickness = InitialSize.X / 3.5f;
- content.BorderColour = Colour4.White;
//We want to fade to a darker colour to avoid colours such as white hiding the "ripple" effect.
ColourInfo colourDarker = DrawableOsuHitObject.AccentColour.Value.Darken(0.1f);
@@ -169,7 +168,8 @@ namespace osu.Game.Rulesets.Osu.Mods
double getAnimationDuration = 1700 + Math.Pow(FadeTime, 1.07f);
// Main bubble scaling based on combo
- this.ScaleTo(MaxSize, getAnimationDuration * 0.8f)
+ this.FadeTo(1)
+ .ScaleTo(MaxSize, getAnimationDuration * 0.8f)
.Then()
// Pop at the end of the bubbles life time
.ScaleTo(MaxSize * 1.5f, getAnimationDuration * 0.2f, Easing.OutQuint)
@@ -177,6 +177,9 @@ namespace osu.Game.Rulesets.Osu.Mods
if (!DrawableOsuHitObject.IsHit) return;
+ content.BorderThickness = InitialSize.X / 3.5f;
+ content.BorderColour = Colour4.White;
+
colourBox.FadeColour(colourDarker);
content.TransformTo(nameof(BorderColour), colourDarker, getAnimationDuration * 0.3f, Easing.OutQuint);
@@ -184,23 +187,23 @@ namespace osu.Game.Rulesets.Osu.Mods
content.TransformTo(nameof(BorderThickness), 2f, getAnimationDuration * 0.3f, Easing.OutQuint)
// Avoids transparency overlap issues during the bubble "pop"
.Then().Schedule(() => content.BorderThickness = 0);
+ }
- Vector2 getPosition()
+ private Vector2 getPosition(DrawableOsuHitObject drawableOsuHitObject)
+ {
+ switch (drawableOsuHitObject)
{
- switch (DrawableOsuHitObject)
- {
- // SliderHeads are derived from HitCircles,
- // so we must handle them before to avoid them using the wrong positioning logic
- case DrawableSliderHead:
- return DrawableOsuHitObject.HitObject.Position;
+ // SliderHeads are derived from HitCircles,
+ // so we must handle them before to avoid them using the wrong positioning logic
+ case DrawableSliderHead:
+ return drawableOsuHitObject.HitObject.Position;
- // Using hitobject position will cause issues with HitCircle placement due to stack leniency.
- case DrawableHitCircle:
- return DrawableOsuHitObject.Position;
+ // Using hitobject position will cause issues with HitCircle placement due to stack leniency.
+ case DrawableHitCircle:
+ return drawableOsuHitObject.Position;
- default:
- return DrawableOsuHitObject.HitObject.Position;
- }
+ default:
+ return drawableOsuHitObject.HitObject.Position;
}
}
}
From f1da213beaaaba85b82c785def1c43f6cb1f62ec Mon Sep 17 00:00:00 2001
From: Cootz
Date: Thu, 16 Feb 2023 16:26:57 +0300
Subject: [PATCH 0110/1400] Add tests
---
osu.Game.Tests/Database/LegacyExporterTest.cs | 85 +++++++++++++++++++
osu.Game/Database/LegacyExporter.cs | 6 +-
2 files changed, 88 insertions(+), 3 deletions(-)
create mode 100644 osu.Game.Tests/Database/LegacyExporterTest.cs
diff --git a/osu.Game.Tests/Database/LegacyExporterTest.cs b/osu.Game.Tests/Database/LegacyExporterTest.cs
new file mode 100644
index 0000000000..5f07e6c917
--- /dev/null
+++ b/osu.Game.Tests/Database/LegacyExporterTest.cs
@@ -0,0 +1,85 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Text;
+using NUnit.Framework;
+using osu.Framework.Platform;
+using osu.Framework.Testing;
+using osu.Game.Database;
+
+namespace osu.Game.Tests.Database
+{
+ public class LegacyExporterTest
+ {
+ private TestLegacyExporter? legacyExporter;
+ private TemporaryNativeStorage? storage;
+
+ [SetUp]
+ public void SetupLegacyExporter()
+ {
+ storage = new TemporaryNativeStorage("export-storage");
+ legacyExporter = new TestLegacyExporter(storage);
+ }
+
+ [Test]
+ public void ExportFileWithNormalName()
+ {
+ var exportStorage = storage?.GetStorageForDirectory(@"exports");
+
+ string filename = "normal file name";
+ var item = new TestPathInfo(filename);
+
+ Assert.That(item.FileName.Length < TestLegacyExporter.GetMaxPath(), Is.True);
+ Assert.DoesNotThrow(() => legacyExporter?.Export(item));
+ Assert.That(exportStorage?.Exists($"{filename}{legacyExporter?.GetExtension()}"), Is.True);
+ }
+
+ [Test]
+ public void ExportFileWithSuperLongName()
+ {
+ var exportStorage = storage?.GetStorageForDirectory(@"exports");
+
+ string fullname = "some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name";
+
+ int capacity = TestLegacyExporter.GetMaxPath() - (legacyExporter?.GetExtension().Length ?? 0);
+ string expectedName = fullname.Remove(capacity);
+
+ var item = new TestPathInfo(fullname);
+
+ Assert.That(item.FileName.Length > TestLegacyExporter.GetMaxPath(), Is.True);
+ Assert.DoesNotThrow(() => legacyExporter?.Export(item));
+ Assert.That(exportStorage?.Exists($"{expectedName}{legacyExporter?.GetExtension()}"), Is.True);
+ }
+
+ [TearDown]
+ public void CleanupAfterTest()
+ {
+ storage?.Dispose();
+ }
+
+ private class TestPathInfo : IHasNamedFiles
+ {
+ public string FileName { get; set; } = string.Empty;
+
+ public TestPathInfo(string fileName) => FileName = fileName;
+
+ public IEnumerable Files { get; set; } = new List();
+
+ public override string ToString() => FileName;
+ }
+
+ private class TestLegacyExporter : LegacyExporter
+ {
+ public TestLegacyExporter(Storage storage) : base(storage) { }
+
+ public static int GetMaxPath() => MAX_PATH;
+
+ public string GetExtension() => FileExtension;
+
+ protected override string FileExtension => ".ots";
+ }
+ }
+}
diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs
index 483c3cbd5c..9041f58368 100644
--- a/osu.Game/Database/LegacyExporter.cs
+++ b/osu.Game/Database/LegacyExporter.cs
@@ -26,7 +26,7 @@ namespace osu.Game.Database
///
/// This constant is smaller 256 because adds additional "_" to the end of the path
///
- private const int max_path = 255 - (32 + 4 + 2); //max path - (Guid + Guid "D" format chars + Storage.CreateFileSafely chars)
+ protected const int MAX_PATH = 255 - (32 + 4 + 2); //max path - (Guid + Guid "D" format chars + Storage.CreateFileSafely chars)
///
/// The file extension for exports (including the leading '.').
@@ -60,11 +60,11 @@ namespace osu.Game.Database
string filename = NamingUtils.GetNextBestFilename(existingExports, $"{itemFilename}{FileExtension}");
- if (filename.Length > max_path)
+ if (filename.Length > MAX_PATH)
{
string filenameWithoutExtension = Path.GetFileNameWithoutExtension(filename);
- filenameWithoutExtension = filenameWithoutExtension.Remove(max_path - FileExtension.Length); //Truncating the name to fit the path limit
+ filenameWithoutExtension = filenameWithoutExtension.Remove(MAX_PATH - FileExtension.Length); //Truncating the name to fit the path limit
filename = $"{filenameWithoutExtension}{FileExtension}";
}
From 6819a45a1bdba3fdd2b28a6d7983b73116ddbded Mon Sep 17 00:00:00 2001
From: Cootz
Date: Thu, 16 Feb 2023 16:42:07 +0300
Subject: [PATCH 0111/1400] Improve code slightly
---
osu.Game.Tests/Database/LegacyExporterTest.cs | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/osu.Game.Tests/Database/LegacyExporterTest.cs b/osu.Game.Tests/Database/LegacyExporterTest.cs
index 5f07e6c917..c464eb5c28 100644
--- a/osu.Game.Tests/Database/LegacyExporterTest.cs
+++ b/osu.Game.Tests/Database/LegacyExporterTest.cs
@@ -2,9 +2,6 @@
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.Text;
using NUnit.Framework;
using osu.Framework.Platform;
using osu.Framework.Testing;
@@ -29,7 +26,7 @@ namespace osu.Game.Tests.Database
{
var exportStorage = storage?.GetStorageForDirectory(@"exports");
- string filename = "normal file name";
+ const string filename = "normal file name";
var item = new TestPathInfo(filename);
Assert.That(item.FileName.Length < TestLegacyExporter.GetMaxPath(), Is.True);
@@ -42,7 +39,7 @@ namespace osu.Game.Tests.Database
{
var exportStorage = storage?.GetStorageForDirectory(@"exports");
- string fullname = "some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name";
+ const string fullname = "some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name";
int capacity = TestLegacyExporter.GetMaxPath() - (legacyExporter?.GetExtension().Length ?? 0);
string expectedName = fullname.Remove(capacity);
@@ -62,7 +59,7 @@ namespace osu.Game.Tests.Database
private class TestPathInfo : IHasNamedFiles
{
- public string FileName { get; set; } = string.Empty;
+ public string FileName { get; set; }
public TestPathInfo(string fileName) => FileName = fileName;
@@ -73,7 +70,10 @@ namespace osu.Game.Tests.Database
private class TestLegacyExporter : LegacyExporter
{
- public TestLegacyExporter(Storage storage) : base(storage) { }
+ public TestLegacyExporter(Storage storage)
+ : base(storage)
+ {
+ }
public static int GetMaxPath() => MAX_PATH;
From 6340730427908b839aaa3d00c82497818cec93e1 Mon Sep 17 00:00:00 2001
From: tsrk
Date: Thu, 16 Feb 2023 21:59:39 +0000
Subject: [PATCH 0112/1400] refactor(KeyCounter): remove circularity
---
.../TestSceneOsuTouchInput.cs | 2 +-
osu.Game/Screens/Play/KeyCounter.cs | 52 +++++++++++--------
.../Screens/Play/KeyCounterActionTrigger.cs | 2 +-
.../Screens/Play/KeyCounterKeyboardTrigger.cs | 2 +-
.../Screens/Play/KeyCounterMouseTrigger.cs | 2 +-
5 files changed, 33 insertions(+), 27 deletions(-)
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
index 950e034d8f..c73025ebb9 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
@@ -593,7 +593,7 @@ namespace osu.Game.Rulesets.Osu.Tests
{
if (e.Action == Action)
{
- Light();
+ LightUp();
}
return false;
diff --git a/osu.Game/Screens/Play/KeyCounter.cs b/osu.Game/Screens/Play/KeyCounter.cs
index 4a7203870c..3748792383 100644
--- a/osu.Game/Screens/Play/KeyCounter.cs
+++ b/osu.Game/Screens/Play/KeyCounter.cs
@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@@ -45,7 +46,9 @@ namespace osu.Game.Screens.Play
Trigger = trigger,
};
- Trigger.Target = this;
+ Trigger.OnLightUp += LightUp;
+ Trigger.OnUnlight += Unlight;
+
Name = trigger.Name;
}
@@ -67,37 +70,40 @@ namespace osu.Game.Screens.Play
CountPresses--;
}
+ protected virtual void LightUp(bool increment = true)
+ {
+ IsLit.Value = true;
+ if (increment)
+ Increment();
+ }
+
+ protected virtual void Unlight(bool preserve = true)
+ {
+ IsLit.Value = false;
+ if (!preserve)
+ Decrement();
+ }
+
+ protected override void Dispose(bool isDisposing)
+ {
+ base.Dispose(isDisposing);
+ Trigger.OnLightUp -= LightUp;
+ Trigger.OnUnlight -= Unlight;
+ }
+
public abstract partial class InputTrigger : Component
{
- private KeyCounter? target;
-
- public KeyCounter Target
- {
- set => target = value;
- }
+ public event Action? OnLightUp;
+ public event Action? OnUnlight;
protected InputTrigger(string name)
{
Name = name;
}
- protected void Light(bool increment = true)
- {
- if (target == null) return;
+ protected void LightUp(bool increment = true) => OnLightUp?.Invoke(increment);
- target.IsLit.Value = true;
- if (increment)
- target.Increment();
- }
-
- protected void Unlight(bool preserve = true)
- {
- if (target == null) return;
-
- target.IsLit.Value = false;
- if (!preserve)
- target.Decrement();
- }
+ protected void Unlight(bool preserve = true) => OnUnlight?.Invoke(preserve);
}
}
}
diff --git a/osu.Game/Screens/Play/KeyCounterActionTrigger.cs b/osu.Game/Screens/Play/KeyCounterActionTrigger.cs
index 51b82ac5e5..c6acb3f95f 100644
--- a/osu.Game/Screens/Play/KeyCounterActionTrigger.cs
+++ b/osu.Game/Screens/Play/KeyCounterActionTrigger.cs
@@ -23,7 +23,7 @@ namespace osu.Game.Screens.Play
if (!EqualityComparer.Default.Equals(action, Action))
return false;
- Light(forwards);
+ LightUp(forwards);
return false;
}
diff --git a/osu.Game/Screens/Play/KeyCounterKeyboardTrigger.cs b/osu.Game/Screens/Play/KeyCounterKeyboardTrigger.cs
index fee716abf4..18eb6b7612 100644
--- a/osu.Game/Screens/Play/KeyCounterKeyboardTrigger.cs
+++ b/osu.Game/Screens/Play/KeyCounterKeyboardTrigger.cs
@@ -22,7 +22,7 @@ namespace osu.Game.Screens.Play
{
if (e.Key == Key)
{
- Light();
+ LightUp();
}
return base.OnKeyDown(e);
diff --git a/osu.Game/Screens/Play/KeyCounterMouseTrigger.cs b/osu.Game/Screens/Play/KeyCounterMouseTrigger.cs
index a693db9b19..1446494b5b 100644
--- a/osu.Game/Screens/Play/KeyCounterMouseTrigger.cs
+++ b/osu.Game/Screens/Play/KeyCounterMouseTrigger.cs
@@ -39,7 +39,7 @@ namespace osu.Game.Screens.Play
protected override bool OnMouseDown(MouseDownEvent e)
{
if (e.Button == Button)
- Light();
+ LightUp();
return base.OnMouseDown(e);
}
From ddd6c1a1c671c24f33479eceff34f7acf05b5cc7 Mon Sep 17 00:00:00 2001
From: tsrk
Date: Thu, 16 Feb 2023 22:20:34 +0000
Subject: [PATCH 0113/1400] refactor(KeyCounter): address bindables issues
`IsCounting` is back being an auto-property.
`countPresses` is now encapsulated and being exposed as an
`IBindable` via `CountPresses`
---
.../Visual/Gameplay/TestSceneAutoplay.cs | 4 ++--
.../Gameplay/TestSceneGameplayRewinding.cs | 4 ++--
.../Visual/Gameplay/TestSceneKeyCounter.cs | 6 +++---
.../Visual/Gameplay/TestSceneReplay.cs | 2 +-
.../TestSceneChangeAndUseGameplayBindings.cs | 4 ++--
osu.Game/Screens/Play/DefaultKeyCounter.cs | 4 ++--
osu.Game/Screens/Play/KeyCounter.cs | 20 +++++--------------
7 files changed, 17 insertions(+), 27 deletions(-)
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs
index 5442b3bfef..4b6e1f089f 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs
@@ -35,14 +35,14 @@ namespace osu.Game.Tests.Visual.Gameplay
var referenceBeatmap = CreateBeatmap(new OsuRuleset().RulesetInfo);
AddUntilStep("score above zero", () => Player.ScoreProcessor.TotalScore.Value > 0);
- AddUntilStep("key counter counted keys", () => Player.HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses > 2));
+ AddUntilStep("key counter counted keys", () => Player.HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses.Value > 2));
seekTo(referenceBeatmap.Breaks[0].StartTime);
AddAssert("keys not counting", () => !Player.HUDOverlay.KeyCounter.IsCounting);
AddAssert("overlay displays 100% accuracy", () => Player.BreakOverlay.ChildrenOfType().Single().AccuracyDisplay.Current.Value == 1);
AddStep("rewind", () => Player.GameplayClockContainer.Seek(-80000));
- AddUntilStep("key counter reset", () => Player.HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses == 0));
+ AddUntilStep("key counter reset", () => Player.HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses.Value == 0));
seekTo(referenceBeatmap.HitObjects[^1].GetEndTime());
AddUntilStep("results displayed", () => getResultsScreen()?.IsLoaded == true);
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs
index 1dffeed01b..9f485cd7bf 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs
@@ -31,11 +31,11 @@ namespace osu.Game.Tests.Visual.Gameplay
AddUntilStep("wait for track to start running", () => Beatmap.Value.Track.IsRunning);
addSeekStep(3000);
AddAssert("all judged", () => Player.DrawableRuleset.Playfield.AllHitObjects.All(h => h.Judged));
- AddUntilStep("key counter counted keys", () => Player.HUDOverlay.KeyCounter.Children.Select(kc => kc.CountPresses).Sum() == 15);
+ AddUntilStep("key counter counted keys", () => Player.HUDOverlay.KeyCounter.Children.Select(kc => kc.CountPresses.Value).Sum() == 15);
AddStep("clear results", () => Player.Results.Clear());
addSeekStep(0);
AddAssert("none judged", () => Player.DrawableRuleset.Playfield.AllHitObjects.All(h => !h.Judged));
- AddUntilStep("key counters reset", () => Player.HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses == 0));
+ AddUntilStep("key counters reset", () => Player.HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses.Value == 0));
AddAssert("no results triggered", () => Player.Results.Count == 0);
}
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs
index 975a5c9465..9eeee800d9 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs
@@ -46,12 +46,12 @@ namespace osu.Game.Tests.Visual.Gameplay
}
addPressKeyStep();
- AddAssert($"Check {testKey} counter after keypress", () => testCounter.CountPresses == 1);
+ AddAssert($"Check {testKey} counter after keypress", () => testCounter.CountPresses.Value == 1);
addPressKeyStep();
- AddAssert($"Check {testKey} counter after keypress", () => testCounter.CountPresses == 2);
+ AddAssert($"Check {testKey} counter after keypress", () => testCounter.CountPresses.Value == 2);
AddStep("Disable counting", () => testCounter.IsCounting = false);
addPressKeyStep();
- AddAssert($"Check {testKey} count has not changed", () => testCounter.CountPresses == 2);
+ AddAssert($"Check {testKey} count has not changed", () => testCounter.CountPresses.Value == 2);
Add(kc);
}
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneReplay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneReplay.cs
index c476aae202..542686f0cd 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneReplay.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneReplay.cs
@@ -27,7 +27,7 @@ namespace osu.Game.Tests.Visual.Gameplay
protected override void AddCheckSteps()
{
AddUntilStep("score above zero", () => ((ScoreAccessibleReplayPlayer)Player).ScoreProcessor.TotalScore.Value > 0);
- AddUntilStep("key counter counted keys", () => ((ScoreAccessibleReplayPlayer)Player).HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses > 0));
+ AddUntilStep("key counter counted keys", () => ((ScoreAccessibleReplayPlayer)Player).HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses.Value > 0));
AddAssert("cannot fail", () => !((ScoreAccessibleReplayPlayer)Player).AllowFail);
}
diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs b/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs
index d937b9e6d7..59a0f9cea8 100644
--- a/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs
+++ b/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs
@@ -69,10 +69,10 @@ namespace osu.Game.Tests.Visual.Navigation
AddUntilStep("wait for gameplay", () => player?.IsBreakTime.Value == false);
AddStep("press 'z'", () => InputManager.Key(Key.Z));
- AddAssert("key counter didn't increase", () => keyCounter.CountPresses == 0);
+ AddAssert("key counter didn't increase", () => keyCounter.CountPresses.Value == 0);
AddStep("press 's'", () => InputManager.Key(Key.S));
- AddAssert("key counter did increase", () => keyCounter.CountPresses == 1);
+ AddAssert("key counter did increase", () => keyCounter.CountPresses.Value == 1);
}
private KeyBindingsSubsection osuBindingSubsection => keyBindingPanel
diff --git a/osu.Game/Screens/Play/DefaultKeyCounter.cs b/osu.Game/Screens/Play/DefaultKeyCounter.cs
index 93dc4abcb5..52d54b9d4a 100644
--- a/osu.Game/Screens/Play/DefaultKeyCounter.cs
+++ b/osu.Game/Screens/Play/DefaultKeyCounter.cs
@@ -67,7 +67,7 @@ namespace osu.Game.Screens.Play
},
countSpriteText = new OsuSpriteText
{
- Text = CountPresses.ToString(@"#,0"),
+ Text = CountPresses.Value.ToString(@"#,0"),
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativePositionAxes = Axes.Both,
@@ -83,7 +83,7 @@ namespace osu.Game.Screens.Play
Width = buttonSprite.DrawWidth;
IsLit.BindValueChanged(e => updateGlowSprite(e.NewValue), true);
- PressesCount.BindValueChanged(e => countSpriteText.Text = e.NewValue.ToString(@"#,0"), true);
+ CountPresses.BindValueChanged(e => countSpriteText.Text = e.NewValue.ToString(@"#,0"), true);
}
private void updateGlowSprite(bool show)
diff --git a/osu.Game/Screens/Play/KeyCounter.cs b/osu.Game/Screens/Play/KeyCounter.cs
index 3748792383..23afa97597 100644
--- a/osu.Game/Screens/Play/KeyCounter.cs
+++ b/osu.Game/Screens/Play/KeyCounter.cs
@@ -12,28 +12,18 @@ namespace osu.Game.Screens.Play
{
public readonly InputTrigger Trigger;
- protected Bindable IsCountingBindable = new BindableBool(true);
-
private readonly Container content;
protected override Container Content => content;
- protected Bindable PressesCount = new BindableInt
+ private readonly Bindable countPresses = new BindableInt
{
MinValue = 0
};
- public bool IsCounting
- {
- get => IsCountingBindable.Value;
- set => IsCountingBindable.Value = value;
- }
+ public bool IsCounting { get; set; } = true;
- public int CountPresses
- {
- get => PressesCount.Value;
- private set => PressesCount.Value = value;
- }
+ public IBindable CountPresses => countPresses;
protected KeyCounter(InputTrigger trigger)
{
@@ -59,7 +49,7 @@ namespace osu.Game.Screens.Play
if (!IsCounting)
return;
- CountPresses++;
+ countPresses.Value++;
}
public void Decrement()
@@ -67,7 +57,7 @@ namespace osu.Game.Screens.Play
if (!IsCounting)
return;
- CountPresses--;
+ countPresses.Value--;
}
protected virtual void LightUp(bool increment = true)
From 6cb00cd42f22b7324df66a2863a0fe333875d2f8 Mon Sep 17 00:00:00 2001
From: Cootz
Date: Fri, 17 Feb 2023 01:44:45 +0300
Subject: [PATCH 0114/1400] Add more test cases
---
osu.Game.Tests/Database/LegacyExporterTest.cs | 54 ++++++++++++++++---
1 file changed, 48 insertions(+), 6 deletions(-)
diff --git a/osu.Game.Tests/Database/LegacyExporterTest.cs b/osu.Game.Tests/Database/LegacyExporterTest.cs
index c464eb5c28..c67ec75e92 100644
--- a/osu.Game.Tests/Database/LegacyExporterTest.cs
+++ b/osu.Game.Tests/Database/LegacyExporterTest.cs
@@ -22,7 +22,7 @@ namespace osu.Game.Tests.Database
}
[Test]
- public void ExportFileWithNormalName()
+ public void ExportFileWithNormalNameTest()
{
var exportStorage = storage?.GetStorageForDirectory(@"exports");
@@ -30,23 +30,65 @@ namespace osu.Game.Tests.Database
var item = new TestPathInfo(filename);
Assert.That(item.FileName.Length < TestLegacyExporter.GetMaxPath(), Is.True);
- Assert.DoesNotThrow(() => legacyExporter?.Export(item));
- Assert.That(exportStorage?.Exists($"{filename}{legacyExporter?.GetExtension()}"), Is.True);
+ exportItemWithLongNameAndAssert(item, exportStorage, filename);
}
[Test]
- public void ExportFileWithSuperLongName()
+ public void ExportFileWithNormalNameMultipleTimesTest()
+ {
+ var exportStorage = storage?.GetStorageForDirectory(@"exports");
+
+ const string filename = "normal file name";
+ var item = new TestPathInfo(filename);
+
+ Assert.That(item.FileName.Length < TestLegacyExporter.GetMaxPath(), Is.True);
+
+ //Export multiple times
+ string expectedFileName;
+ for (int i = 0; i < 10; i++)
+ {
+ expectedFileName = i == 0 ? filename : $"{filename} ({i})";
+ exportItemWithLongNameAndAssert(item, exportStorage, expectedFileName);
+ }
+ }
+
+ [Test]
+ public void ExportFileWithSuperLongNameTest()
{
var exportStorage = storage?.GetStorageForDirectory(@"exports");
const string fullname = "some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name";
- int capacity = TestLegacyExporter.GetMaxPath() - (legacyExporter?.GetExtension().Length ?? 0);
- string expectedName = fullname.Remove(capacity);
+ int expectedLength = TestLegacyExporter.GetMaxPath() - (legacyExporter?.GetExtension().Length ?? 0);
+ string expectedName = fullname.Remove(expectedLength);
var item = new TestPathInfo(fullname);
Assert.That(item.FileName.Length > TestLegacyExporter.GetMaxPath(), Is.True);
+ exportItemWithLongNameAndAssert(item, exportStorage, expectedName);
+ }
+
+ [Test]
+ public void ExportFileWithSuperLongNameMultipleTimesTest()
+ {
+ var exportStorage = storage?.GetStorageForDirectory(@"exports");
+
+ const string fullname = "some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name";
+
+ int expectedLength = TestLegacyExporter.GetMaxPath() - (legacyExporter?.GetExtension().Length ?? 0);
+ string expectedName = fullname.Remove(expectedLength);
+
+ var item = new TestPathInfo(fullname);
+
+ Assert.That(item.FileName.Length > TestLegacyExporter.GetMaxPath(), Is.True);
+
+ //Export multiple times
+ for (int i = 0; i < 10; i++)
+ exportItemWithLongNameAndAssert(item, exportStorage, expectedName);
+ }
+
+ private void exportItemWithLongNameAndAssert(IHasNamedFiles item, Storage? exportStorage, string expectedName)
+ {
Assert.DoesNotThrow(() => legacyExporter?.Export(item));
Assert.That(exportStorage?.Exists($"{expectedName}{legacyExporter?.GetExtension()}"), Is.True);
}
From 1d8b348e4c72d29d44ce0f56d9d6e71f98000187 Mon Sep 17 00:00:00 2001
From: Cootz
Date: Fri, 17 Feb 2023 01:46:15 +0300
Subject: [PATCH 0115/1400] Improve naming
---
osu.Game.Tests/Database/LegacyExporterTest.cs | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/osu.Game.Tests/Database/LegacyExporterTest.cs b/osu.Game.Tests/Database/LegacyExporterTest.cs
index c67ec75e92..97b32b0c51 100644
--- a/osu.Game.Tests/Database/LegacyExporterTest.cs
+++ b/osu.Game.Tests/Database/LegacyExporterTest.cs
@@ -30,7 +30,7 @@ namespace osu.Game.Tests.Database
var item = new TestPathInfo(filename);
Assert.That(item.FileName.Length < TestLegacyExporter.GetMaxPath(), Is.True);
- exportItemWithLongNameAndAssert(item, exportStorage, filename);
+ exportItemAndAssert(item, exportStorage, filename);
}
[Test]
@@ -48,7 +48,7 @@ namespace osu.Game.Tests.Database
for (int i = 0; i < 10; i++)
{
expectedFileName = i == 0 ? filename : $"{filename} ({i})";
- exportItemWithLongNameAndAssert(item, exportStorage, expectedFileName);
+ exportItemAndAssert(item, exportStorage, expectedFileName);
}
}
@@ -65,7 +65,7 @@ namespace osu.Game.Tests.Database
var item = new TestPathInfo(fullname);
Assert.That(item.FileName.Length > TestLegacyExporter.GetMaxPath(), Is.True);
- exportItemWithLongNameAndAssert(item, exportStorage, expectedName);
+ exportItemAndAssert(item, exportStorage, expectedName);
}
[Test]
@@ -84,10 +84,10 @@ namespace osu.Game.Tests.Database
//Export multiple times
for (int i = 0; i < 10; i++)
- exportItemWithLongNameAndAssert(item, exportStorage, expectedName);
+ exportItemAndAssert(item, exportStorage, expectedName);
}
- private void exportItemWithLongNameAndAssert(IHasNamedFiles item, Storage? exportStorage, string expectedName)
+ private void exportItemAndAssert(IHasNamedFiles item, Storage? exportStorage, string expectedName)
{
Assert.DoesNotThrow(() => legacyExporter?.Export(item));
Assert.That(exportStorage?.Exists($"{expectedName}{legacyExporter?.GetExtension()}"), Is.True);
From f4038a49a17f8670f3b3ed8613e12d197d4e96b6 Mon Sep 17 00:00:00 2001
From: Cootz
Date: Fri, 17 Feb 2023 01:50:24 +0300
Subject: [PATCH 0116/1400] Fix inspectCode issues
---
osu.Game.Tests/Database/LegacyExporterTest.cs | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/osu.Game.Tests/Database/LegacyExporterTest.cs b/osu.Game.Tests/Database/LegacyExporterTest.cs
index 97b32b0c51..d67cb8abf1 100644
--- a/osu.Game.Tests/Database/LegacyExporterTest.cs
+++ b/osu.Game.Tests/Database/LegacyExporterTest.cs
@@ -44,10 +44,9 @@ namespace osu.Game.Tests.Database
Assert.That(item.FileName.Length < TestLegacyExporter.GetMaxPath(), Is.True);
//Export multiple times
- string expectedFileName;
for (int i = 0; i < 10; i++)
{
- expectedFileName = i == 0 ? filename : $"{filename} ({i})";
+ string expectedFileName = i == 0 ? filename : $"{filename} ({i})";
exportItemAndAssert(item, exportStorage, expectedFileName);
}
}
From c61fac578ca53fa4dba22ac7ec85aa0cc335c762 Mon Sep 17 00:00:00 2001
From: tsrk
Date: Thu, 16 Feb 2023 23:15:03 +0000
Subject: [PATCH 0117/1400] style(KeyCounter): rename methods and arguments
As for the second suggestion in
https://github.com/ppy/osu/pull/22654#discussion_r1109047998,
I went with the first one as only one Trigger actually uses this
argument for rewinding.
---
.../TestSceneOsuTouchInput.cs | 4 ++--
osu.Game/Screens/Play/KeyCounter.cs | 20 +++++++++----------
.../Screens/Play/KeyCounterActionTrigger.cs | 4 ++--
.../Screens/Play/KeyCounterKeyboardTrigger.cs | 4 ++--
.../Screens/Play/KeyCounterMouseTrigger.cs | 4 ++--
5 files changed, 18 insertions(+), 18 deletions(-)
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
index c73025ebb9..8a933c6b24 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
@@ -593,7 +593,7 @@ namespace osu.Game.Rulesets.Osu.Tests
{
if (e.Action == Action)
{
- LightUp();
+ Activate();
}
return false;
@@ -602,7 +602,7 @@ namespace osu.Game.Rulesets.Osu.Tests
public void OnReleased(KeyBindingReleaseEvent e)
{
if (e.Action == Action)
- Unlight();
+ Deactivate();
}
}
diff --git a/osu.Game/Screens/Play/KeyCounter.cs b/osu.Game/Screens/Play/KeyCounter.cs
index 23afa97597..a276c9d59e 100644
--- a/osu.Game/Screens/Play/KeyCounter.cs
+++ b/osu.Game/Screens/Play/KeyCounter.cs
@@ -36,8 +36,8 @@ namespace osu.Game.Screens.Play
Trigger = trigger,
};
- Trigger.OnLightUp += LightUp;
- Trigger.OnUnlight += Unlight;
+ Trigger.OnActivate += Activate;
+ Trigger.OnDeactivate += Deactivate;
Name = trigger.Name;
}
@@ -60,14 +60,14 @@ namespace osu.Game.Screens.Play
countPresses.Value--;
}
- protected virtual void LightUp(bool increment = true)
+ protected virtual void Activate(bool increment = true)
{
IsLit.Value = true;
if (increment)
Increment();
}
- protected virtual void Unlight(bool preserve = true)
+ protected virtual void Deactivate(bool preserve = true)
{
IsLit.Value = false;
if (!preserve)
@@ -77,23 +77,23 @@ namespace osu.Game.Screens.Play
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
- Trigger.OnLightUp -= LightUp;
- Trigger.OnUnlight -= Unlight;
+ Trigger.OnActivate -= Activate;
+ Trigger.OnDeactivate -= Deactivate;
}
public abstract partial class InputTrigger : Component
{
- public event Action? OnLightUp;
- public event Action? OnUnlight;
+ public event Action? OnActivate;
+ public event Action? OnDeactivate;
protected InputTrigger(string name)
{
Name = name;
}
- protected void LightUp(bool increment = true) => OnLightUp?.Invoke(increment);
+ protected void Activate(bool forwardPlayback = true) => OnActivate?.Invoke(forwardPlayback);
- protected void Unlight(bool preserve = true) => OnUnlight?.Invoke(preserve);
+ protected void Deactivate(bool forwardPlayback = true) => OnDeactivate?.Invoke(forwardPlayback);
}
}
}
diff --git a/osu.Game/Screens/Play/KeyCounterActionTrigger.cs b/osu.Game/Screens/Play/KeyCounterActionTrigger.cs
index c6acb3f95f..8bb9bdc886 100644
--- a/osu.Game/Screens/Play/KeyCounterActionTrigger.cs
+++ b/osu.Game/Screens/Play/KeyCounterActionTrigger.cs
@@ -23,7 +23,7 @@ namespace osu.Game.Screens.Play
if (!EqualityComparer.Default.Equals(action, Action))
return false;
- LightUp(forwards);
+ Activate(forwards);
return false;
}
@@ -32,7 +32,7 @@ namespace osu.Game.Screens.Play
if (!EqualityComparer.Default.Equals(action, Action))
return;
- Unlight(forwards);
+ Deactivate(forwards);
}
}
}
diff --git a/osu.Game/Screens/Play/KeyCounterKeyboardTrigger.cs b/osu.Game/Screens/Play/KeyCounterKeyboardTrigger.cs
index 18eb6b7612..56c5ab0083 100644
--- a/osu.Game/Screens/Play/KeyCounterKeyboardTrigger.cs
+++ b/osu.Game/Screens/Play/KeyCounterKeyboardTrigger.cs
@@ -22,7 +22,7 @@ namespace osu.Game.Screens.Play
{
if (e.Key == Key)
{
- LightUp();
+ Activate();
}
return base.OnKeyDown(e);
@@ -31,7 +31,7 @@ namespace osu.Game.Screens.Play
protected override void OnKeyUp(KeyUpEvent e)
{
if (e.Key == Key)
- Unlight();
+ Deactivate();
base.OnKeyUp(e);
}
diff --git a/osu.Game/Screens/Play/KeyCounterMouseTrigger.cs b/osu.Game/Screens/Play/KeyCounterMouseTrigger.cs
index 1446494b5b..66890073a8 100644
--- a/osu.Game/Screens/Play/KeyCounterMouseTrigger.cs
+++ b/osu.Game/Screens/Play/KeyCounterMouseTrigger.cs
@@ -39,7 +39,7 @@ namespace osu.Game.Screens.Play
protected override bool OnMouseDown(MouseDownEvent e)
{
if (e.Button == Button)
- LightUp();
+ Activate();
return base.OnMouseDown(e);
}
@@ -47,7 +47,7 @@ namespace osu.Game.Screens.Play
protected override void OnMouseUp(MouseUpEvent e)
{
if (e.Button == Button)
- Unlight();
+ Deactivate();
base.OnMouseUp(e);
}
From e3ca751027af079ac74e73ad7e88d59c8dc82d24 Mon Sep 17 00:00:00 2001
From: tsrk
Date: Thu, 16 Feb 2023 23:17:47 +0000
Subject: [PATCH 0118/1400] refactor: make `FillFlowContainer` read-only
---
osu.Game/Screens/Play/KeyCounterDisplay.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/osu.Game/Screens/Play/KeyCounterDisplay.cs b/osu.Game/Screens/Play/KeyCounterDisplay.cs
index ed47af11a3..0f2f8e43c9 100644
--- a/osu.Game/Screens/Play/KeyCounterDisplay.cs
+++ b/osu.Game/Screens/Play/KeyCounterDisplay.cs
@@ -17,7 +17,7 @@ namespace osu.Game.Screens.Play
{
protected readonly Bindable ConfigVisibility = new Bindable();
- protected FillFlowContainer KeyFlow = new FillFlowContainer();
+ protected readonly FillFlowContainer KeyFlow = new FillFlowContainer();
protected override Container Content => KeyFlow;
From 6193aeed120f2bc85768a47efafa21b95695119e Mon Sep 17 00:00:00 2001
From: tsrk
Date: Fri, 17 Feb 2023 00:13:45 +0000
Subject: [PATCH 0119/1400] fix(TestSceneOsuTouchInput): missing Value call
---
osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
index 8a933c6b24..4cb017cc56 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
@@ -562,8 +562,8 @@ namespace osu.Game.Rulesets.Osu.Tests
private void assertKeyCounter(int left, int right)
{
- AddAssert($"The left key was pressed {left} times", () => leftKeyCounter.CountPresses, () => Is.EqualTo(left));
- AddAssert($"The right key was pressed {right} times", () => rightKeyCounter.CountPresses, () => Is.EqualTo(right));
+ AddAssert($"The left key was pressed {left} times", () => leftKeyCounter.CountPresses.Value, () => Is.EqualTo(left));
+ AddAssert($"The right key was pressed {right} times", () => rightKeyCounter.CountPresses.Value, () => Is.EqualTo(right));
}
private void releaseAllTouches()
From d0e8d65766df488c98bf99ccdef7c05df3f694d8 Mon Sep 17 00:00:00 2001
From: tsrk
Date: Fri, 17 Feb 2023 00:40:01 +0000
Subject: [PATCH 0120/1400] style(KeyCounter): rename `IsLit` to `IsActive`
---
osu.Game/Screens/Play/DefaultKeyCounter.cs | 2 +-
osu.Game/Screens/Play/KeyCounter.cs | 6 +++---
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/osu.Game/Screens/Play/DefaultKeyCounter.cs b/osu.Game/Screens/Play/DefaultKeyCounter.cs
index 52d54b9d4a..3673281577 100644
--- a/osu.Game/Screens/Play/DefaultKeyCounter.cs
+++ b/osu.Game/Screens/Play/DefaultKeyCounter.cs
@@ -82,7 +82,7 @@ namespace osu.Game.Screens.Play
Height = buttonSprite.DrawHeight;
Width = buttonSprite.DrawWidth;
- IsLit.BindValueChanged(e => updateGlowSprite(e.NewValue), true);
+ IsActive.BindValueChanged(e => updateGlowSprite(e.NewValue), true);
CountPresses.BindValueChanged(e => countSpriteText.Text = e.NewValue.ToString(@"#,0"), true);
}
diff --git a/osu.Game/Screens/Play/KeyCounter.cs b/osu.Game/Screens/Play/KeyCounter.cs
index a276c9d59e..212843cbe9 100644
--- a/osu.Game/Screens/Play/KeyCounter.cs
+++ b/osu.Game/Screens/Play/KeyCounter.cs
@@ -42,7 +42,7 @@ namespace osu.Game.Screens.Play
Name = trigger.Name;
}
- protected Bindable IsLit = new BindableBool();
+ protected Bindable IsActive = new BindableBool();
public void Increment()
{
@@ -62,14 +62,14 @@ namespace osu.Game.Screens.Play
protected virtual void Activate(bool increment = true)
{
- IsLit.Value = true;
+ IsActive.Value = true;
if (increment)
Increment();
}
protected virtual void Deactivate(bool preserve = true)
{
- IsLit.Value = false;
+ IsActive.Value = false;
if (!preserve)
Decrement();
}
From 415220a44769fa8a7027ec8d56eb38b63fac6e04 Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Fri, 17 Feb 2023 13:30:00 +0900
Subject: [PATCH 0121/1400] Tidy up new test method code quality
---
osu.Game.Tests/Database/LegacyExporterTest.cs | 55 +++++++++++--------
1 file changed, 31 insertions(+), 24 deletions(-)
diff --git a/osu.Game.Tests/Database/LegacyExporterTest.cs b/osu.Game.Tests/Database/LegacyExporterTest.cs
index d67cb8abf1..803cd40132 100644
--- a/osu.Game.Tests/Database/LegacyExporterTest.cs
+++ b/osu.Game.Tests/Database/LegacyExporterTest.cs
@@ -3,6 +3,7 @@
using System.Collections.Generic;
using NUnit.Framework;
+using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Platform;
using osu.Framework.Testing;
using osu.Game.Database;
@@ -11,11 +12,11 @@ namespace osu.Game.Tests.Database
{
public class LegacyExporterTest
{
- private TestLegacyExporter? legacyExporter;
- private TemporaryNativeStorage? storage;
+ private TestLegacyExporter legacyExporter = null!;
+ private TemporaryNativeStorage storage = null!;
[SetUp]
- public void SetupLegacyExporter()
+ public void SetUp()
{
storage = new TemporaryNativeStorage("export-storage");
legacyExporter = new TestLegacyExporter(storage);
@@ -24,24 +25,24 @@ namespace osu.Game.Tests.Database
[Test]
public void ExportFileWithNormalNameTest()
{
- var exportStorage = storage?.GetStorageForDirectory(@"exports");
+ var exportStorage = storage.GetStorageForDirectory(@"exports");
const string filename = "normal file name";
var item = new TestPathInfo(filename);
- Assert.That(item.FileName.Length < TestLegacyExporter.GetMaxPath(), Is.True);
+ Assert.That(item.Filename.Length < TestLegacyExporter.GetMaxPath(), Is.True);
exportItemAndAssert(item, exportStorage, filename);
}
[Test]
public void ExportFileWithNormalNameMultipleTimesTest()
{
- var exportStorage = storage?.GetStorageForDirectory(@"exports");
+ var exportStorage = storage.GetStorageForDirectory(@"exports");
const string filename = "normal file name";
var item = new TestPathInfo(filename);
- Assert.That(item.FileName.Length < TestLegacyExporter.GetMaxPath(), Is.True);
+ Assert.That(item.Filename.Length < TestLegacyExporter.GetMaxPath(), Is.True);
//Export multiple times
for (int i = 0; i < 10; i++)
@@ -54,59 +55,65 @@ namespace osu.Game.Tests.Database
[Test]
public void ExportFileWithSuperLongNameTest()
{
- var exportStorage = storage?.GetStorageForDirectory(@"exports");
+ var exportStorage = storage.GetStorageForDirectory(@"exports");
- const string fullname = "some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name";
+ const string fullname =
+ "some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name";
- int expectedLength = TestLegacyExporter.GetMaxPath() - (legacyExporter?.GetExtension().Length ?? 0);
+ int expectedLength = TestLegacyExporter.GetMaxPath() - (legacyExporter.GetExtension().Length);
string expectedName = fullname.Remove(expectedLength);
var item = new TestPathInfo(fullname);
- Assert.That(item.FileName.Length > TestLegacyExporter.GetMaxPath(), Is.True);
+ Assert.That(item.Filename.Length > TestLegacyExporter.GetMaxPath(), Is.True);
exportItemAndAssert(item, exportStorage, expectedName);
}
[Test]
public void ExportFileWithSuperLongNameMultipleTimesTest()
{
- var exportStorage = storage?.GetStorageForDirectory(@"exports");
+ var exportStorage = storage.GetStorageForDirectory(@"exports");
- const string fullname = "some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name";
+ const string fullname =
+ "some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name";
- int expectedLength = TestLegacyExporter.GetMaxPath() - (legacyExporter?.GetExtension().Length ?? 0);
+ int expectedLength = TestLegacyExporter.GetMaxPath() - (legacyExporter.GetExtension().Length);
string expectedName = fullname.Remove(expectedLength);
var item = new TestPathInfo(fullname);
- Assert.That(item.FileName.Length > TestLegacyExporter.GetMaxPath(), Is.True);
+ Assert.That(item.Filename.Length > TestLegacyExporter.GetMaxPath(), Is.True);
//Export multiple times
for (int i = 0; i < 10; i++)
exportItemAndAssert(item, exportStorage, expectedName);
}
- private void exportItemAndAssert(IHasNamedFiles item, Storage? exportStorage, string expectedName)
+ private void exportItemAndAssert(IHasNamedFiles item, Storage exportStorage, string expectedName)
{
- Assert.DoesNotThrow(() => legacyExporter?.Export(item));
- Assert.That(exportStorage?.Exists($"{expectedName}{legacyExporter?.GetExtension()}"), Is.True);
+ Assert.DoesNotThrow(() => legacyExporter.Export(item));
+ Assert.That(exportStorage.Exists($"{expectedName}{legacyExporter.GetExtension()}"), Is.True);
}
[TearDown]
- public void CleanupAfterTest()
+ public void TearDown()
{
- storage?.Dispose();
+ if (storage.IsNotNull())
+ storage.Dispose();
}
private class TestPathInfo : IHasNamedFiles
{
- public string FileName { get; set; }
+ public string Filename { get; }
- public TestPathInfo(string fileName) => FileName = fileName;
+ public IEnumerable Files { get; } = new List();
- public IEnumerable Files { get; set; } = new List();
+ public TestPathInfo(string filename)
+ {
+ Filename = filename;
+ }
- public override string ToString() => FileName;
+ public override string ToString() => Filename;
}
private class TestLegacyExporter : LegacyExporter
From 96b1498932c4b93126a477cf1acc1b93d11c1b57 Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Fri, 17 Feb 2023 13:33:22 +0900
Subject: [PATCH 0122/1400] Rename max length variable to make sense (it's a
filename limit, not path)
---
osu.Game.Tests/Database/LegacyExporterTest.cs | 14 +++++++-------
osu.Game/Database/LegacyExporter.cs | 12 +++++++-----
2 files changed, 14 insertions(+), 12 deletions(-)
diff --git a/osu.Game.Tests/Database/LegacyExporterTest.cs b/osu.Game.Tests/Database/LegacyExporterTest.cs
index 803cd40132..6f144ee833 100644
--- a/osu.Game.Tests/Database/LegacyExporterTest.cs
+++ b/osu.Game.Tests/Database/LegacyExporterTest.cs
@@ -30,7 +30,7 @@ namespace osu.Game.Tests.Database
const string filename = "normal file name";
var item = new TestPathInfo(filename);
- Assert.That(item.Filename.Length < TestLegacyExporter.GetMaxPath(), Is.True);
+ Assert.That(item.Filename.Length, Is.LessThan(TestLegacyExporter.GetMaxPathLength()));
exportItemAndAssert(item, exportStorage, filename);
}
@@ -42,7 +42,7 @@ namespace osu.Game.Tests.Database
const string filename = "normal file name";
var item = new TestPathInfo(filename);
- Assert.That(item.Filename.Length < TestLegacyExporter.GetMaxPath(), Is.True);
+ Assert.That(item.Filename.Length < TestLegacyExporter.GetMaxPathLength(), Is.True);
//Export multiple times
for (int i = 0; i < 10; i++)
@@ -60,12 +60,12 @@ namespace osu.Game.Tests.Database
const string fullname =
"some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name";
- int expectedLength = TestLegacyExporter.GetMaxPath() - (legacyExporter.GetExtension().Length);
+ int expectedLength = TestLegacyExporter.GetMaxPathLength() - (legacyExporter.GetExtension().Length);
string expectedName = fullname.Remove(expectedLength);
var item = new TestPathInfo(fullname);
- Assert.That(item.Filename.Length > TestLegacyExporter.GetMaxPath(), Is.True);
+ Assert.That(item.Filename.Length > TestLegacyExporter.GetMaxPathLength(), Is.True);
exportItemAndAssert(item, exportStorage, expectedName);
}
@@ -77,12 +77,12 @@ namespace osu.Game.Tests.Database
const string fullname =
"some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name";
- int expectedLength = TestLegacyExporter.GetMaxPath() - (legacyExporter.GetExtension().Length);
+ int expectedLength = TestLegacyExporter.GetMaxPathLength() - (legacyExporter.GetExtension().Length);
string expectedName = fullname.Remove(expectedLength);
var item = new TestPathInfo(fullname);
- Assert.That(item.Filename.Length > TestLegacyExporter.GetMaxPath(), Is.True);
+ Assert.That(item.Filename.Length > TestLegacyExporter.GetMaxPathLength(), Is.True);
//Export multiple times
for (int i = 0; i < 10; i++)
@@ -123,7 +123,7 @@ namespace osu.Game.Tests.Database
{
}
- public static int GetMaxPath() => MAX_PATH;
+ public static int GetMaxPathLength() => MAX_FILENAME_LENGTH;
public string GetExtension() => FileExtension;
diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs
index 9041f58368..1b74454027 100644
--- a/osu.Game/Database/LegacyExporter.cs
+++ b/osu.Game/Database/LegacyExporter.cs
@@ -21,12 +21,14 @@ namespace osu.Game.Database
where TModel : class, IHasNamedFiles
{
///
- /// Max length of filename (including extension)
+ /// Max length of filename (including extension).
///
///
- /// This constant is smaller 256 because adds additional "_" to the end of the path
+ /// TODO: WHY? DOCUMENTATION PER PLATFORM LINKS HERE.
+ ///
+ /// This actual usable length is smaller 256 because adds additional "_" to the end of the path
///
- protected const int MAX_PATH = 255 - (32 + 4 + 2); //max path - (Guid + Guid "D" format chars + Storage.CreateFileSafely chars)
+ protected const int MAX_FILENAME_LENGTH = 255 - (32 + 4 + 2); //max path - (Guid + Guid "D" format chars + Storage.CreateFileSafely chars)
///
/// The file extension for exports (including the leading '.').
@@ -60,11 +62,11 @@ namespace osu.Game.Database
string filename = NamingUtils.GetNextBestFilename(existingExports, $"{itemFilename}{FileExtension}");
- if (filename.Length > MAX_PATH)
+ if (filename.Length > MAX_FILENAME_LENGTH)
{
string filenameWithoutExtension = Path.GetFileNameWithoutExtension(filename);
- filenameWithoutExtension = filenameWithoutExtension.Remove(MAX_PATH - FileExtension.Length); //Truncating the name to fit the path limit
+ filenameWithoutExtension = filenameWithoutExtension.Remove(MAX_FILENAME_LENGTH - FileExtension.Length); //Truncating the name to fit the path limit
filename = $"{filenameWithoutExtension}{FileExtension}";
}
From 8c772a723f0f8ae52cf3141fab286c64c2eba198 Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Fri, 17 Feb 2023 13:34:19 +0900
Subject: [PATCH 0123/1400] Expose constant `public`ly rather than reexposing
business
---
osu.Game/Database/LegacyExporter.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs
index 1b74454027..7434a46602 100644
--- a/osu.Game/Database/LegacyExporter.cs
+++ b/osu.Game/Database/LegacyExporter.cs
@@ -28,7 +28,7 @@ namespace osu.Game.Database
///
/// This actual usable length is smaller 256 because adds additional "_" to the end of the path
///
- protected const int MAX_FILENAME_LENGTH = 255 - (32 + 4 + 2); //max path - (Guid + Guid "D" format chars + Storage.CreateFileSafely chars)
+ public const int MAX_FILENAME_LENGTH = 255 - (32 + 4 + 2); //max path - (Guid + Guid "D" format chars + Storage.CreateFileSafely chars)
///
/// The file extension for exports (including the leading '.').
From 99236f0ae80399d9fade78c7331dff63d59301e4 Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Fri, 17 Feb 2023 13:39:24 +0900
Subject: [PATCH 0124/1400] Move long filename to fixture level
---
osu.Game.Tests/Database/LegacyExporterTest.cs | 31 ++++++++-----------
1 file changed, 13 insertions(+), 18 deletions(-)
diff --git a/osu.Game.Tests/Database/LegacyExporterTest.cs b/osu.Game.Tests/Database/LegacyExporterTest.cs
index 6f144ee833..114872bcf8 100644
--- a/osu.Game.Tests/Database/LegacyExporterTest.cs
+++ b/osu.Game.Tests/Database/LegacyExporterTest.cs
@@ -15,6 +15,9 @@ namespace osu.Game.Tests.Database
private TestLegacyExporter legacyExporter = null!;
private TemporaryNativeStorage storage = null!;
+ private const string long_filename =
+ "some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name";
+
[SetUp]
public void SetUp()
{
@@ -30,7 +33,7 @@ namespace osu.Game.Tests.Database
const string filename = "normal file name";
var item = new TestPathInfo(filename);
- Assert.That(item.Filename.Length, Is.LessThan(TestLegacyExporter.GetMaxPathLength()));
+ Assert.That(item.Filename.Length, Is.LessThan(TestLegacyExporter.MAX_FILENAME_LENGTH));
exportItemAndAssert(item, exportStorage, filename);
}
@@ -42,7 +45,7 @@ namespace osu.Game.Tests.Database
const string filename = "normal file name";
var item = new TestPathInfo(filename);
- Assert.That(item.Filename.Length < TestLegacyExporter.GetMaxPathLength(), Is.True);
+ Assert.That(item.Filename.Length < TestLegacyExporter.MAX_FILENAME_LENGTH, Is.True);
//Export multiple times
for (int i = 0; i < 10; i++)
@@ -57,15 +60,12 @@ namespace osu.Game.Tests.Database
{
var exportStorage = storage.GetStorageForDirectory(@"exports");
- const string fullname =
- "some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name";
+ int expectedLength = TestLegacyExporter.MAX_FILENAME_LENGTH - (legacyExporter.GetExtension().Length);
+ string expectedName = long_filename.Remove(expectedLength);
- int expectedLength = TestLegacyExporter.GetMaxPathLength() - (legacyExporter.GetExtension().Length);
- string expectedName = fullname.Remove(expectedLength);
+ var item = new TestPathInfo(long_filename);
- var item = new TestPathInfo(fullname);
-
- Assert.That(item.Filename.Length > TestLegacyExporter.GetMaxPathLength(), Is.True);
+ Assert.That(item.Filename.Length > TestLegacyExporter.MAX_FILENAME_LENGTH, Is.True);
exportItemAndAssert(item, exportStorage, expectedName);
}
@@ -74,15 +74,12 @@ namespace osu.Game.Tests.Database
{
var exportStorage = storage.GetStorageForDirectory(@"exports");
- const string fullname =
- "some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name";
+ int expectedLength = TestLegacyExporter.MAX_FILENAME_LENGTH - (legacyExporter.GetExtension().Length);
+ string expectedName = long_filename.Remove(expectedLength);
- int expectedLength = TestLegacyExporter.GetMaxPathLength() - (legacyExporter.GetExtension().Length);
- string expectedName = fullname.Remove(expectedLength);
+ var item = new TestPathInfo(long_filename);
- var item = new TestPathInfo(fullname);
-
- Assert.That(item.Filename.Length > TestLegacyExporter.GetMaxPathLength(), Is.True);
+ Assert.That(item.Filename.Length > TestLegacyExporter.MAX_FILENAME_LENGTH, Is.True);
//Export multiple times
for (int i = 0; i < 10; i++)
@@ -123,8 +120,6 @@ namespace osu.Game.Tests.Database
{
}
- public static int GetMaxPathLength() => MAX_FILENAME_LENGTH;
-
public string GetExtension() => FileExtension;
protected override string FileExtension => ".ots";
From 4560ae6b026bd1ce575713ccab7d9052f73af40b Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Fri, 17 Feb 2023 13:39:31 +0900
Subject: [PATCH 0125/1400] Mark test as fixture
---
osu.Game.Tests/Database/LegacyExporterTest.cs | 1 +
1 file changed, 1 insertion(+)
diff --git a/osu.Game.Tests/Database/LegacyExporterTest.cs b/osu.Game.Tests/Database/LegacyExporterTest.cs
index 114872bcf8..ec20028a2c 100644
--- a/osu.Game.Tests/Database/LegacyExporterTest.cs
+++ b/osu.Game.Tests/Database/LegacyExporterTest.cs
@@ -10,6 +10,7 @@ using osu.Game.Database;
namespace osu.Game.Tests.Database
{
+ [TestFixture]
public class LegacyExporterTest
{
private TestLegacyExporter legacyExporter = null!;
From 86d110e893cd2572377c575fc67e5260a1199e27 Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Fri, 17 Feb 2023 13:43:42 +0900
Subject: [PATCH 0126/1400] Simplify test storage by removing nested storage
---
osu.Game.Tests/Database/LegacyExporterTest.cs | 20 ++++++-------------
1 file changed, 6 insertions(+), 14 deletions(-)
diff --git a/osu.Game.Tests/Database/LegacyExporterTest.cs b/osu.Game.Tests/Database/LegacyExporterTest.cs
index ec20028a2c..f38ffb7db6 100644
--- a/osu.Game.Tests/Database/LegacyExporterTest.cs
+++ b/osu.Game.Tests/Database/LegacyExporterTest.cs
@@ -29,20 +29,16 @@ namespace osu.Game.Tests.Database
[Test]
public void ExportFileWithNormalNameTest()
{
- var exportStorage = storage.GetStorageForDirectory(@"exports");
-
const string filename = "normal file name";
var item = new TestPathInfo(filename);
Assert.That(item.Filename.Length, Is.LessThan(TestLegacyExporter.MAX_FILENAME_LENGTH));
- exportItemAndAssert(item, exportStorage, filename);
+ exportItemAndAssert(item, filename);
}
[Test]
public void ExportFileWithNormalNameMultipleTimesTest()
{
- var exportStorage = storage.GetStorageForDirectory(@"exports");
-
const string filename = "normal file name";
var item = new TestPathInfo(filename);
@@ -52,29 +48,25 @@ namespace osu.Game.Tests.Database
for (int i = 0; i < 10; i++)
{
string expectedFileName = i == 0 ? filename : $"{filename} ({i})";
- exportItemAndAssert(item, exportStorage, expectedFileName);
+ exportItemAndAssert(item, expectedFileName);
}
}
[Test]
public void ExportFileWithSuperLongNameTest()
{
- var exportStorage = storage.GetStorageForDirectory(@"exports");
-
int expectedLength = TestLegacyExporter.MAX_FILENAME_LENGTH - (legacyExporter.GetExtension().Length);
string expectedName = long_filename.Remove(expectedLength);
var item = new TestPathInfo(long_filename);
Assert.That(item.Filename.Length > TestLegacyExporter.MAX_FILENAME_LENGTH, Is.True);
- exportItemAndAssert(item, exportStorage, expectedName);
+ exportItemAndAssert(item, expectedName);
}
[Test]
public void ExportFileWithSuperLongNameMultipleTimesTest()
{
- var exportStorage = storage.GetStorageForDirectory(@"exports");
-
int expectedLength = TestLegacyExporter.MAX_FILENAME_LENGTH - (legacyExporter.GetExtension().Length);
string expectedName = long_filename.Remove(expectedLength);
@@ -84,13 +76,13 @@ namespace osu.Game.Tests.Database
//Export multiple times
for (int i = 0; i < 10; i++)
- exportItemAndAssert(item, exportStorage, expectedName);
+ exportItemAndAssert(item, expectedName);
}
- private void exportItemAndAssert(IHasNamedFiles item, Storage exportStorage, string expectedName)
+ private void exportItemAndAssert(IHasNamedFiles item, string expectedName)
{
Assert.DoesNotThrow(() => legacyExporter.Export(item));
- Assert.That(exportStorage.Exists($"{expectedName}{legacyExporter.GetExtension()}"), Is.True);
+ Assert.That(storage.Exists($"exports/{expectedName}{legacyExporter.GetExtension()}"), Is.True);
}
[TearDown]
From 8ef3fb26e056b2c271a690be5539983f6d9d09b0 Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Fri, 17 Feb 2023 13:45:27 +0900
Subject: [PATCH 0127/1400] More constants and assert fixes
---
osu.Game.Tests/Database/LegacyExporterTest.cs | 19 ++++++++++---------
1 file changed, 10 insertions(+), 9 deletions(-)
diff --git a/osu.Game.Tests/Database/LegacyExporterTest.cs b/osu.Game.Tests/Database/LegacyExporterTest.cs
index f38ffb7db6..b8dca6dc7b 100644
--- a/osu.Game.Tests/Database/LegacyExporterTest.cs
+++ b/osu.Game.Tests/Database/LegacyExporterTest.cs
@@ -16,6 +16,8 @@ namespace osu.Game.Tests.Database
private TestLegacyExporter legacyExporter = null!;
private TemporaryNativeStorage storage = null!;
+ private const string short_filename = "normal file name";
+
private const string long_filename =
"some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name";
@@ -29,25 +31,24 @@ namespace osu.Game.Tests.Database
[Test]
public void ExportFileWithNormalNameTest()
{
- const string filename = "normal file name";
- var item = new TestPathInfo(filename);
+ var item = new TestPathInfo(short_filename);
Assert.That(item.Filename.Length, Is.LessThan(TestLegacyExporter.MAX_FILENAME_LENGTH));
- exportItemAndAssert(item, filename);
+
+ exportItemAndAssert(item, short_filename);
}
[Test]
public void ExportFileWithNormalNameMultipleTimesTest()
{
- const string filename = "normal file name";
- var item = new TestPathInfo(filename);
+ var item = new TestPathInfo(short_filename);
- Assert.That(item.Filename.Length < TestLegacyExporter.MAX_FILENAME_LENGTH, Is.True);
+ Assert.That(item.Filename.Length, Is.LessThan(TestLegacyExporter.MAX_FILENAME_LENGTH));
//Export multiple times
for (int i = 0; i < 10; i++)
{
- string expectedFileName = i == 0 ? filename : $"{filename} ({i})";
+ string expectedFileName = i == 0 ? short_filename : $"{short_filename} ({i})";
exportItemAndAssert(item, expectedFileName);
}
}
@@ -60,7 +61,7 @@ namespace osu.Game.Tests.Database
var item = new TestPathInfo(long_filename);
- Assert.That(item.Filename.Length > TestLegacyExporter.MAX_FILENAME_LENGTH, Is.True);
+ Assert.That(item.Filename.Length, Is.GreaterThan(TestLegacyExporter.MAX_FILENAME_LENGTH));
exportItemAndAssert(item, expectedName);
}
@@ -72,7 +73,7 @@ namespace osu.Game.Tests.Database
var item = new TestPathInfo(long_filename);
- Assert.That(item.Filename.Length > TestLegacyExporter.MAX_FILENAME_LENGTH, Is.True);
+ Assert.That(item.Filename.Length, Is.GreaterThan(TestLegacyExporter.MAX_FILENAME_LENGTH));
//Export multiple times
for (int i = 0; i < 10; i++)
From 372b6b794cae69dc16a882f0caa3b91dcfef0491 Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Fri, 17 Feb 2023 13:45:43 +0900
Subject: [PATCH 0128/1400] I don't know what .ots is but let's not use random
file extension that make no sense
---
osu.Game.Tests/Database/LegacyExporterTest.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/osu.Game.Tests/Database/LegacyExporterTest.cs b/osu.Game.Tests/Database/LegacyExporterTest.cs
index b8dca6dc7b..c9aea80585 100644
--- a/osu.Game.Tests/Database/LegacyExporterTest.cs
+++ b/osu.Game.Tests/Database/LegacyExporterTest.cs
@@ -116,7 +116,7 @@ namespace osu.Game.Tests.Database
public string GetExtension() => FileExtension;
- protected override string FileExtension => ".ots";
+ protected override string FileExtension => ".test";
}
}
}
From c94e647e21902db2fc98bc3a42ad1b2a75246842 Mon Sep 17 00:00:00 2001
From: tsrk
Date: Fri, 17 Feb 2023 09:09:56 +0000
Subject: [PATCH 0129/1400] style(KeyCounterDisplay): remove type check
---
osu.Game/Screens/Play/KeyCounterDisplay.cs | 5 -----
1 file changed, 5 deletions(-)
diff --git a/osu.Game/Screens/Play/KeyCounterDisplay.cs b/osu.Game/Screens/Play/KeyCounterDisplay.cs
index 0f2f8e43c9..d2b50ff73d 100644
--- a/osu.Game/Screens/Play/KeyCounterDisplay.cs
+++ b/osu.Game/Screens/Play/KeyCounterDisplay.cs
@@ -29,15 +29,10 @@ namespace osu.Game.Screens.Play
public override void Add(KeyCounter key)
{
- if (!CheckType(key))
- throw new ArgumentException($"{key.GetType()} is not a supported {nameof(KeyCounter)}.", nameof(key));
-
base.Add(key);
key.IsCounting = IsCounting;
}
- protected virtual bool CheckType(KeyCounter key) => true;
-
[BackgroundDependencyLoader]
private void load(OsuConfigManager config)
{
From 8830e0658834095dd87e3d9b82b425528021b93a Mon Sep 17 00:00:00 2001
From: tsrk
Date: Fri, 17 Feb 2023 09:17:11 +0000
Subject: [PATCH 0130/1400] fix: compilation
---
osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs | 2 --
1 file changed, 2 deletions(-)
diff --git a/osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs b/osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs
index b69ecfd7ae..fbf1b87395 100644
--- a/osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs
+++ b/osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs
@@ -49,8 +49,6 @@ namespace osu.Game.Screens.Play
defaultKey.KeyUpTextColor = KeyUpTextColor;
}
- protected override bool CheckType(KeyCounter key) => key is DefaultKeyCounter;
-
protected override void UpdateVisibility() =>
// Isolate changing visibility of the key counters from fading this component.
KeyFlow.FadeTo(AlwaysVisible.Value || ConfigVisibility.Value ? 1 : 0, duration);
From ceed3606cd7a3b0666c345ea768219ac5e65b91d Mon Sep 17 00:00:00 2001
From: Cootz <50776304+Cootz@users.noreply.github.com>
Date: Fri, 17 Feb 2023 13:46:06 +0300
Subject: [PATCH 0131/1400] Remove redundant comment
Co-authored-by: Dean Herbert
---
osu.Game/Database/LegacyExporter.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs
index 7434a46602..7fe0428db3 100644
--- a/osu.Game/Database/LegacyExporter.cs
+++ b/osu.Game/Database/LegacyExporter.cs
@@ -66,7 +66,7 @@ namespace osu.Game.Database
{
string filenameWithoutExtension = Path.GetFileNameWithoutExtension(filename);
- filenameWithoutExtension = filenameWithoutExtension.Remove(MAX_FILENAME_LENGTH - FileExtension.Length); //Truncating the name to fit the path limit
+ filenameWithoutExtension = filenameWithoutExtension.Remove(MAX_FILENAME_LENGTH - FileExtension.Length);
filename = $"{filenameWithoutExtension}{FileExtension}";
}
From a3b440493aeae5fc3fbea99e36be28758c8fe2ba Mon Sep 17 00:00:00 2001
From: Cootz
Date: Fri, 17 Feb 2023 15:23:43 +0300
Subject: [PATCH 0132/1400] Update xml doc
---
osu.Game/Database/LegacyExporter.cs | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs
index 7fe0428db3..2d0a1d3528 100644
--- a/osu.Game/Database/LegacyExporter.cs
+++ b/osu.Game/Database/LegacyExporter.cs
@@ -24,9 +24,18 @@ namespace osu.Game.Database
/// Max length of filename (including extension).
///
///
- /// TODO: WHY? DOCUMENTATION PER PLATFORM LINKS HERE.
- ///
- /// This actual usable length is smaller 256 because adds additional "_" to the end of the path
+ ///
+ /// Filename limit for most OSs is 255, this actual usable length is smaller because adds additional "_" to the end of the path.
+ ///
+ ///
+ /// For more information see:
+ ///
+ /// File specification syntax
+ ///
+ ///
+ /// File systems limitations
+ ///
+ ///
///
public const int MAX_FILENAME_LENGTH = 255 - (32 + 4 + 2); //max path - (Guid + Guid "D" format chars + Storage.CreateFileSafely chars)
From fd1beaef87ef2156b5f5e56bf6d1656ece326a16 Mon Sep 17 00:00:00 2001
From: Cootz
Date: Fri, 17 Feb 2023 15:24:27 +0300
Subject: [PATCH 0133/1400] Fix typo
---
osu.Game/Database/LegacyExporter.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs
index 2d0a1d3528..04d5a3aebc 100644
--- a/osu.Game/Database/LegacyExporter.cs
+++ b/osu.Game/Database/LegacyExporter.cs
@@ -25,7 +25,7 @@ namespace osu.Game.Database
///
///
///
- /// Filename limit for most OSs is 255, this actual usable length is smaller because adds additional "_" to the end of the path.
+ /// The filename limit for most OSs is 255. This actual usable length is smaller because adds an additional "_" to the end of the path.
///
///
/// For more information see:
From e3bdb3d852a85748032ea468d1763849aee74249 Mon Sep 17 00:00:00 2001
From: Cootz
Date: Fri, 17 Feb 2023 15:32:36 +0300
Subject: [PATCH 0134/1400] Align links in one line
---
osu.Game/Database/LegacyExporter.cs | 8 +-------
1 file changed, 1 insertion(+), 7 deletions(-)
diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs
index 04d5a3aebc..cf88efb151 100644
--- a/osu.Game/Database/LegacyExporter.cs
+++ b/osu.Game/Database/LegacyExporter.cs
@@ -28,13 +28,7 @@ namespace osu.Game.Database
/// The filename limit for most OSs is 255. This actual usable length is smaller because adds an additional "_" to the end of the path.
///
///
- /// For more information see:
- ///
- /// File specification syntax
- ///
- ///
- /// File systems limitations
- ///
+ /// For more information see file specification syntax, file systems limitations
///
///
public const int MAX_FILENAME_LENGTH = 255 - (32 + 4 + 2); //max path - (Guid + Guid "D" format chars + Storage.CreateFileSafely chars)
From eac0aa79a3bcaf23982b590144ec5471cc4f952c Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Fri, 17 Feb 2023 21:52:10 +0900
Subject: [PATCH 0135/1400] cancellationToken pass, notification adujust
---
osu.Game/Database/LegacyModelExporter.cs | 73 ++++++++++++++----------
osu.Game/Database/LegacyScoreExporter.cs | 3 +-
2 files changed, 45 insertions(+), 31 deletions(-)
diff --git a/osu.Game/Database/LegacyModelExporter.cs b/osu.Game/Database/LegacyModelExporter.cs
index d896e4bce6..1475f29f89 100644
--- a/osu.Game/Database/LegacyModelExporter.cs
+++ b/osu.Game/Database/LegacyModelExporter.cs
@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Threading;
using System.Threading.Tasks;
using osu.Framework.Logging;
using osu.Framework.Platform;
@@ -32,33 +33,52 @@ namespace osu.Game.Database
protected Storage UserFileStorage;
private readonly Storage exportStorage;
- protected RealmAccess RealmAccess;
+ private readonly RealmAccess realmAccess;
private string filename = string.Empty;
public Action? PostNotification { get; set; }
+ ///
+ /// Construct exporter.
+ /// Create a new exporter for each export, otherwise it will cause confusing notifications.
+ ///
+ /// Storage for storing exported files. Basically it is used to provide export stream
+ /// The RealmAccess used to provide the exported file.
protected LegacyModelExporter(Storage storage, RealmAccess realm)
{
exportStorage = storage.GetStorageForDirectory(@"exports");
UserFileStorage = storage.GetStorageForDirectory(@"files");
- RealmAccess = realm;
+ realmAccess = realm;
}
///
/// Export the model to default folder.
///
/// The model should export.
+ ///
+ /// The Cancellation token that can cancel the exporting.
+ /// If specified CancellationToken, then use it. Otherwise use PostNotification's CancellationToken.
+ ///
///
- public async Task ExportAsync(TModel model)
+ public async Task ExportAsync(TModel model, CancellationToken? cancellationToken = null)
{
string itemFilename = model.GetDisplayString().GetValidFilename();
IEnumerable existingExports = exportStorage.GetFiles("", $"{itemFilename}*{FileExtension}");
filename = NamingUtils.GetNextBestFilename(existingExports, $"{itemFilename}{FileExtension}");
bool success;
+ ProgressNotification notification = new ProgressNotification
+ {
+ State = ProgressNotificationState.Active,
+ Text = "Exporting...",
+ CompletionText = "Export completed"
+ };
+ notification.CompletionClickAction += () => exportStorage.PresentFileExternally(filename);
+ PostNotification?.Invoke(notification);
+
using (var stream = exportStorage.CreateFileSafely(filename))
{
- success = await ExportToStreamAsync(model, stream);
+ success = await ExportToStreamAsync(model, stream, notification, cancellationToken ?? notification.CancellationToken);
}
if (!success)
@@ -72,44 +92,34 @@ namespace osu.Game.Database
///
/// The medel which have .
/// The stream to export.
+ /// The notification will displayed to the user
+ /// The Cancellation token that can cancel the exporting.
/// Whether the export was successful
- public async Task ExportToStreamAsync(TModel model, Stream stream)
+ public async Task ExportToStreamAsync(TModel model, Stream stream, ProgressNotification? notification = null, CancellationToken cancellationToken = default)
{
- ProgressNotification notification = new ProgressNotification
- {
- State = ProgressNotificationState.Active,
- Text = "Exporting...",
- CompletionText = "Export completed"
- };
- notification.CompletionClickAction += () => exportStorage.PresentFileExternally(filename);
- PostNotification?.Invoke(notification);
+ ProgressNotification notify = notification ?? new ProgressNotification();
Guid id = model.ID;
return await Task.Run(() =>
{
- RealmAccess.Run(r =>
+ realmAccess.Run(r =>
{
TModel refetchModel = r.Find(id);
- ExportToStream(refetchModel, stream, notification);
+ ExportToStream(refetchModel, stream, notify, cancellationToken);
});
- }, notification.CancellationToken).ContinueWith(t =>
+ }, cancellationToken).ContinueWith(t =>
{
- if (t.IsCanceled)
- {
- return false;
- }
-
if (t.IsFaulted)
{
- notification.State = ProgressNotificationState.Cancelled;
+ notify.State = ProgressNotificationState.Cancelled;
Logger.Error(t.Exception, "An error occurred while exporting");
return false;
}
- notification.CompletionText = "Export Complete, Click to open the folder";
- notification.State = ProgressNotificationState.Completed;
+ notify.CompletionText = "Export Complete, Click to open the folder";
+ notify.State = ProgressNotificationState.Completed;
return true;
- });
+ }, cancellationToken);
}
///
@@ -119,7 +129,8 @@ namespace osu.Game.Database
/// The item to export.
/// The output stream to export to.
/// The notification will displayed to the user
- protected abstract void ExportToStream(TModel model, Stream outputStream, ProgressNotification notification);
+ /// The Cancellation token that can cancel the exporting.
+ protected abstract void ExportToStream(TModel model, Stream outputStream, ProgressNotification notification, CancellationToken cancellationToken = default);
}
public abstract class LegacyArchiveExporter : LegacyModelExporter
@@ -130,15 +141,17 @@ namespace osu.Game.Database
{
}
- protected override void ExportToStream(TModel model, Stream outputStream, ProgressNotification notification) => exportZipArchive(model, outputStream, notification);
+ protected override void ExportToStream(TModel model, Stream outputStream, ProgressNotification notification, CancellationToken cancellationToken = default)
+ => exportZipArchive(model, outputStream, notification, cancellationToken);
///
/// Exports an item to Stream as a legacy (.zip based) package.
///
- /// The item to export.
+ /// The model will be exported.
/// The output stream to export to.
/// The notification will displayed to the user
- private void exportZipArchive(TModel model, Stream outputStream, ProgressNotification notification)
+ /// The Cancellation token that can cancel the exporting.
+ private void exportZipArchive(TModel model, Stream outputStream, ProgressNotification notification, CancellationToken cancellationToken = default)
{
using var writer = new ZipWriter(outputStream, new ZipWriterOptions(CompressionType.Deflate));
@@ -147,7 +160,7 @@ namespace osu.Game.Database
foreach (var file in model.Files)
{
- notification.CancellationToken.ThrowIfCancellationRequested();
+ cancellationToken.ThrowIfCancellationRequested();
using (var stream = UserFileStorage.GetStream(file.File.GetStoragePath()))
{
diff --git a/osu.Game/Database/LegacyScoreExporter.cs b/osu.Game/Database/LegacyScoreExporter.cs
index 1a30d823e1..b3a9276d5e 100644
--- a/osu.Game/Database/LegacyScoreExporter.cs
+++ b/osu.Game/Database/LegacyScoreExporter.cs
@@ -3,6 +3,7 @@
using System.IO;
using System.Linq;
+using System.Threading;
using osu.Framework.Platform;
using osu.Game.Extensions;
using osu.Game.Overlays.Notifications;
@@ -19,7 +20,7 @@ namespace osu.Game.Database
protected override string FileExtension => ".osr";
- protected override void ExportToStream(ScoreInfo model, Stream stream, ProgressNotification notification)
+ protected override void ExportToStream(ScoreInfo model, Stream stream, ProgressNotification notification, CancellationToken cancellationToken = default)
{
var file = model.Files.SingleOrDefault();
if (file == null)
From 29d6483e172597216df72e884ff8f9096985820d Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Fri, 17 Feb 2023 22:19:24 +0900
Subject: [PATCH 0136/1400] ConfigureAwait for awaited task
---
osu.Game/Database/LegacyModelExporter.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/osu.Game/Database/LegacyModelExporter.cs b/osu.Game/Database/LegacyModelExporter.cs
index 1475f29f89..ff0e3de20a 100644
--- a/osu.Game/Database/LegacyModelExporter.cs
+++ b/osu.Game/Database/LegacyModelExporter.cs
@@ -78,7 +78,7 @@ namespace osu.Game.Database
using (var stream = exportStorage.CreateFileSafely(filename))
{
- success = await ExportToStreamAsync(model, stream, notification, cancellationToken ?? notification.CancellationToken);
+ success = await ExportToStreamAsync(model, stream, notification, cancellationToken ?? notification.CancellationToken).ConfigureAwait(false);
}
if (!success)
@@ -119,7 +119,7 @@ namespace osu.Game.Database
notify.CompletionText = "Export Complete, Click to open the folder";
notify.State = ProgressNotificationState.Completed;
return true;
- }, cancellationToken);
+ }, cancellationToken).ConfigureAwait(false);
}
///
From 843d841f5a4687caccde1dc0a5d3570ee653875f Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Fri, 17 Feb 2023 22:23:50 +0900
Subject: [PATCH 0137/1400] GetFilename and something other
https://github.com/ppy/osu/pull/21739
---
osu.Game/Database/LegacyModelExporter.cs | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/osu.Game/Database/LegacyModelExporter.cs b/osu.Game/Database/LegacyModelExporter.cs
index ff0e3de20a..644b486c2d 100644
--- a/osu.Game/Database/LegacyModelExporter.cs
+++ b/osu.Game/Database/LegacyModelExporter.cs
@@ -32,10 +32,10 @@ namespace osu.Game.Database
protected Storage UserFileStorage;
private readonly Storage exportStorage;
+ protected virtual string GetFilename(TModel item) => item.GetDisplayString();
private readonly RealmAccess realmAccess;
- private string filename = string.Empty;
public Action? PostNotification { get; set; }
///
@@ -62,9 +62,12 @@ namespace osu.Game.Database
///
public async Task ExportAsync(TModel model, CancellationToken? cancellationToken = null)
{
- string itemFilename = model.GetDisplayString().GetValidFilename();
- IEnumerable existingExports = exportStorage.GetFiles("", $"{itemFilename}*{FileExtension}");
- filename = NamingUtils.GetNextBestFilename(existingExports, $"{itemFilename}{FileExtension}");
+ string itemFilename = GetFilename(model).GetValidFilename();
+ IEnumerable existingExports =
+ exportStorage
+ .GetFiles(string.Empty, $"{itemFilename}*{FileExtension}")
+ .Concat(exportStorage.GetDirectories(string.Empty));
+ string filename = NamingUtils.GetNextBestFilename(existingExports, $"{itemFilename}{FileExtension}");
bool success;
ProgressNotification notification = new ProgressNotification
From 309e9b24e28135dc9ef9e341292ddb7137efaa33 Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Sun, 19 Feb 2023 01:18:27 +0900
Subject: [PATCH 0138/1400] split LegacyArchiveExporter
---
osu.Game/Database/LegacyArchiveExporter.cs | 73 ++++++++++++++++++++++
osu.Game/Database/LegacyModelExporter.cs | 60 ------------------
2 files changed, 73 insertions(+), 60 deletions(-)
create mode 100644 osu.Game/Database/LegacyArchiveExporter.cs
diff --git a/osu.Game/Database/LegacyArchiveExporter.cs b/osu.Game/Database/LegacyArchiveExporter.cs
new file mode 100644
index 0000000000..f87f373624
--- /dev/null
+++ b/osu.Game/Database/LegacyArchiveExporter.cs
@@ -0,0 +1,73 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.IO;
+using System.Linq;
+using System.Threading;
+using osu.Framework.Platform;
+using osu.Game.Extensions;
+using osu.Game.Overlays.Notifications;
+using Realms;
+using SharpCompress.Common;
+using SharpCompress.Writers;
+using SharpCompress.Writers.Zip;
+
+namespace osu.Game.Database
+{
+ public abstract class LegacyArchiveExporter : LegacyModelExporter
+ where TModel : RealmObject, IHasNamedFiles, IHasGuidPrimaryKey
+ {
+ protected LegacyArchiveExporter(Storage storage, RealmAccess realm)
+ : base(storage, realm)
+ {
+ }
+
+ protected override void ExportToStream(TModel model, Stream outputStream, ProgressNotification notification, CancellationToken cancellationToken = default)
+ => exportZipArchive(model, outputStream, notification, cancellationToken);
+
+ ///
+ /// Exports an item to Stream as a legacy (.zip based) package.
+ ///
+ /// The model will be exported.
+ /// The output stream to export to.
+ /// The notification will displayed to the user
+ /// The Cancellation token that can cancel the exporting.
+ private void exportZipArchive(TModel model, Stream outputStream, ProgressNotification notification, CancellationToken cancellationToken = default)
+ {
+ using var writer = new ZipWriter(outputStream, new ZipWriterOptions(CompressionType.Deflate));
+
+ float i = 0;
+ bool fileMissing = false;
+
+ foreach (var file in model.Files)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ using (var stream = UserFileStorage.GetStream(file.File.GetStoragePath()))
+ {
+ // Sometimes we cannot find the file(probably deleted by the user), so we handle this and post a error.
+ if (stream == null)
+ {
+ // Only pop up once to prevent spam.
+ if (!fileMissing)
+ {
+ PostNotification?.Invoke(new SimpleErrorNotification
+ {
+ Text = "Some of your files are missing, they will not be included in the archive"
+ });
+ fileMissing = true;
+ }
+ }
+ else
+ {
+ writer.Write(file.Filename, stream);
+ }
+ }
+
+ i++;
+ notification.Progress = i / model.Files.Count();
+ notification.Text = $"Exporting... ({i}/{model.Files.Count()})";
+ }
+ }
+ }
+}
diff --git a/osu.Game/Database/LegacyModelExporter.cs b/osu.Game/Database/LegacyModelExporter.cs
index 644b486c2d..69277879dc 100644
--- a/osu.Game/Database/LegacyModelExporter.cs
+++ b/osu.Game/Database/LegacyModelExporter.cs
@@ -13,9 +13,6 @@ using osu.Game.Extensions;
using osu.Game.Overlays.Notifications;
using osu.Game.Utils;
using Realms;
-using SharpCompress.Common;
-using SharpCompress.Writers;
-using SharpCompress.Writers.Zip;
namespace osu.Game.Database
{
@@ -135,61 +132,4 @@ namespace osu.Game.Database
/// The Cancellation token that can cancel the exporting.
protected abstract void ExportToStream(TModel model, Stream outputStream, ProgressNotification notification, CancellationToken cancellationToken = default);
}
-
- public abstract class LegacyArchiveExporter : LegacyModelExporter
- where TModel : RealmObject, IHasNamedFiles, IHasGuidPrimaryKey
- {
- protected LegacyArchiveExporter(Storage storage, RealmAccess realm)
- : base(storage, realm)
- {
- }
-
- protected override void ExportToStream(TModel model, Stream outputStream, ProgressNotification notification, CancellationToken cancellationToken = default)
- => exportZipArchive(model, outputStream, notification, cancellationToken);
-
- ///
- /// Exports an item to Stream as a legacy (.zip based) package.
- ///
- /// The model will be exported.
- /// The output stream to export to.
- /// The notification will displayed to the user
- /// The Cancellation token that can cancel the exporting.
- private void exportZipArchive(TModel model, Stream outputStream, ProgressNotification notification, CancellationToken cancellationToken = default)
- {
- using var writer = new ZipWriter(outputStream, new ZipWriterOptions(CompressionType.Deflate));
-
- float i = 0;
- bool fileMissing = false;
-
- foreach (var file in model.Files)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- using (var stream = UserFileStorage.GetStream(file.File.GetStoragePath()))
- {
- // Sometimes we cannot find the file(probably deleted by the user), so we handle this and post a error.
- if (stream == null)
- {
- // Only pop up once to prevent spam.
- if (!fileMissing)
- {
- PostNotification?.Invoke(new SimpleErrorNotification
- {
- Text = "Some of your files are missing, they will not be included in the archive"
- });
- fileMissing = true;
- }
- }
- else
- {
- writer.Write(file.Filename, stream);
- }
- }
-
- i++;
- notification.Progress = i / model.Files.Count();
- notification.Text = $"Exporting... ({i}/{model.Files.Count()})";
- }
- }
- }
}
From d61160374255aff4b4564207afd2c6aeca93405f Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Sun, 19 Feb 2023 01:45:09 +0900
Subject: [PATCH 0139/1400] catch OperationCanceledException
---
osu.Game/Database/LegacyModelExporter.cs | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/osu.Game/Database/LegacyModelExporter.cs b/osu.Game/Database/LegacyModelExporter.cs
index 69277879dc..e17805f417 100644
--- a/osu.Game/Database/LegacyModelExporter.cs
+++ b/osu.Game/Database/LegacyModelExporter.cs
@@ -76,9 +76,16 @@ namespace osu.Game.Database
notification.CompletionClickAction += () => exportStorage.PresentFileExternally(filename);
PostNotification?.Invoke(notification);
- using (var stream = exportStorage.CreateFileSafely(filename))
+ try
{
- success = await ExportToStreamAsync(model, stream, notification, cancellationToken ?? notification.CancellationToken).ConfigureAwait(false);
+ using (var stream = exportStorage.CreateFileSafely(filename))
+ {
+ success = await ExportToStreamAsync(model, stream, notification, cancellationToken ?? notification.CancellationToken).ConfigureAwait(false);
+ }
+ }
+ catch (OperationCanceledException)
+ {
+ success = false;
}
if (!success)
From 30985f192ee462a7e08a5a12792906b16f2229b0 Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Sun, 19 Feb 2023 02:06:07 +0900
Subject: [PATCH 0140/1400] catch ObjectDisposedException
---
osu.Game/Database/LegacyArchiveExporter.cs | 52 +++++++++++++---------
1 file changed, 32 insertions(+), 20 deletions(-)
diff --git a/osu.Game/Database/LegacyArchiveExporter.cs b/osu.Game/Database/LegacyArchiveExporter.cs
index f87f373624..2f75e36fee 100644
--- a/osu.Game/Database/LegacyArchiveExporter.cs
+++ b/osu.Game/Database/LegacyArchiveExporter.cs
@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System;
using System.IO;
using System.Linq;
using System.Threading;
@@ -39,34 +40,45 @@ namespace osu.Game.Database
float i = 0;
bool fileMissing = false;
- foreach (var file in model.Files)
+ try
{
- cancellationToken.ThrowIfCancellationRequested();
-
- using (var stream = UserFileStorage.GetStream(file.File.GetStoragePath()))
+ foreach (var file in model.Files)
{
- // Sometimes we cannot find the file(probably deleted by the user), so we handle this and post a error.
- if (stream == null)
+ cancellationToken.ThrowIfCancellationRequested();
+
+ using (var stream = UserFileStorage.GetStream(file.File.GetStoragePath()))
{
- // Only pop up once to prevent spam.
- if (!fileMissing)
+ // Sometimes we cannot find the file(probably deleted by the user), so we handle this and post a error.
+ if (stream == null)
{
- PostNotification?.Invoke(new SimpleErrorNotification
+ // Only pop up once to prevent spam.
+ if (!fileMissing)
{
- Text = "Some of your files are missing, they will not be included in the archive"
- });
- fileMissing = true;
+ PostNotification?.Invoke(new SimpleErrorNotification
+ {
+ Text = "Some of your files are missing, they will not be included in the archive"
+ });
+ fileMissing = true;
+ }
+ }
+ else
+ {
+ writer.Write(file.Filename, stream);
}
}
- else
- {
- writer.Write(file.Filename, stream);
- }
- }
- i++;
- notification.Progress = i / model.Files.Count();
- notification.Text = $"Exporting... ({i}/{model.Files.Count()})";
+ i++;
+ notification.Progress = i / model.Files.Count();
+ notification.Text = $"Exporting... ({i}/{model.Files.Count()})";
+ }
+ }
+ catch (ObjectDisposedException)
+ {
+ // outputStream may close before writing when request cancel
+ if (cancellationToken.IsCancellationRequested)
+ return;
+
+ throw;
}
}
}
From 2a6ea99e6a0da51b7e610125e4bbb2d6175675b3 Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Sun, 19 Feb 2023 02:09:59 +0900
Subject: [PATCH 0141/1400] store exportingModels for all exporter
No one wants to export multiple copies of the same model at the same time, right?
---
osu.Game/Database/LegacyModelExporter.cs | 28 ++++++++++++++++++++----
1 file changed, 24 insertions(+), 4 deletions(-)
diff --git a/osu.Game/Database/LegacyModelExporter.cs b/osu.Game/Database/LegacyModelExporter.cs
index e17805f417..f9605140e3 100644
--- a/osu.Game/Database/LegacyModelExporter.cs
+++ b/osu.Game/Database/LegacyModelExporter.cs
@@ -35,6 +35,9 @@ namespace osu.Game.Database
public Action? PostNotification { get; set; }
+ // Store the model being exported.
+ private readonly List exportingModels = new List();
+
///
/// Construct exporter.
/// Create a new exporter for each export, otherwise it will cause confusing notifications.
@@ -59,13 +62,26 @@ namespace osu.Game.Database
///
public async Task ExportAsync(TModel model, CancellationToken? cancellationToken = null)
{
+ if (!exportingModels.Contains(model))
+ {
+ exportingModels.Add(model);
+ }
+ else
+ {
+ PostNotification?.Invoke(new SimpleErrorNotification()
+ {
+ Text = "File is being exported"
+ });
+ return;
+ }
+
string itemFilename = GetFilename(model).GetValidFilename();
IEnumerable existingExports =
exportStorage
.GetFiles(string.Empty, $"{itemFilename}*{FileExtension}")
.Concat(exportStorage.GetDirectories(string.Empty));
string filename = NamingUtils.GetNextBestFilename(existingExports, $"{itemFilename}{FileExtension}");
- bool success;
+ bool success = false;
ProgressNotification notification = new ProgressNotification
{
@@ -87,10 +103,14 @@ namespace osu.Game.Database
{
success = false;
}
-
- if (!success)
+ finally
{
- exportStorage.Delete(filename);
+ if (!success)
+ {
+ exportStorage.Delete(filename);
+ }
+
+ exportingModels.Remove(model);
}
}
From 8446e7d841993bcb8644d542daa6a3ae9b482905 Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Sun, 19 Feb 2023 02:17:24 +0900
Subject: [PATCH 0142/1400] comment
---
osu.Game/Database/LegacyArchiveExporter.cs | 2 +-
osu.Game/Database/LegacyModelExporter.cs | 4 +++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/osu.Game/Database/LegacyArchiveExporter.cs b/osu.Game/Database/LegacyArchiveExporter.cs
index 2f75e36fee..24a5d52f73 100644
--- a/osu.Game/Database/LegacyArchiveExporter.cs
+++ b/osu.Game/Database/LegacyArchiveExporter.cs
@@ -74,7 +74,7 @@ namespace osu.Game.Database
}
catch (ObjectDisposedException)
{
- // outputStream may close before writing when request cancel
+ // outputStream may close before writing when request cancel.
if (cancellationToken.IsCancellationRequested)
return;
diff --git a/osu.Game/Database/LegacyModelExporter.cs b/osu.Game/Database/LegacyModelExporter.cs
index f9605140e3..fd63b5f28a 100644
--- a/osu.Game/Database/LegacyModelExporter.cs
+++ b/osu.Game/Database/LegacyModelExporter.cs
@@ -35,7 +35,7 @@ namespace osu.Game.Database
public Action? PostNotification { get; set; }
- // Store the model being exported.
+ // Store the model being exporting.
private readonly List exportingModels = new List();
///
@@ -62,6 +62,7 @@ namespace osu.Game.Database
///
public async Task ExportAsync(TModel model, CancellationToken? cancellationToken = null)
{
+ // check if the model is being exporting already
if (!exportingModels.Contains(model))
{
exportingModels.Add(model);
@@ -105,6 +106,7 @@ namespace osu.Game.Database
}
finally
{
+ // cleanup if export is failed or canceled.
if (!success)
{
exportStorage.Delete(filename);
From 79715fe37b3ac24ce30e1dd50e441c67adc27e5e Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Sun, 19 Feb 2023 02:24:07 +0900
Subject: [PATCH 0143/1400] catch when zipWriter dispose
ObjectDisposedException also appear when zipwriter dispose after user request cancel
---
osu.Game/Database/LegacyArchiveExporter.cs | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/osu.Game/Database/LegacyArchiveExporter.cs b/osu.Game/Database/LegacyArchiveExporter.cs
index 24a5d52f73..fd2befd2e0 100644
--- a/osu.Game/Database/LegacyArchiveExporter.cs
+++ b/osu.Game/Database/LegacyArchiveExporter.cs
@@ -35,13 +35,13 @@ namespace osu.Game.Database
/// The Cancellation token that can cancel the exporting.
private void exportZipArchive(TModel model, Stream outputStream, ProgressNotification notification, CancellationToken cancellationToken = default)
{
- using var writer = new ZipWriter(outputStream, new ZipWriterOptions(CompressionType.Deflate));
-
- float i = 0;
- bool fileMissing = false;
-
try
{
+ var writer = new ZipWriter(outputStream, new ZipWriterOptions(CompressionType.Deflate));
+
+ float i = 0;
+ bool fileMissing = false;
+
foreach (var file in model.Files)
{
cancellationToken.ThrowIfCancellationRequested();
From fba99b344ce666f04057096f42a0edf70fb41dcd Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Sun, 19 Feb 2023 02:41:08 +0900
Subject: [PATCH 0144/1400] Accidentally deleted using
wtf
---
osu.Game/Database/LegacyArchiveExporter.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/osu.Game/Database/LegacyArchiveExporter.cs b/osu.Game/Database/LegacyArchiveExporter.cs
index fd2befd2e0..e5215e13a6 100644
--- a/osu.Game/Database/LegacyArchiveExporter.cs
+++ b/osu.Game/Database/LegacyArchiveExporter.cs
@@ -37,7 +37,7 @@ namespace osu.Game.Database
{
try
{
- var writer = new ZipWriter(outputStream, new ZipWriterOptions(CompressionType.Deflate));
+ using var writer = new ZipWriter(outputStream, new ZipWriterOptions(CompressionType.Deflate));
float i = 0;
bool fileMissing = false;
From 229b31520f039a9dbacb99cabab04e132dfdf9fb Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Sun, 19 Feb 2023 02:42:33 +0900
Subject: [PATCH 0145/1400] remove ()
---
osu.Game/Database/LegacyModelExporter.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/osu.Game/Database/LegacyModelExporter.cs b/osu.Game/Database/LegacyModelExporter.cs
index fd63b5f28a..acb83ce1d5 100644
--- a/osu.Game/Database/LegacyModelExporter.cs
+++ b/osu.Game/Database/LegacyModelExporter.cs
@@ -69,7 +69,7 @@ namespace osu.Game.Database
}
else
{
- PostNotification?.Invoke(new SimpleErrorNotification()
+ PostNotification?.Invoke(new SimpleErrorNotification
{
Text = "File is being exported"
});
From 0667b8396083dd52fc1f4d321d49f56068c45ff4 Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Sun, 19 Feb 2023 02:56:53 +0900
Subject: [PATCH 0146/1400] Path.GetExtension() will not get null
---
osu.Game/Database/LegacyScoreImporter.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/osu.Game/Database/LegacyScoreImporter.cs b/osu.Game/Database/LegacyScoreImporter.cs
index 131b4ffb0e..b80a35f90a 100644
--- a/osu.Game/Database/LegacyScoreImporter.cs
+++ b/osu.Game/Database/LegacyScoreImporter.cs
@@ -20,7 +20,7 @@ namespace osu.Game.Database
return Enumerable.Empty();
return storage.GetFiles(ImportFromStablePath)
- .Where(p => Importer.HandledExtensions.Any(ext => Path.GetExtension(p)?.Equals(ext, StringComparison.OrdinalIgnoreCase) ?? false))
+ .Where(p => Importer.HandledExtensions.Any(ext => Path.GetExtension(p).Equals(ext, StringComparison.OrdinalIgnoreCase)))
.Select(path => storage.GetFullPath(path));
}
From 04dcd661e06988365775fec6044ddad12c39aa51 Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Tue, 21 Feb 2023 20:53:02 +0900
Subject: [PATCH 0147/1400] async logic fix
---
osu.Game/Database/LegacyModelExporter.cs | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/osu.Game/Database/LegacyModelExporter.cs b/osu.Game/Database/LegacyModelExporter.cs
index acb83ce1d5..cd405f90be 100644
--- a/osu.Game/Database/LegacyModelExporter.cs
+++ b/osu.Game/Database/LegacyModelExporter.cs
@@ -124,12 +124,12 @@ namespace osu.Game.Database
/// The notification will displayed to the user
/// The Cancellation token that can cancel the exporting.
/// Whether the export was successful
- public async Task ExportToStreamAsync(TModel model, Stream stream, ProgressNotification? notification = null, CancellationToken cancellationToken = default)
+ public Task ExportToStreamAsync(TModel model, Stream stream, ProgressNotification? notification = null, CancellationToken cancellationToken = default)
{
ProgressNotification notify = notification ?? new ProgressNotification();
Guid id = model.ID;
- return await Task.Run(() =>
+ return Task.Run(() =>
{
realmAccess.Run(r =>
{
@@ -148,7 +148,7 @@ namespace osu.Game.Database
notify.CompletionText = "Export Complete, Click to open the folder";
notify.State = ProgressNotificationState.Completed;
return true;
- }, cancellationToken).ConfigureAwait(false);
+ }, cancellationToken);
}
///
From d20e1df6030cba04cc2d75385608b59b560c5b93 Mon Sep 17 00:00:00 2001
From: cdwcgt
Date: Tue, 21 Feb 2023 20:54:06 +0900
Subject: [PATCH 0148/1400] wrong xmldoc
because of https://github.com/ppy/osu/pull/21308/commits/6900d0120a70287ef531a4c0facd398508a76b06
---
osu.Game/Database/LegacyModelExporter.cs | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/osu.Game/Database/LegacyModelExporter.cs b/osu.Game/Database/LegacyModelExporter.cs
index cd405f90be..96104a68a0 100644
--- a/osu.Game/Database/LegacyModelExporter.cs
+++ b/osu.Game/Database/LegacyModelExporter.cs
@@ -152,10 +152,9 @@ namespace osu.Game.Database
}
///
- /// Exports an item to Stream.
- /// Override if custom export method is required.
+ /// Exports model to Stream.
///
- /// The item to export.
+ /// The model to export.
/// The output stream to export to.
/// The notification will displayed to the user
/// The Cancellation token that can cancel the exporting.
From 90aa4288d0a9a265d666c8e66545108bce4d8edd Mon Sep 17 00:00:00 2001
From: Cootz
Date: Tue, 21 Feb 2023 18:35:53 +0300
Subject: [PATCH 0149/1400] Reduce the allowed length by 5 to account for (99)
suffix. Move truncating logic to `GetFilename`. Update tests.
---
osu.Game.Tests/Database/LegacyExporterTest.cs | 9 ++++++---
osu.Game/Database/LegacyExporter.cs | 20 +++++++++----------
2 files changed, 16 insertions(+), 13 deletions(-)
diff --git a/osu.Game.Tests/Database/LegacyExporterTest.cs b/osu.Game.Tests/Database/LegacyExporterTest.cs
index c9aea80585..d41b3a5017 100644
--- a/osu.Game.Tests/Database/LegacyExporterTest.cs
+++ b/osu.Game.Tests/Database/LegacyExporterTest.cs
@@ -46,7 +46,7 @@ namespace osu.Game.Tests.Database
Assert.That(item.Filename.Length, Is.LessThan(TestLegacyExporter.MAX_FILENAME_LENGTH));
//Export multiple times
- for (int i = 0; i < 10; i++)
+ for (int i = 0; i < 100; i++)
{
string expectedFileName = i == 0 ? short_filename : $"{short_filename} ({i})";
exportItemAndAssert(item, expectedFileName);
@@ -76,8 +76,11 @@ namespace osu.Game.Tests.Database
Assert.That(item.Filename.Length, Is.GreaterThan(TestLegacyExporter.MAX_FILENAME_LENGTH));
//Export multiple times
- for (int i = 0; i < 10; i++)
- exportItemAndAssert(item, expectedName);
+ for (int i = 0; i < 100; i++)
+ {
+ string expectedFilename = i == 0 ? expectedName : $"{expectedName} ({i})";
+ exportItemAndAssert(item, expectedFilename);
+ }
}
private void exportItemAndAssert(IHasNamedFiles item, string expectedName)
diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs
index cf88efb151..0fa7b9e03c 100644
--- a/osu.Game/Database/LegacyExporter.cs
+++ b/osu.Game/Database/LegacyExporter.cs
@@ -31,7 +31,7 @@ namespace osu.Game.Database
/// For more information see file specification syntax, file systems limitations
///
///
- public const int MAX_FILENAME_LENGTH = 255 - (32 + 4 + 2); //max path - (Guid + Guid "D" format chars + Storage.CreateFileSafely chars)
+ public const int MAX_FILENAME_LENGTH = 255 - (32 + 4 + 2 + 5); //max path - (Guid + Guid "D" format chars + Storage.CreateFileSafely chars + account for ' (99)' suffix)
///
/// The file extension for exports (including the leading '.').
@@ -48,7 +48,15 @@ namespace osu.Game.Database
UserFileStorage = storage.GetStorageForDirectory(@"files");
}
- protected virtual string GetFilename(TModel item) => item.GetDisplayString();
+ protected virtual string GetFilename(TModel item)
+ {
+ string filename = item.GetDisplayString();
+
+ if (filename.Length > MAX_FILENAME_LENGTH - FileExtension.Length)
+ return filename.Remove(MAX_FILENAME_LENGTH - FileExtension.Length);
+
+ return filename;
+ }
///
/// Exports an item to a legacy (.zip based) package.
@@ -65,14 +73,6 @@ namespace osu.Game.Database
string filename = NamingUtils.GetNextBestFilename(existingExports, $"{itemFilename}{FileExtension}");
- if (filename.Length > MAX_FILENAME_LENGTH)
- {
- string filenameWithoutExtension = Path.GetFileNameWithoutExtension(filename);
-
- filenameWithoutExtension = filenameWithoutExtension.Remove(MAX_FILENAME_LENGTH - FileExtension.Length);
- filename = $"{filenameWithoutExtension}{FileExtension}";
- }
-
using (var stream = exportStorage.CreateFileSafely(filename))
ExportModelTo(item, stream);
From fc3d74472cc52b6e06cd1c0791f7277d7ed77744 Mon Sep 17 00:00:00 2001
From: Salman Ahmed
Date: Tue, 21 Feb 2023 15:55:46 +0300
Subject: [PATCH 0150/1400] Add mobile local framework reference support
---
UseLocalFramework.ps1 | 48 ++++++++++++++++++++++++++++++++++++++-----
UseLocalFramework.sh | 39 +++++++++++++++++++++++++++++------
2 files changed, 76 insertions(+), 11 deletions(-)
diff --git a/UseLocalFramework.ps1 b/UseLocalFramework.ps1
index 837685f310..9f4547d980 100644
--- a/UseLocalFramework.ps1
+++ b/UseLocalFramework.ps1
@@ -3,15 +3,53 @@
#
# https://github.com/ppy/osu-framework/wiki/Testing-local-framework-checkout-with-other-projects
-$CSPROJ="osu.Game/osu.Game.csproj"
+$GAME_CSPROJ="osu.Game/osu.Game.csproj"
+$ANDROID_PROPS="osu.Android.props"
+$IOS_PROPS="osu.iOS.props"
$SLN="osu.sln"
-dotnet remove $CSPROJ package ppy.osu.Framework;
-dotnet sln $SLN add ../osu-framework/osu.Framework/osu.Framework.csproj ../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj;
-dotnet add $CSPROJ reference ../osu-framework/osu.Framework/osu.Framework.csproj
+dotnet remove $GAME_CSPROJ reference ppy.osu.Framework;
+dotnet remove $ANDROID_PROPS reference ppy.osu.Framework.Android;
+dotnet remove $IOS_PROPS reference ppy.osu.Framework.iOS;
+
+dotnet sln $SLN add ../osu-framework/osu.Framework/osu.Framework.csproj `
+ ../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj `
+ ../osu-framework/osu.Framework.Android/osu.Framework.Android.csproj `
+ ../osu-framework/osu.Framework.iOS/osu.Framework.iOS.csproj;
+
+dotnet add $GAME_CSPROJ reference ../osu-framework/osu.Framework/osu.Framework.csproj;
+dotnet add $ANDROID_PROPS reference ../osu-framework/osu.Framework.Android/osu.Framework.Android.csproj;
+dotnet add $IOS_PROPS reference ../osu-framework/osu.Framework.iOS/osu.Framework.iOS.csproj;
+
+# workaround for dotnet add not inserting $(MSBuildThisFileDirectory) on props files
+(Get-Content "osu.Android.props") -replace "`"..\\osu-framework", "`"`$(MSBuildThisFileDirectory)..\osu-framework" | Set-Content "osu.Android.props"
+(Get-Content "osu.iOS.props") -replace "`"..\\osu-framework", "`"`$(MSBuildThisFileDirectory)..\osu-framework" | Set-Content "osu.iOS.props"
+
+# needed because iOS framework nupkg includes a set of properties to work around certain issues during building,
+# and those get ignored when referencing framework via project, threfore we have to manually include it via props reference.
+(Get-Content "osu.iOS.props") |
+ Foreach-Object {
+ if ($_ -match "")
+ {
+ " "
+ }
+
+ $_
+ } | Set-Content "osu.iOS.props"
+
+$TMP=New-TemporaryFile
$SLNF=Get-Content "osu.Desktop.slnf" | ConvertFrom-Json
-$TMP=New-TemporaryFile
$SLNF.solution.projects += ("../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj")
ConvertTo-Json $SLNF | Out-File $TMP -Encoding UTF8
Move-Item -Path $TMP -Destination "osu.Desktop.slnf" -Force
+
+$SLNF=Get-Content "osu.Android.slnf" | ConvertFrom-Json
+$SLNF.solution.projects += ("../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj", "../osu-framework/osu.Framework.Android/osu.Framework.Android.csproj")
+ConvertTo-Json $SLNF | Out-File $TMP -Encoding UTF8
+Move-Item -Path $TMP -Destination "osu.Android.slnf" -Force
+
+$SLNF=Get-Content "osu.iOS.slnf" | ConvertFrom-Json
+$SLNF.solution.projects += ("../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj", "../osu-framework/osu.Framework.iOS/osu.Framework.iOS.csproj")
+ConvertTo-Json $SLNF | Out-File $TMP -Encoding UTF8
+Move-Item -Path $TMP -Destination "osu.iOS.slnf" -Force
diff --git a/UseLocalFramework.sh b/UseLocalFramework.sh
index 4fd1fdfd1b..c12b388e96 100755
--- a/UseLocalFramework.sh
+++ b/UseLocalFramework.sh
@@ -5,14 +5,41 @@
#
# https://github.com/ppy/osu-framework/wiki/Testing-local-framework-checkout-with-other-projects
-CSPROJ="osu.Game/osu.Game.csproj"
+GAME_CSPROJ="osu.Game/osu.Game.csproj"
+ANDROID_PROPS="osu.Android.props"
+IOS_PROPS="osu.iOS.props"
SLN="osu.sln"
-dotnet remove $CSPROJ package ppy.osu.Framework
-dotnet sln $SLN add ../osu-framework/osu.Framework/osu.Framework.csproj ../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj
-dotnet add $CSPROJ reference ../osu-framework/osu.Framework/osu.Framework.csproj
+dotnet remove $GAME_CSPROJ reference ppy.osu.Framework
+dotnet remove $ANDROID_PROPS reference ppy.osu.Framework.Android
+dotnet remove $IOS_PROPS reference ppy.osu.Framework.iOS
+
+dotnet sln $SLN add ../osu-framework/osu.Framework/osu.Framework.csproj \
+ ../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj \
+ ../osu-framework/osu.Framework.Android/osu.Framework.Android.csproj \
+ ../osu-framework/osu.Framework.iOS/osu.Framework.iOS.csproj
+
+dotnet add $GAME_CSPROJ reference ../osu-framework/osu.Framework/osu.Framework.csproj
+dotnet add $ANDROID_PROPS reference ../osu-framework/osu.Framework.Android/osu.Framework.Android.csproj
+dotnet add $IOS_PROPS reference ../osu-framework/osu.Framework.iOS/osu.Framework.iOS.csproj
+
+# workaround for dotnet add not inserting $(MSBuildThisFileDirectory) on props files
+sed -i.bak 's:"..\\osu-framework:"$(MSBuildThisFileDirectory)..\\osu-framework:g' ./osu.Android.props && rm osu.Android.props.bak
+sed -i.bak 's:"..\\osu-framework:"$(MSBuildThisFileDirectory)..\\osu-framework:g' ./osu.iOS.props && rm osu.iOS.props.bak
+
+# needed because iOS framework nupkg includes a set of properties to work around certain issues during building,
+# and those get ignored when referencing framework via project, threfore we have to manually include it via props reference.
+sed -i.bak '/<\/Project>/i\
+ \
+' ./osu.iOS.props && rm osu.iOS.props.bak
-SLNF="osu.Desktop.slnf"
tmp=$(mktemp)
+
jq '.solution.projects += ["../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj"]' osu.Desktop.slnf > $tmp
-mv -f $tmp $SLNF
+mv -f $tmp osu.Desktop.slnf
+
+jq '.solution.projects += ["../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj", "../osu-framework/osu.Framework.Android/osu.Framework.Android.csproj"]' osu.Android.slnf > $tmp
+mv -f $tmp osu.Android.slnf
+
+jq '.solution.projects += ["../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj", "../osu-framework/osu.Framework.iOS/osu.Framework.iOS.csproj"]' osu.iOS.slnf > $tmp
+mv -f $tmp osu.iOS.slnf
From 191604340f8cbaf4d42c31cbc2ef2665fdfbb318 Mon Sep 17 00:00:00 2001
From: Terochi
Date: Tue, 21 Feb 2023 19:05:10 +0100
Subject: [PATCH 0151/1400] Added a way for mod settings to be kept when
changing ruleset + test
---
.../TestSceneModSelectOverlay.cs | 48 +++++++++++++++++++
osu.Game/OsuGameBase.cs | 17 ++++++-
osu.Game/Rulesets/Mods/Mod.cs | 31 ++++++++++--
3 files changed, 91 insertions(+), 5 deletions(-)
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs
index 5ccaebd721..25edcd4e0a 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs
@@ -21,6 +21,7 @@ using osu.Game.Rulesets.Catch.Mods;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Mods;
+using osu.Game.Rulesets.Taiko.Mods;
using osu.Game.Tests.Mods;
using osuTK;
using osuTK.Input;
@@ -371,6 +372,53 @@ namespace osu.Game.Tests.Visual.UserInterface
AddAssert("no mod selected", () => SelectedMods.Value.Count == 0);
}
+ [Test]
+ public void TestKeepSharedSettingsFromSimilarMods()
+ {
+ const float setting_change = 1.2f;
+
+ createScreen();
+ changeRuleset(0);
+
+ AddStep("select difficulty adjust mod", () => SelectedMods.Value = new[] { Ruleset.Value.CreateInstance().CreateMod()! });
+
+ changeRuleset(0);
+ AddAssert("ensure mod still selected", () => SelectedMods.Value.SingleOrDefault() is OsuModDifficultyAdjust);
+
+ AddStep("change mod settings", () =>
+ {
+ var osuMod = (getMod() as OsuModDifficultyAdjust)!;
+ osuMod.ExtendedLimits.Value = true;
+ osuMod.CircleSize.Value = setting_change;
+ osuMod.DrainRate.Value = setting_change;
+ osuMod.OverallDifficulty.Value = setting_change;
+ osuMod.ApproachRate.Value = setting_change;
+ });
+
+ changeRuleset(1);
+ AddAssert("taiko variant selected", () => SelectedMods.Value.SingleOrDefault() is TaikoModDifficultyAdjust);
+
+ AddAssert("shared settings didn't change", () =>
+ {
+ var taikoMod = getMod() as TaikoModDifficultyAdjust;
+ return
+ taikoMod?.ExtendedLimits.Value == true &&
+ taikoMod?.DrainRate.Value == setting_change &&
+ taikoMod?.OverallDifficulty.Value == setting_change;
+ });
+
+ AddAssert("non-shared settings at default", () =>
+ {
+ var taikoMod = getMod() as TaikoModDifficultyAdjust;
+ if (taikoMod == null)
+ return false;
+
+ return taikoMod.ScrollSpeed.Value == taikoMod.ScrollSpeed.Default;
+ });
+
+ ModDifficultyAdjust getMod() => (SelectedMods.Value.Single() as ModDifficultyAdjust)!;
+ }
+
[Test]
public void TestExternallySetCustomizedMod()
{
diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs
index cf58d07b9e..9644e3fc75 100644
--- a/osu.Game/OsuGameBase.cs
+++ b/osu.Game/OsuGameBase.cs
@@ -393,8 +393,11 @@ namespace osu.Game
Ruleset.BindValueChanged(onRulesetChanged);
Beatmap.BindValueChanged(onBeatmapChanged);
+ SelectedMods.BindValueChanged(change => Logger.Log($"{modSetting(change.OldValue)} => {modSetting(change.NewValue)}"));
}
+ private object modSetting(IReadOnlyList mods) => mods.OfType().FirstOrDefault()?.GetSettingsSourceProperties().First().Item2.GetValue(mods.OfType().First())!;
+
private void addFilesWarning()
{
var realmStore = new RealmFileStore(realm, Storage);
@@ -626,7 +629,8 @@ namespace osu.Game
return;
}
- var previouslySelectedMods = SelectedMods.Value.ToArray();
+ //for some reason emptying SelectedMods resets all SettingSources Bindables to default value
+ var previouslySelectedMods = SelectedMods.Value.Select(mod => mod.DeepClone()).ToArray();
if (!SelectedMods.Disabled)
SelectedMods.Value = Array.Empty();
@@ -634,7 +638,16 @@ namespace osu.Game
AvailableMods.Value = dict;
if (!SelectedMods.Disabled)
- SelectedMods.Value = previouslySelectedMods.Select(m => instance.CreateModFromAcronym(m.Acronym)).Where(m => m != null).ToArray();
+ {
+ SelectedMods.Value = previouslySelectedMods.Select(oldMod =>
+ {
+ Mod newMod = instance.CreateModFromAcronym(oldMod.Acronym);
+
+ newMod?.CopyFromSimilar(oldMod);
+
+ return newMod;
+ }).Where(m => m != null).ToArray();
+ }
void revertRulesetChange() => Ruleset.Value = r.OldValue?.Available == true ? r.OldValue : RulesetStore.AvailableRulesets.First();
}
diff --git a/osu.Game/Rulesets/Mods/Mod.cs b/osu.Game/Rulesets/Mods/Mod.cs
index 04d55bc5fe..7cb647d223 100644
--- a/osu.Game/Rulesets/Mods/Mod.cs
+++ b/osu.Game/Rulesets/Mods/Mod.cs
@@ -12,6 +12,7 @@ using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Framework.Testing;
using osu.Game.Configuration;
+using osu.Game.Extensions;
using osu.Game.Rulesets.UI;
using osu.Game.Utils;
@@ -139,6 +140,30 @@ namespace osu.Game.Rulesets.Mods
return result;
}
+ ///
+ /// Copies all shared mod setting values from into this instance.
+ ///
+ /// The mod to copy properties from.
+ public void CopyFromSimilar(Mod source)
+ {
+ Dictionary oldSettings = new Dictionary();
+
+ foreach (var (_, property) in source.GetSettingsSourceProperties())
+ {
+ oldSettings.Add(property.Name.ToSnakeCase(), property.GetValue(source)!);
+ }
+
+ foreach (var (_, property) in this.GetSettingsSourceProperties())
+ {
+ var targetBindable = (IBindable)property.GetValue(this)!;
+
+ if (!oldSettings.TryGetValue(property.Name.ToSnakeCase(), out object? sourceSetting))
+ continue;
+
+ CopyAdjustedSetting(targetBindable, sourceSetting);
+ }
+ }
+
///
/// Copies mod setting values from into this instance, overwriting all existing settings.
///
@@ -148,10 +173,10 @@ namespace osu.Game.Rulesets.Mods
if (source.GetType() != GetType())
throw new ArgumentException($"Expected mod of type {GetType()}, got {source.GetType()}.", nameof(source));
- foreach (var (_, prop) in this.GetSettingsSourceProperties())
+ foreach (var (_, property) in this.GetSettingsSourceProperties())
{
- var targetBindable = (IBindable)prop.GetValue(this)!;
- var sourceBindable = (IBindable)prop.GetValue(source)!;
+ var targetBindable = (IBindable)property.GetValue(this)!;
+ var sourceBindable = (IBindable)property.GetValue(source)!;
CopyAdjustedSetting(targetBindable, sourceBindable);
}
From 5bec2d7c525fac4fd975f0abb3e5fd19a37ef843 Mon Sep 17 00:00:00 2001
From: tsrk
Date: Tue, 21 Feb 2023 19:02:56 +0000
Subject: [PATCH 0152/1400] style(KeyCounter): `forwardPlayback`
---
osu.Game/Screens/Play/KeyCounter.cs | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/osu.Game/Screens/Play/KeyCounter.cs b/osu.Game/Screens/Play/KeyCounter.cs
index 212843cbe9..a07c650736 100644
--- a/osu.Game/Screens/Play/KeyCounter.cs
+++ b/osu.Game/Screens/Play/KeyCounter.cs
@@ -60,17 +60,17 @@ namespace osu.Game.Screens.Play
countPresses.Value--;
}
- protected virtual void Activate(bool increment = true)
+ protected virtual void Activate(bool forwardPlayback = true)
{
IsActive.Value = true;
- if (increment)
+ if (forwardPlayback)
Increment();
}
- protected virtual void Deactivate(bool preserve = true)
+ protected virtual void Deactivate(bool forwardPlayback = true)
{
IsActive.Value = false;
- if (!preserve)
+ if (!forwardPlayback)
Decrement();
}
From 42a5a06b9d6e8e1416c2aaf828dfe236e9617b6e Mon Sep 17 00:00:00 2001
From: tsrk
Date: Tue, 21 Feb 2023 19:10:37 +0000
Subject: [PATCH 0153/1400] style(KeyCounter): fields and methods visiblity
---
osu.Game/Screens/Play/KeyCounter.cs | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/osu.Game/Screens/Play/KeyCounter.cs b/osu.Game/Screens/Play/KeyCounter.cs
index a07c650736..4bad6920e3 100644
--- a/osu.Game/Screens/Play/KeyCounter.cs
+++ b/osu.Game/Screens/Play/KeyCounter.cs
@@ -42,9 +42,9 @@ namespace osu.Game.Screens.Play
Name = trigger.Name;
}
- protected Bindable IsActive = new BindableBool();
+ protected readonly Bindable IsActive = new BindableBool();
- public void Increment()
+ private void increment()
{
if (!IsCounting)
return;
@@ -52,7 +52,7 @@ namespace osu.Game.Screens.Play
countPresses.Value++;
}
- public void Decrement()
+ private void decrement()
{
if (!IsCounting)
return;
@@ -64,14 +64,14 @@ namespace osu.Game.Screens.Play
{
IsActive.Value = true;
if (forwardPlayback)
- Increment();
+ increment();
}
protected virtual void Deactivate(bool forwardPlayback = true)
{
IsActive.Value = false;
if (!forwardPlayback)
- Decrement();
+ decrement();
}
protected override void Dispose(bool isDisposing)
From dd53a700711dd79fac8466fca94ea881db5fa537 Mon Sep 17 00:00:00 2001
From: Terochi
Date: Tue, 21 Feb 2023 20:59:36 +0100
Subject: [PATCH 0154/1400] Addressed change requests
---
.../TestSceneModSelectOverlay.cs | 4 +-
osu.Game/OsuGameBase.cs | 8 +---
osu.Game/Rulesets/Mods/Mod.cs | 40 +++++++++----------
3 files changed, 24 insertions(+), 28 deletions(-)
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs
index 25edcd4e0a..7a46876737 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs
@@ -403,8 +403,8 @@ namespace osu.Game.Tests.Visual.UserInterface
var taikoMod = getMod() as TaikoModDifficultyAdjust;
return
taikoMod?.ExtendedLimits.Value == true &&
- taikoMod?.DrainRate.Value == setting_change &&
- taikoMod?.OverallDifficulty.Value == setting_change;
+ taikoMod.DrainRate.Value == setting_change &&
+ taikoMod.OverallDifficulty.Value == setting_change;
});
AddAssert("non-shared settings at default", () =>
diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs
index 9644e3fc75..af2fb123d3 100644
--- a/osu.Game/OsuGameBase.cs
+++ b/osu.Game/OsuGameBase.cs
@@ -58,7 +58,6 @@ using osu.Game.Rulesets.Mods;
using osu.Game.Scoring;
using osu.Game.Skinning;
using osu.Game.Utils;
-using File = System.IO.File;
using RuntimeInfo = osu.Framework.RuntimeInfo;
namespace osu.Game
@@ -393,11 +392,8 @@ namespace osu.Game
Ruleset.BindValueChanged(onRulesetChanged);
Beatmap.BindValueChanged(onBeatmapChanged);
- SelectedMods.BindValueChanged(change => Logger.Log($"{modSetting(change.OldValue)} => {modSetting(change.NewValue)}"));
}
- private object modSetting(IReadOnlyList mods) => mods.OfType().FirstOrDefault()?.GetSettingsSourceProperties().First().Item2.GetValue(mods.OfType().First())!;
-
private void addFilesWarning()
{
var realmStore = new RealmFileStore(realm, Storage);
@@ -629,7 +625,7 @@ namespace osu.Game
return;
}
- //for some reason emptying SelectedMods resets all SettingSources Bindables to default value
+ //DeepCloning collection, because emptying SelectedMods resets all SettingSources Bindables to their default value
var previouslySelectedMods = SelectedMods.Value.Select(mod => mod.DeepClone()).ToArray();
if (!SelectedMods.Disabled)
@@ -643,7 +639,7 @@ namespace osu.Game
{
Mod newMod = instance.CreateModFromAcronym(oldMod.Acronym);
- newMod?.CopyFromSimilar(oldMod);
+ newMod?.CopySharedSettings(oldMod);
return newMod;
}).Where(m => m != null).ToArray();
diff --git a/osu.Game/Rulesets/Mods/Mod.cs b/osu.Game/Rulesets/Mods/Mod.cs
index 7cb647d223..bc588a5cd8 100644
--- a/osu.Game/Rulesets/Mods/Mod.cs
+++ b/osu.Game/Rulesets/Mods/Mod.cs
@@ -141,10 +141,28 @@ namespace osu.Game.Rulesets.Mods
}
///
- /// Copies all shared mod setting values from into this instance.
+ /// Copies mod setting values from into this instance, overwriting all existing settings.
///
/// The mod to copy properties from.
- public void CopyFromSimilar(Mod source)
+ public void CopyFrom(Mod source)
+ {
+ if (source.GetType() != GetType())
+ throw new ArgumentException($"Expected mod of type {GetType()}, got {source.GetType()}.", nameof(source));
+
+ foreach (var (_, property) in this.GetSettingsSourceProperties())
+ {
+ var targetBindable = (IBindable)property.GetValue(this)!;
+ var sourceBindable = (IBindable)property.GetValue(source)!;
+
+ CopyAdjustedSetting(targetBindable, sourceBindable);
+ }
+ }
+
+ ///
+ /// Copies all mod setting values sharing same from into this instance.
+ ///
+ /// The mod to copy properties from.
+ internal void CopySharedSettings(Mod source)
{
Dictionary oldSettings = new Dictionary();
@@ -164,24 +182,6 @@ namespace osu.Game.Rulesets.Mods
}
}
- ///
- /// Copies mod setting values from into this instance, overwriting all existing settings.
- ///
- /// The mod to copy properties from.
- public void CopyFrom(Mod source)
- {
- if (source.GetType() != GetType())
- throw new ArgumentException($"Expected mod of type {GetType()}, got {source.GetType()}.", nameof(source));
-
- foreach (var (_, property) in this.GetSettingsSourceProperties())
- {
- var targetBindable = (IBindable)property.GetValue(this)!;
- var sourceBindable = (IBindable)property.GetValue(source)!;
-
- CopyAdjustedSetting(targetBindable, sourceBindable);
- }
- }
-
///
/// When creating copies or clones of a Mod, this method will be called
/// to copy explicitly adjusted user settings from .
From 82b07d19f86374a24128ee4e8ff7918bf1aa7acf Mon Sep 17 00:00:00 2001
From: Terochi
Date: Tue, 21 Feb 2023 21:48:11 +0100
Subject: [PATCH 0155/1400] Fix of incorrect `using` optimization
---
osu.Game/OsuGameBase.cs | 1 +
1 file changed, 1 insertion(+)
diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs
index af2fb123d3..e16aaf39ee 100644
--- a/osu.Game/OsuGameBase.cs
+++ b/osu.Game/OsuGameBase.cs
@@ -58,6 +58,7 @@ using osu.Game.Rulesets.Mods;
using osu.Game.Scoring;
using osu.Game.Skinning;
using osu.Game.Utils;
+using File = System.IO.File;
using RuntimeInfo = osu.Framework.RuntimeInfo;
namespace osu.Game
From e321536acc2299c19b131b457838c84f15c1aed3 Mon Sep 17 00:00:00 2001
From: Terochi
Date: Wed, 22 Feb 2023 07:48:43 +0100
Subject: [PATCH 0156/1400] Small clean up
---
osu.Game/OsuGameBase.cs | 9 ++-------
1 file changed, 2 insertions(+), 7 deletions(-)
diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs
index e16aaf39ee..de1f2e810c 100644
--- a/osu.Game/OsuGameBase.cs
+++ b/osu.Game/OsuGameBase.cs
@@ -626,17 +626,12 @@ namespace osu.Game
return;
}
- //DeepCloning collection, because emptying SelectedMods resets all SettingSources Bindables to their default value
- var previouslySelectedMods = SelectedMods.Value.Select(mod => mod.DeepClone()).ToArray();
-
- if (!SelectedMods.Disabled)
- SelectedMods.Value = Array.Empty();
-
AvailableMods.Value = dict;
if (!SelectedMods.Disabled)
{
- SelectedMods.Value = previouslySelectedMods.Select(oldMod =>
+ //converting mods from one ruleset to the other, while also keeping their shared settings unchanged
+ SelectedMods.Value = SelectedMods.Value.Select(oldMod =>
{
Mod newMod = instance.CreateModFromAcronym(oldMod.Acronym);
From 6e48860c79646d0f60e86e7e010954773d300730 Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Wed, 22 Feb 2023 17:13:55 +0900
Subject: [PATCH 0157/1400] Update in line with framework menu handling changes
---
osu.Game/Graphics/UserInterface/DrawableOsuMenuItem.cs | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/osu.Game/Graphics/UserInterface/DrawableOsuMenuItem.cs b/osu.Game/Graphics/UserInterface/DrawableOsuMenuItem.cs
index ad02e3b2ab..0adff11342 100644
--- a/osu.Game/Graphics/UserInterface/DrawableOsuMenuItem.cs
+++ b/osu.Game/Graphics/UserInterface/DrawableOsuMenuItem.cs
@@ -77,10 +77,12 @@ namespace osu.Game.Graphics.UserInterface
private void updateState()
{
- hoverClickSounds.Enabled.Value = !Item.Action.Disabled;
- Alpha = Item.Action.Disabled ? 0.2f : 1;
+ bool enabledState = IsActionable || HasSubmenu;
- if (IsHovered && !Item.Action.Disabled)
+ hoverClickSounds.Enabled.Value = enabledState;
+ Alpha = enabledState ? 1 : 0.2f;
+
+ if (IsHovered && enabledState)
{
text.BoldText.FadeIn(transition_length, Easing.OutQuint);
text.NormalText.FadeOut(transition_length, Easing.OutQuint);
From 16c8a392a1c7c73d0aeae9aa02edcd1a6e4d2f7e Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Wed, 22 Feb 2023 17:45:38 +0900
Subject: [PATCH 0158/1400] Add ability to send selected skin components to
front or back
---
osu.Game/Overlays/SkinEditor/SkinEditor.cs | 37 ++++++++++++++++++-
.../SkinEditor/SkinSelectionHandler.cs | 9 +++++
.../ISerialisableDrawableContainer.cs | 3 +-
osu.Game/Skinning/SkinComponentsContainer.cs | 4 +-
4 files changed, 49 insertions(+), 4 deletions(-)
diff --git a/osu.Game/Overlays/SkinEditor/SkinEditor.cs b/osu.Game/Overlays/SkinEditor/SkinEditor.cs
index 9d470f58f1..95b88b141f 100644
--- a/osu.Game/Overlays/SkinEditor/SkinEditor.cs
+++ b/osu.Game/Overlays/SkinEditor/SkinEditor.cs
@@ -556,11 +556,46 @@ namespace osu.Game.Overlays.SkinEditor
changeHandler?.BeginChange();
foreach (var item in items)
- availableTargets.FirstOrDefault(t => t.Components.Contains(item))?.Remove(item);
+ availableTargets.FirstOrDefault(t => t.Components.Contains(item))?.Remove(item, true);
changeHandler?.EndChange();
}
+ public void BringSelectionToFront()
+ {
+ if (getTarget(selectedTarget.Value) is not SkinComponentsContainer target)
+ return;
+
+ // Iterating by target components order ensures we maintain the same order across selected components, regardless
+ // of the order they were selected in.
+ foreach (var d in target.Components.ToArray())
+ {
+ if (!SelectedComponents.Contains(d))
+ continue;
+
+ target.Remove(d, false);
+
+ // Selection would be reset by the remove.
+ SelectedComponents.Add(d);
+ target.Add(d);
+ }
+ }
+
+ public void SendSelectionToBack()
+ {
+ if (getTarget(selectedTarget.Value) is not SkinComponentsContainer target)
+ return;
+
+ foreach (var d in target.Components.ToArray())
+ {
+ if (SelectedComponents.Contains(d))
+ continue;
+
+ target.Remove(d, false);
+ target.Add(d);
+ }
+ }
+
#region Drag & drop import handling
public Task Import(params string[] paths)
diff --git a/osu.Game/Overlays/SkinEditor/SkinSelectionHandler.cs b/osu.Game/Overlays/SkinEditor/SkinSelectionHandler.cs
index c628ad8480..b43f4eeb00 100644
--- a/osu.Game/Overlays/SkinEditor/SkinSelectionHandler.cs
+++ b/osu.Game/Overlays/SkinEditor/SkinSelectionHandler.cs
@@ -13,6 +13,7 @@ using osu.Framework.Utils;
using osu.Game.Extensions;
using osu.Game.Graphics.UserInterface;
using osu.Game.Rulesets.Edit;
+using osu.Game.Screens.Edit.Components.Menus;
using osu.Game.Screens.Edit.Compose.Components;
using osu.Game.Skinning;
using osuTK;
@@ -206,6 +207,14 @@ namespace osu.Game.Overlays.SkinEditor
((Drawable)blueprint.Item).Position = Vector2.Zero;
});
+ yield return new EditorMenuItemSpacer();
+
+ yield return new OsuMenuItem("Bring to front", MenuItemType.Standard, () => skinEditor.BringSelectionToFront());
+
+ yield return new OsuMenuItem("Send to back", MenuItemType.Standard, () => skinEditor.SendSelectionToBack());
+
+ yield return new EditorMenuItemSpacer();
+
foreach (var item in base.GetContextMenuItemsForSelection(selection))
yield return item;
diff --git a/osu.Game/Skinning/ISerialisableDrawableContainer.cs b/osu.Game/Skinning/ISerialisableDrawableContainer.cs
index 9f93d8a2e3..a19c8c5162 100644
--- a/osu.Game/Skinning/ISerialisableDrawableContainer.cs
+++ b/osu.Game/Skinning/ISerialisableDrawableContainer.cs
@@ -45,6 +45,7 @@ namespace osu.Game.Skinning
/// Remove an existing skinnable component from this target.
///
/// The component to remove.
- void Remove(ISerialisableDrawable component);
+ /// Whether removed items should be immediately disposed.
+ void Remove(ISerialisableDrawable component, bool disposeImmediately);
}
}
diff --git a/osu.Game/Skinning/SkinComponentsContainer.cs b/osu.Game/Skinning/SkinComponentsContainer.cs
index d18e9023cd..adf0a288b4 100644
--- a/osu.Game/Skinning/SkinComponentsContainer.cs
+++ b/osu.Game/Skinning/SkinComponentsContainer.cs
@@ -100,7 +100,7 @@ namespace osu.Game.Skinning
///
/// Thrown when attempting to add an element to a target which is not supported by the current skin.
/// Thrown if the provided instance is not a .
- public void Remove(ISerialisableDrawable component)
+ public void Remove(ISerialisableDrawable component, bool disposeImmediately)
{
if (content == null)
throw new NotSupportedException("Attempting to remove a new component from a target container which is not supported by the current skin.");
@@ -108,7 +108,7 @@ namespace osu.Game.Skinning
if (!(component is Drawable drawable))
throw new ArgumentException($"Provided argument must be of type {nameof(Drawable)}.", nameof(component));
- content.Remove(drawable, true);
+ content.Remove(drawable, disposeImmediately);
components.Remove(component);
}
From 90ca635a1771d9953f3891656296b7b7d98dda84 Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Wed, 22 Feb 2023 17:56:59 +0900
Subject: [PATCH 0159/1400] Fix weird nullability in `TestSceneSkinEditor`
---
.../Visual/Gameplay/TestSceneSkinEditor.cs | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs
index 2f20d75813..83609b9ae7 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs
@@ -4,6 +4,7 @@
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
+using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Testing;
@@ -21,7 +22,7 @@ namespace osu.Game.Tests.Visual.Gameplay
{
public partial class TestSceneSkinEditor : PlayerTestScene
{
- private SkinEditor? skinEditor;
+ private SkinEditor skinEditor = null!;
protected override bool Autoplay => true;
@@ -40,17 +41,18 @@ namespace osu.Game.Tests.Visual.Gameplay
AddStep("reload skin editor", () =>
{
- skinEditor?.Expire();
+ if (skinEditor.IsNotNull())
+ skinEditor.Expire();
Player.ScaleTo(0.4f);
LoadComponentAsync(skinEditor = new SkinEditor(Player), Add);
});
- AddUntilStep("wait for loaded", () => skinEditor!.IsLoaded);
+ AddUntilStep("wait for loaded", () => skinEditor.IsLoaded);
}
[Test]
public void TestToggleEditor()
{
- AddToggleStep("toggle editor visibility", _ => skinEditor!.ToggleVisibility());
+ AddToggleStep("toggle editor visibility", _ => skinEditor.ToggleVisibility());
}
[Test]
@@ -63,7 +65,7 @@ namespace osu.Game.Tests.Visual.Gameplay
var blueprint = skinEditor.ChildrenOfType().First(b => b.Item is BarHitErrorMeter);
hitErrorMeter = (BarHitErrorMeter)blueprint.Item;
- skinEditor!.SelectedComponents.Clear();
+ skinEditor.SelectedComponents.Clear();
skinEditor.SelectedComponents.Add(blueprint.Item);
});
From 32a9c066dfd2a02c0cc40f5554417ab5bd8e8c97 Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Wed, 22 Feb 2023 18:17:03 +0900
Subject: [PATCH 0160/1400] Add test coverage of bring-to-front / send-to-back
operations
---
.../Visual/Gameplay/TestSceneSkinEditor.cs | 51 ++++++++++++++++++-
1 file changed, 50 insertions(+), 1 deletion(-)
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs
index 83609b9ae7..9690d00d4c 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs
@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
@@ -32,12 +33,14 @@ namespace osu.Game.Tests.Visual.Gameplay
[Cached]
public readonly EditorClipboard Clipboard = new EditorClipboard();
+ private SkinComponentsContainer targetContainer => Player.ChildrenOfType().First();
+
[SetUpSteps]
public override void SetUpSteps()
{
base.SetUpSteps();
- AddUntilStep("wait for hud load", () => Player.ChildrenOfType().All(c => c.ComponentsLoaded));
+ AddUntilStep("wait for hud load", () => targetContainer.ComponentsLoaded);
AddStep("reload skin editor", () =>
{
@@ -49,6 +52,52 @@ namespace osu.Game.Tests.Visual.Gameplay
AddUntilStep("wait for loaded", () => skinEditor.IsLoaded);
}
+ [TestCase(false)]
+ [TestCase(true)]
+ public void TestBringToFront(bool alterSelectionOrder)
+ {
+ AddAssert("Ensure over three components available", () => targetContainer.Components.Count, () => Is.GreaterThan(3));
+
+ IEnumerable originalOrder = null!;
+
+ AddStep("Save order of components before operation", () => originalOrder = targetContainer.Components.Take(3).ToArray());
+
+ if (alterSelectionOrder)
+ AddStep("Select first three components in reverse order", () => skinEditor.SelectedComponents.AddRange(originalOrder.Reverse()));
+ else
+ AddStep("Select first three components", () => skinEditor.SelectedComponents.AddRange(originalOrder));
+
+ AddAssert("Components are not front-most", () => targetContainer.Components.TakeLast(3).ToArray(), () => Is.Not.EqualTo(skinEditor.SelectedComponents));
+
+ AddStep("Bring to front", () => skinEditor.BringSelectionToFront());
+ AddAssert("Ensure components are now front-most in original order", () => targetContainer.Components.TakeLast(3).ToArray(), () => Is.EqualTo(originalOrder));
+ AddStep("Bring to front again", () => skinEditor.BringSelectionToFront());
+ AddAssert("Ensure components are still front-most in original order", () => targetContainer.Components.TakeLast(3).ToArray(), () => Is.EqualTo(originalOrder));
+ }
+
+ [TestCase(false)]
+ [TestCase(true)]
+ public void TestSendToBack(bool alterSelectionOrder)
+ {
+ AddAssert("Ensure over three components available", () => targetContainer.Components.Count, () => Is.GreaterThan(3));
+
+ IEnumerable originalOrder = null!;
+
+ AddStep("Save order of components before operation", () => originalOrder = targetContainer.Components.TakeLast(3).ToArray());
+
+ if (alterSelectionOrder)
+ AddStep("Select last three components in reverse order", () => skinEditor.SelectedComponents.AddRange(originalOrder.Reverse()));
+ else
+ AddStep("Select last three components", () => skinEditor.SelectedComponents.AddRange(originalOrder));
+
+ AddAssert("Components are not back-most", () => targetContainer.Components.Take(3).ToArray(), () => Is.Not.EqualTo(skinEditor.SelectedComponents));
+
+ AddStep("Send to back", () => skinEditor.SendSelectionToBack());
+ AddAssert("Ensure components are now back-most in original order", () => targetContainer.Components.Take(3).ToArray(), () => Is.EqualTo(originalOrder));
+ AddStep("Send to back again", () => skinEditor.SendSelectionToBack());
+ AddAssert("Ensure components are still back-most in original order", () => targetContainer.Components.Take(3).ToArray(), () => Is.EqualTo(originalOrder));
+ }
+
[Test]
public void TestToggleEditor()
{
From 1beec7103725ca9ade4b081804d8a7cc83e5c912 Mon Sep 17 00:00:00 2001
From: tsrk
Date: Wed, 22 Feb 2023 14:58:27 +0000
Subject: [PATCH 0161/1400] refactor(KeyCounterDisplay): apply suggestions
I also took the freedom to add type checking, as we can't limit the
usage of `Add()` since it's a Container. The exception thrown also
advises of using the suggested `AddTrigger()` instead.
---
.../Visual/Gameplay/TestSceneAutoplay.cs | 2 +-
.../Visual/Gameplay/TestSceneHUDOverlay.cs | 2 +-
.../Visual/Gameplay/TestSceneKeyCounter.cs | 4 +-
.../TestSceneSkinEditorMultipleSkins.cs | 2 +-
.../Gameplay/TestSceneSkinnableHUDOverlay.cs | 2 +-
osu.Game/Rulesets/UI/RulesetInputManager.cs | 10 +--
.../Screens/Play/DefaultKeyCounterDisplay.cs | 27 ++++--
osu.Game/Screens/Play/KeyCounter.cs | 6 +-
osu.Game/Screens/Play/KeyCounterDisplay.cs | 84 +++++++++++--------
osu.Game/Screens/Play/Player.cs | 7 +-
10 files changed, 86 insertions(+), 60 deletions(-)
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs
index 4b6e1f089f..903cd178b7 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs
@@ -38,7 +38,7 @@ namespace osu.Game.Tests.Visual.Gameplay
AddUntilStep("key counter counted keys", () => Player.HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses.Value > 2));
seekTo(referenceBeatmap.Breaks[0].StartTime);
- AddAssert("keys not counting", () => !Player.HUDOverlay.KeyCounter.IsCounting);
+ AddAssert("keys not counting", () => !Player.HUDOverlay.KeyCounter.IsCounting.Value);
AddAssert("overlay displays 100% accuracy", () => Player.BreakOverlay.ChildrenOfType().Single().AccuracyDisplay.Current.Value == 1);
AddStep("rewind", () => Player.GameplayClockContainer.Seek(-80000));
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs
index af79650d29..a586d798f5 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs
@@ -267,7 +267,7 @@ namespace osu.Game.Tests.Visual.Gameplay
hudOverlay = new HUDOverlay(null, Array.Empty());
// Add any key just to display the key counter visually.
- hudOverlay.KeyCounter.Add(hudOverlay.KeyCounter.CreateKeyCounter(new KeyCounterKeyboardTrigger(Key.Space)));
+ hudOverlay.KeyCounter.AddTrigger(new KeyCounterKeyboardTrigger(Key.Space));
scoreProcessor.Combo.Value = 1;
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs
index 9eeee800d9..5405274cd0 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs
@@ -35,7 +35,7 @@ namespace osu.Game.Tests.Visual.Gameplay
AddStep("Add random", () =>
{
Key key = (Key)((int)Key.A + RNG.Next(26));
- kc.Add(kc.CreateKeyCounter(new KeyCounterKeyboardTrigger(key)));
+ kc.AddTrigger(new KeyCounterKeyboardTrigger(key));
});
Key testKey = ((KeyCounterKeyboardTrigger)kc.Children.First().Trigger).Key;
@@ -49,7 +49,7 @@ namespace osu.Game.Tests.Visual.Gameplay
AddAssert($"Check {testKey} counter after keypress", () => testCounter.CountPresses.Value == 1);
addPressKeyStep();
AddAssert($"Check {testKey} counter after keypress", () => testCounter.CountPresses.Value == 2);
- AddStep("Disable counting", () => testCounter.IsCounting = false);
+ AddStep("Disable counting", () => testCounter.IsCounting.Value = false);
addPressKeyStep();
AddAssert($"Check {testKey} count has not changed", () => testCounter.CountPresses.Value == 2);
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs
index 432ff2fc7e..e4f257582d 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs
@@ -53,7 +53,7 @@ namespace osu.Game.Tests.Visual.Gameplay
};
// Add any key just to display the key counter visually.
- hudOverlay.KeyCounter.Add(hudOverlay.KeyCounter.CreateKeyCounter(new KeyCounterKeyboardTrigger(Key.Space)));
+ hudOverlay.KeyCounter.AddTrigger(new KeyCounterKeyboardTrigger(Key.Space));
scoreProcessor.Combo.Value = 1;
return new Container
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs
index 24de29fa03..9848894f84 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs
@@ -88,7 +88,7 @@ namespace osu.Game.Tests.Visual.Gameplay
hudOverlay = new HUDOverlay(null, Array.Empty