mirror of
https://github.com/ppy/osu.git
synced 2024-11-11 08:27:49 +08:00
Merge branch 'master' into taiko-hitsounding-final-attempt
This commit is contained in:
commit
055e4a78f0
@ -9,6 +9,9 @@ indent_style = space
|
|||||||
indent_size = 2
|
indent_size = 2
|
||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[g_*.cs]
|
||||||
|
generated_code = true
|
||||||
|
|
||||||
[*.cs]
|
[*.cs]
|
||||||
end_of_line = crlf
|
end_of_line = crlf
|
||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
<AndroidManifestMerger>manifestmerger.jar</AndroidManifestMerger>
|
<AndroidManifestMerger>manifestmerger.jar</AndroidManifestMerger>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2023.625.0" />
|
<PackageReference Include="ppy.osu.Framework.Android" Version="2023.707.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<AndroidManifestOverlay Include="$(MSBuildThisFileDirectory)osu.Android\Properties\AndroidManifestOverlay.xml" />
|
<AndroidManifestOverlay Include="$(MSBuildThisFileDirectory)osu.Android\Properties\AndroidManifestOverlay.xml" />
|
||||||
|
@ -187,7 +187,7 @@ namespace osu.Desktop
|
|||||||
return edit.BeatmapInfo.ToString() ?? string.Empty;
|
return edit.BeatmapInfo.ToString() ?? string.Empty;
|
||||||
|
|
||||||
case UserActivity.WatchingReplay watching:
|
case UserActivity.WatchingReplay watching:
|
||||||
return watching.BeatmapInfo.ToString();
|
return watching.BeatmapInfo?.ToString() ?? string.Empty;
|
||||||
|
|
||||||
case UserActivity.InLobby lobby:
|
case UserActivity.InLobby lobby:
|
||||||
return privacyMode.Value == DiscordRichPresenceMode.Limited ? string.Empty : lobby.Room.Name.Value;
|
return privacyMode.Value == DiscordRichPresenceMode.Limited ? string.Empty : lobby.Room.Name.Value;
|
||||||
|
@ -147,14 +147,12 @@ namespace osu.Desktop
|
|||||||
{
|
{
|
||||||
base.SetHost(host);
|
base.SetHost(host);
|
||||||
|
|
||||||
var desktopWindow = (SDL2DesktopWindow)host.Window;
|
|
||||||
|
|
||||||
var iconStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(GetType(), "lazer.ico");
|
var iconStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(GetType(), "lazer.ico");
|
||||||
if (iconStream != null)
|
if (iconStream != null)
|
||||||
desktopWindow.SetIconFromStream(iconStream);
|
host.Window.SetIconFromStream(iconStream);
|
||||||
|
|
||||||
desktopWindow.CursorState |= CursorState.Hidden;
|
host.Window.CursorState |= CursorState.Hidden;
|
||||||
desktopWindow.Title = Name;
|
host.Window.Title = Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override BatteryInfo CreateBatteryInfo() => new SDL2BatteryInfo();
|
protected override BatteryInfo CreateBatteryInfo() => new SDL2BatteryInfo();
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Rulesets.Catch.UI;
|
using osu.Game.Rulesets.Catch.UI;
|
||||||
|
using osu.Game.Screens.Play;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
@ -59,7 +60,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy
|
|||||||
|
|
||||||
lastDisplayedCombo = combo;
|
lastDisplayedCombo = combo;
|
||||||
|
|
||||||
if (Time.Elapsed < 0)
|
if ((Clock as IGameplayClock)?.IsRewinding == true)
|
||||||
{
|
{
|
||||||
// needs more work to make rewind somehow look good.
|
// needs more work to make rewind somehow look good.
|
||||||
// basically we want the previous increment to play... or turning off RemoveCompletedTransforms (not feasible from a performance angle).
|
// basically we want the previous increment to play... or turning off RemoveCompletedTransforms (not feasible from a performance angle).
|
||||||
|
@ -10,6 +10,7 @@ using osu.Game.Rulesets.Catch.Objects.Drawables;
|
|||||||
using osu.Game.Rulesets.Catch.Replays;
|
using osu.Game.Rulesets.Catch.Replays;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
|
using osu.Game.Screens.Play;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.UI
|
namespace osu.Game.Rulesets.Catch.UI
|
||||||
@ -96,7 +97,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
|
|
||||||
comboDisplay.X = Catcher.X;
|
comboDisplay.X = Catcher.X;
|
||||||
|
|
||||||
if (Time.Elapsed <= 0)
|
if ((Clock as IGameplayClock)?.IsRewinding == true)
|
||||||
{
|
{
|
||||||
// This is probably a wrong value, but currently the true value is not recorded.
|
// This is probably a wrong value, but currently the true value is not recorded.
|
||||||
// Setting `true` will prevent generation of false-positive after-images (with more false-negatives).
|
// Setting `true` will prevent generation of false-positive after-images (with more false-negatives).
|
||||||
|
@ -16,6 +16,7 @@ using osu.Game.Rulesets.Objects;
|
|||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
|
using osu.Game.Screens.Play;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
@ -298,7 +299,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// do not run any of this logic when rewinding, as it inverts order of presses/releases.
|
// do not run any of this logic when rewinding, as it inverts order of presses/releases.
|
||||||
if (Time.Elapsed < 0)
|
if ((Clock as IGameplayClock)?.IsRewinding == true)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (CheckHittable?.Invoke(this, Time.Current) == false)
|
if (CheckHittable?.Invoke(this, Time.Current) == false)
|
||||||
@ -337,7 +338,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// do not run any of this logic when rewinding, as it inverts order of presses/releases.
|
// do not run any of this logic when rewinding, as it inverts order of presses/releases.
|
||||||
if (Time.Elapsed < 0)
|
if ((Clock as IGameplayClock)?.IsRewinding == true)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Tail.UpdateResult();
|
Tail.UpdateResult();
|
||||||
|
@ -14,6 +14,7 @@ using osu.Framework.Input.Events;
|
|||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osu.Game.Rulesets.Osu.Skinning.Default;
|
using osu.Game.Rulesets.Osu.Skinning.Default;
|
||||||
|
using osu.Game.Screens.Play;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
@ -179,16 +180,13 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
|
|
||||||
private Vector2? lastPosition;
|
private Vector2? lastPosition;
|
||||||
|
|
||||||
private bool rewinding;
|
|
||||||
|
|
||||||
public void UpdateProgress(double completionProgress)
|
public void UpdateProgress(double completionProgress)
|
||||||
{
|
{
|
||||||
Position = drawableSlider.HitObject.CurvePositionAt(completionProgress);
|
Position = drawableSlider.HitObject.CurvePositionAt(completionProgress);
|
||||||
|
|
||||||
var diff = lastPosition.HasValue ? lastPosition.Value - Position : Position - drawableSlider.HitObject.CurvePositionAt(completionProgress + 0.01f);
|
var diff = lastPosition.HasValue ? lastPosition.Value - Position : Position - drawableSlider.HitObject.CurvePositionAt(completionProgress + 0.01f);
|
||||||
|
|
||||||
if (Clock.ElapsedFrameTime != 0)
|
bool rewinding = (Clock as IGameplayClock)?.IsRewinding == true;
|
||||||
rewinding = Clock.ElapsedFrameTime < 0;
|
|
||||||
|
|
||||||
// Ensure the value is substantially high enough to allow for Atan2 to get a valid angle.
|
// Ensure the value is substantially high enough to allow for Atan2 to get a valid angle.
|
||||||
if (diff.LengthFast < 0.01f)
|
if (diff.LengthFast < 0.01f)
|
||||||
|
@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
|
|||||||
effectiveMissCount = Math.Max(1.0, 1000.0 / totalSuccessfulHits) * countMiss;
|
effectiveMissCount = Math.Max(1.0, 1000.0 / totalSuccessfulHits) * countMiss;
|
||||||
|
|
||||||
// TODO: The detection of rulesets is temporary until the leftover old skills have been reworked.
|
// TODO: The detection of rulesets is temporary until the leftover old skills have been reworked.
|
||||||
bool isConvert = score.BeatmapInfo.Ruleset.OnlineID != 1;
|
bool isConvert = score.BeatmapInfo!.Ruleset.OnlineID != 1;
|
||||||
|
|
||||||
double multiplier = 1.13;
|
double multiplier = 1.13;
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -8,6 +9,7 @@ using osu.Framework.Graphics.Animations;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Primitives;
|
using osu.Framework.Graphics.Primitives;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Taiko.Objects;
|
using osu.Game.Rulesets.Taiko.Objects;
|
||||||
@ -26,11 +28,12 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
|
|||||||
private Bindable<int> currentCombo { get; } = new BindableInt();
|
private Bindable<int> currentCombo { get; } = new BindableInt();
|
||||||
|
|
||||||
private int animationFrame;
|
private int animationFrame;
|
||||||
private double beatLength;
|
|
||||||
|
|
||||||
// required for editor blueprints (not sure why these circle pieces are zero size).
|
// required for editor blueprints (not sure why these circle pieces are zero size).
|
||||||
public override Quad ScreenSpaceDrawQuad => backgroundLayer.ScreenSpaceDrawQuad;
|
public override Quad ScreenSpaceDrawQuad => backgroundLayer.ScreenSpaceDrawQuad;
|
||||||
|
|
||||||
|
private TimingControlPoint timingPoint = TimingControlPoint.DEFAULT;
|
||||||
|
|
||||||
public LegacyCirclePiece()
|
public LegacyCirclePiece()
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
@ -39,11 +42,8 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
|
|||||||
[Resolved(canBeNull: true)]
|
[Resolved(canBeNull: true)]
|
||||||
private GameplayState? gameplayState { get; set; }
|
private GameplayState? gameplayState { get; set; }
|
||||||
|
|
||||||
[Resolved(canBeNull: true)]
|
|
||||||
private IBeatSyncProvider? beatSyncProvider { get; set; }
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(ISkinSource skin, DrawableHitObject drawableHitObject)
|
private void load(ISkinSource skin, DrawableHitObject drawableHitObject, IBeatSyncProvider? beatSyncProvider)
|
||||||
{
|
{
|
||||||
Drawable? getDrawableFor(string lookup)
|
Drawable? getDrawableFor(string lookup)
|
||||||
{
|
{
|
||||||
@ -64,6 +64,11 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
|
|||||||
if (foregroundLayer != null)
|
if (foregroundLayer != null)
|
||||||
AddInternal(foregroundLayer);
|
AddInternal(foregroundLayer);
|
||||||
|
|
||||||
|
drawableHitObject.StartTimeBindable.BindValueChanged(startTime =>
|
||||||
|
{
|
||||||
|
timingPoint = beatSyncProvider?.ControlPoints?.TimingPointAt(startTime.NewValue) ?? TimingControlPoint.DEFAULT;
|
||||||
|
}, true);
|
||||||
|
|
||||||
// Animations in taiko skins are used in a custom way (>150 combo and animating in time with beat).
|
// Animations in taiko skins are used in a custom way (>150 combo and animating in time with beat).
|
||||||
// For now just stop at first frame for sanity.
|
// For now just stop at first frame for sanity.
|
||||||
foreach (var c in InternalChildren)
|
foreach (var c in InternalChildren)
|
||||||
@ -115,14 +120,8 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (beatSyncProvider?.ControlPoints != null)
|
animationFrame = Math.Abs(Time.Current - timingPoint.Time) % ((timingPoint.BeatLength * 2) / multiplier) >= timingPoint.BeatLength / multiplier ? 0 : 1;
|
||||||
{
|
animatableForegroundLayer.GotoFrame(animationFrame);
|
||||||
beatLength = beatSyncProvider.ControlPoints.TimingPointAt(Time.Current).BeatLength;
|
|
||||||
|
|
||||||
animationFrame = Time.Current % ((beatLength * 2) / multiplier) >= beatLength / multiplier ? 0 : 1;
|
|
||||||
|
|
||||||
animatableForegroundLayer.GotoFrame(animationFrame);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Color4 accentColour;
|
private Color4 accentColour;
|
||||||
|
@ -64,7 +64,7 @@ namespace osu.Game.Tests.Beatmaps
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestCachedRetrievalWithFiles() => AddStep("run test", () =>
|
public void TestCachedRetrievalWithFiles() => AddStep("run test", () =>
|
||||||
{
|
{
|
||||||
var beatmap = Realm.Run(r => r.Find<BeatmapInfo>(importedSet.Beatmaps.First().ID).Detach());
|
var beatmap = Realm.Run(r => r.Find<BeatmapInfo>(importedSet.Beatmaps.First().ID)!.Detach());
|
||||||
|
|
||||||
Assert.That(beatmap.BeatmapSet?.Files, Has.Count.GreaterThan(0));
|
Assert.That(beatmap.BeatmapSet?.Files, Has.Count.GreaterThan(0));
|
||||||
|
|
||||||
@ -90,7 +90,7 @@ namespace osu.Game.Tests.Beatmaps
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestForcedRefetchRetrievalWithFiles() => AddStep("run test", () =>
|
public void TestForcedRefetchRetrievalWithFiles() => AddStep("run test", () =>
|
||||||
{
|
{
|
||||||
var beatmap = Realm.Run(r => r.Find<BeatmapInfo>(importedSet.Beatmaps.First().ID).Detach());
|
var beatmap = Realm.Run(r => r.Find<BeatmapInfo>(importedSet.Beatmaps.First().ID)!.Detach());
|
||||||
|
|
||||||
Assert.That(beatmap.BeatmapSet?.Files, Has.Count.GreaterThan(0));
|
Assert.That(beatmap.BeatmapSet?.Files, Has.Count.GreaterThan(0));
|
||||||
|
|
||||||
@ -102,7 +102,7 @@ namespace osu.Game.Tests.Beatmaps
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestSavePreservesCollections() => AddStep("run test", () =>
|
public void TestSavePreservesCollections() => AddStep("run test", () =>
|
||||||
{
|
{
|
||||||
var beatmap = Realm.Run(r => r.Find<BeatmapInfo>(importedSet.Beatmaps.First().ID).Detach());
|
var beatmap = Realm.Run(r => r.Find<BeatmapInfo>(importedSet.Beatmaps.First().ID)!.Detach());
|
||||||
|
|
||||||
var working = beatmaps.GetWorkingBeatmap(beatmap);
|
var working = beatmaps.GetWorkingBeatmap(beatmap);
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ namespace osu.Game.Tests.Database
|
|||||||
{
|
{
|
||||||
return Realm.Run(r =>
|
return Realm.Run(r =>
|
||||||
{
|
{
|
||||||
var beatmapSetInfo = r.Find<BeatmapSetInfo>(importedSet.ID);
|
var beatmapSetInfo = r.Find<BeatmapSetInfo>(importedSet.ID)!;
|
||||||
return beatmapSetInfo.Beatmaps.All(b => b.StarRating > 0);
|
return beatmapSetInfo.Beatmaps.All(b => b.StarRating > 0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -51,7 +51,7 @@ namespace osu.Game.Tests.Database
|
|||||||
{
|
{
|
||||||
Realm.Write(r =>
|
Realm.Write(r =>
|
||||||
{
|
{
|
||||||
var beatmapSetInfo = r.Find<BeatmapSetInfo>(importedSet.ID);
|
var beatmapSetInfo = r.Find<BeatmapSetInfo>(importedSet.ID)!;
|
||||||
foreach (var b in beatmapSetInfo.Beatmaps)
|
foreach (var b in beatmapSetInfo.Beatmaps)
|
||||||
b.StarRating = -1;
|
b.StarRating = -1;
|
||||||
});
|
});
|
||||||
@ -66,7 +66,7 @@ namespace osu.Game.Tests.Database
|
|||||||
{
|
{
|
||||||
return Realm.Run(r =>
|
return Realm.Run(r =>
|
||||||
{
|
{
|
||||||
var beatmapSetInfo = r.Find<BeatmapSetInfo>(importedSet.ID);
|
var beatmapSetInfo = r.Find<BeatmapSetInfo>(importedSet.ID)!;
|
||||||
return beatmapSetInfo.Beatmaps.All(b => b.StarRating > 0);
|
return beatmapSetInfo.Beatmaps.All(b => b.StarRating > 0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -79,7 +79,7 @@ namespace osu.Game.Tests.Database
|
|||||||
{
|
{
|
||||||
return Realm.Run(r =>
|
return Realm.Run(r =>
|
||||||
{
|
{
|
||||||
var beatmapSetInfo = r.Find<BeatmapSetInfo>(importedSet.ID);
|
var beatmapSetInfo = r.Find<BeatmapSetInfo>(importedSet.ID)!;
|
||||||
return beatmapSetInfo.Beatmaps.All(b => b.StarRating > 0);
|
return beatmapSetInfo.Beatmaps.All(b => b.StarRating > 0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -90,7 +90,7 @@ namespace osu.Game.Tests.Database
|
|||||||
{
|
{
|
||||||
Realm.Write(r =>
|
Realm.Write(r =>
|
||||||
{
|
{
|
||||||
var beatmapSetInfo = r.Find<BeatmapSetInfo>(importedSet.ID);
|
var beatmapSetInfo = r.Find<BeatmapSetInfo>(importedSet.ID)!;
|
||||||
foreach (var b in beatmapSetInfo.Beatmaps)
|
foreach (var b in beatmapSetInfo.Beatmaps)
|
||||||
b.StarRating = -1;
|
b.StarRating = -1;
|
||||||
});
|
});
|
||||||
@ -107,7 +107,7 @@ namespace osu.Game.Tests.Database
|
|||||||
{
|
{
|
||||||
return Realm.Run(r =>
|
return Realm.Run(r =>
|
||||||
{
|
{
|
||||||
var beatmapSetInfo = r.Find<BeatmapSetInfo>(importedSet.ID);
|
var beatmapSetInfo = r.Find<BeatmapSetInfo>(importedSet.ID)!;
|
||||||
return beatmapSetInfo.Beatmaps.All(b => b.StarRating == -1);
|
return beatmapSetInfo.Beatmaps.All(b => b.StarRating == -1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -118,7 +118,7 @@ namespace osu.Game.Tests.Database
|
|||||||
{
|
{
|
||||||
return Realm.Run(r =>
|
return Realm.Run(r =>
|
||||||
{
|
{
|
||||||
var beatmapSetInfo = r.Find<BeatmapSetInfo>(importedSet.ID);
|
var beatmapSetInfo = r.Find<BeatmapSetInfo>(importedSet.ID)!;
|
||||||
return beatmapSetInfo.Beatmaps.All(b => b.StarRating > 0);
|
return beatmapSetInfo.Beatmaps.All(b => b.StarRating > 0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -417,6 +417,60 @@ namespace osu.Game.Tests.Database
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestImport_Modify_Revert()
|
||||||
|
{
|
||||||
|
RunTestWithRealmAsync(async (realm, storage) =>
|
||||||
|
{
|
||||||
|
var importer = new BeatmapImporter(storage, realm);
|
||||||
|
using var store = new RealmRulesetStore(realm, storage);
|
||||||
|
|
||||||
|
var imported = await LoadOszIntoStore(importer, realm.Realm);
|
||||||
|
|
||||||
|
await createScoreForBeatmap(realm.Realm, imported.Beatmaps.First());
|
||||||
|
|
||||||
|
var score = realm.Run(r => r.All<ScoreInfo>().Single());
|
||||||
|
|
||||||
|
string originalHash = imported.Beatmaps.First().Hash;
|
||||||
|
const string modified_hash = "new_hash";
|
||||||
|
|
||||||
|
Assert.That(imported.Beatmaps.First().Scores.Single(), Is.EqualTo(score));
|
||||||
|
|
||||||
|
Assert.That(score.BeatmapHash, Is.EqualTo(originalHash));
|
||||||
|
Assert.That(score.BeatmapInfo, Is.EqualTo(imported.Beatmaps.First()));
|
||||||
|
|
||||||
|
// imitate making local changes via editor
|
||||||
|
// ReSharper disable once MethodHasAsyncOverload
|
||||||
|
realm.Write(r =>
|
||||||
|
{
|
||||||
|
BeatmapInfo beatmap = imported.Beatmaps.First();
|
||||||
|
beatmap.Hash = modified_hash;
|
||||||
|
beatmap.ResetOnlineInfo();
|
||||||
|
beatmap.UpdateLocalScores(r);
|
||||||
|
});
|
||||||
|
|
||||||
|
Assert.That(!imported.Beatmaps.First().Scores.Any());
|
||||||
|
|
||||||
|
Assert.That(score.BeatmapInfo, Is.Null);
|
||||||
|
Assert.That(score.BeatmapHash, Is.EqualTo(originalHash));
|
||||||
|
|
||||||
|
// imitate reverting the local changes made above
|
||||||
|
// ReSharper disable once MethodHasAsyncOverload
|
||||||
|
realm.Write(r =>
|
||||||
|
{
|
||||||
|
BeatmapInfo beatmap = imported.Beatmaps.First();
|
||||||
|
beatmap.Hash = originalHash;
|
||||||
|
beatmap.ResetOnlineInfo();
|
||||||
|
beatmap.UpdateLocalScores(r);
|
||||||
|
});
|
||||||
|
|
||||||
|
Assert.That(imported.Beatmaps.First().Scores.Single(), Is.EqualTo(score));
|
||||||
|
|
||||||
|
Assert.That(score.BeatmapHash, Is.EqualTo(originalHash));
|
||||||
|
Assert.That(score.BeatmapInfo, Is.EqualTo(imported.Beatmaps.First()));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestImport_ThenModifyMapWithScore_ThenImport()
|
public void TestImport_ThenModifyMapWithScore_ThenImport()
|
||||||
{
|
{
|
||||||
@ -431,19 +485,19 @@ namespace osu.Game.Tests.Database
|
|||||||
|
|
||||||
await createScoreForBeatmap(realm.Realm, imported.Beatmaps.First());
|
await createScoreForBeatmap(realm.Realm, imported.Beatmaps.First());
|
||||||
|
|
||||||
|
Assert.That(imported.Beatmaps.First().Scores.Any());
|
||||||
|
|
||||||
// imitate making local changes via editor
|
// imitate making local changes via editor
|
||||||
// ReSharper disable once MethodHasAsyncOverload
|
// ReSharper disable once MethodHasAsyncOverload
|
||||||
realm.Write(_ =>
|
realm.Write(r =>
|
||||||
{
|
{
|
||||||
BeatmapInfo beatmap = imported.Beatmaps.First();
|
BeatmapInfo beatmap = imported.Beatmaps.First();
|
||||||
beatmap.Hash = "new_hash";
|
beatmap.Hash = "new_hash";
|
||||||
beatmap.ResetOnlineInfo();
|
beatmap.ResetOnlineInfo();
|
||||||
|
beatmap.UpdateLocalScores(r);
|
||||||
});
|
});
|
||||||
|
|
||||||
// for now, making changes to a beatmap doesn't remove the backlink from the score to the beatmap.
|
Assert.That(!imported.Beatmaps.First().Scores.Any());
|
||||||
// the logic of ensuring that scores match the beatmap is upheld via comparing the hash in usages (see: https://github.com/ppy/osu/pull/22539).
|
|
||||||
// TODO: revisit when fixing https://github.com/ppy/osu/issues/24069.
|
|
||||||
Assert.That(imported.Beatmaps.First().Scores.Any());
|
|
||||||
|
|
||||||
var importedSecondTime = await importer.Import(new ImportTask(temp));
|
var importedSecondTime = await importer.Import(new ImportTask(temp));
|
||||||
|
|
||||||
@ -461,6 +515,7 @@ namespace osu.Game.Tests.Database
|
|||||||
Assert.That(importedFirstTimeBeatmap.Hash != importedSecondTimeBeatmap.Hash);
|
Assert.That(importedFirstTimeBeatmap.Hash != importedSecondTimeBeatmap.Hash);
|
||||||
Assert.That(!importedFirstTimeBeatmap.Scores.Any());
|
Assert.That(!importedFirstTimeBeatmap.Scores.Any());
|
||||||
Assert.That(importedSecondTimeBeatmap.Scores.Count() == 1);
|
Assert.That(importedSecondTimeBeatmap.Scores.Count() == 1);
|
||||||
|
Assert.That(importedSecondTimeBeatmap.Scores.Single().BeatmapInfo, Is.EqualTo(importedSecondTimeBeatmap));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,7 +323,7 @@ namespace osu.Game.Tests.Database
|
|||||||
var beatmapInfo = s.Beatmaps.First(b => b.File?.Filename != removedFilename);
|
var beatmapInfo = s.Beatmaps.First(b => b.File?.Filename != removedFilename);
|
||||||
|
|
||||||
scoreTargetBeatmapHash = beatmapInfo.Hash;
|
scoreTargetBeatmapHash = beatmapInfo.Hash;
|
||||||
s.Realm.Add(new ScoreInfo(beatmapInfo, s.Realm.All<RulesetInfo>().First(), new RealmUser()));
|
s.Realm!.Add(new ScoreInfo(beatmapInfo, s.Realm.All<RulesetInfo>().First(), new RealmUser()));
|
||||||
});
|
});
|
||||||
|
|
||||||
realm.Run(r => r.Refresh());
|
realm.Run(r => r.Refresh());
|
||||||
@ -372,7 +372,7 @@ namespace osu.Game.Tests.Database
|
|||||||
|
|
||||||
scoreTargetBeatmapHash = beatmapInfo.Hash;
|
scoreTargetBeatmapHash = beatmapInfo.Hash;
|
||||||
|
|
||||||
s.Realm.Add(new ScoreInfo(beatmapInfo, s.Realm.All<RulesetInfo>().First(), new RealmUser()));
|
s.Realm!.Add(new ScoreInfo(beatmapInfo, s.Realm.All<RulesetInfo>().First(), new RealmUser()));
|
||||||
});
|
});
|
||||||
|
|
||||||
// locally modify beatmap
|
// locally modify beatmap
|
||||||
@ -383,14 +383,14 @@ namespace osu.Game.Tests.Database
|
|||||||
|
|
||||||
beatmapInfo.Hash = new_beatmap_hash;
|
beatmapInfo.Hash = new_beatmap_hash;
|
||||||
beatmapInfo.ResetOnlineInfo();
|
beatmapInfo.ResetOnlineInfo();
|
||||||
|
beatmapInfo.UpdateLocalScores(s.Realm!);
|
||||||
});
|
});
|
||||||
|
|
||||||
realm.Run(r => r.Refresh());
|
realm.Run(r => r.Refresh());
|
||||||
|
|
||||||
// for now, making changes to a beatmap doesn't remove the backlink from the score to the beatmap.
|
// making changes to a beatmap doesn't remove the score from realm, but should disassociate the beatmap.
|
||||||
// the logic of ensuring that scores match the beatmap is upheld via comparing the hash in usages (https://github.com/ppy/osu/pull/22539).
|
|
||||||
// TODO: revisit when fixing https://github.com/ppy/osu/issues/24069.
|
|
||||||
checkCount<ScoreInfo>(realm, 1);
|
checkCount<ScoreInfo>(realm, 1);
|
||||||
|
Assert.That(realm.Run(r => r.All<ScoreInfo>().First().BeatmapInfo), Is.Null);
|
||||||
|
|
||||||
// reimport the original beatmap before local modifications
|
// reimport the original beatmap before local modifications
|
||||||
var importAfterUpdate = await importer.ImportAsUpdate(new ProgressNotification(), new ImportTask(pathOnlineCopy), importBeforeUpdate.Value);
|
var importAfterUpdate = await importer.ImportAsUpdate(new ProgressNotification(), new ImportTask(pathOnlineCopy), importBeforeUpdate.Value);
|
||||||
@ -435,7 +435,7 @@ namespace osu.Game.Tests.Database
|
|||||||
{
|
{
|
||||||
var beatmapInfo = s.Beatmaps.Last();
|
var beatmapInfo = s.Beatmaps.Last();
|
||||||
scoreTargetFilename = beatmapInfo.File?.Filename;
|
scoreTargetFilename = beatmapInfo.File?.Filename;
|
||||||
s.Realm.Add(new ScoreInfo(beatmapInfo, s.Realm.All<RulesetInfo>().First(), new RealmUser()));
|
s.Realm!.Add(new ScoreInfo(beatmapInfo, s.Realm.All<RulesetInfo>().First(), new RealmUser()));
|
||||||
});
|
});
|
||||||
|
|
||||||
realm.Run(r => r.Refresh());
|
realm.Run(r => r.Refresh());
|
||||||
@ -528,7 +528,7 @@ namespace osu.Game.Tests.Database
|
|||||||
|
|
||||||
importBeforeUpdate.PerformWrite(s =>
|
importBeforeUpdate.PerformWrite(s =>
|
||||||
{
|
{
|
||||||
var beatmapCollection = s.Realm.Add(new BeatmapCollection("test collection"));
|
var beatmapCollection = s.Realm!.Add(new BeatmapCollection("test collection"));
|
||||||
beatmapsToAddToCollection = s.Beatmaps.Count - (allOriginalBeatmapsInCollection ? 0 : 1);
|
beatmapsToAddToCollection = s.Beatmaps.Count - (allOriginalBeatmapsInCollection ? 0 : 1);
|
||||||
|
|
||||||
for (int i = 0; i < beatmapsToAddToCollection; i++)
|
for (int i = 0; i < beatmapsToAddToCollection; i++)
|
||||||
@ -543,7 +543,7 @@ namespace osu.Game.Tests.Database
|
|||||||
|
|
||||||
importAfterUpdate.PerformRead(updated =>
|
importAfterUpdate.PerformRead(updated =>
|
||||||
{
|
{
|
||||||
updated.Realm.Refresh();
|
updated.Realm!.Refresh();
|
||||||
|
|
||||||
string[] hashes = updated.Realm.All<BeatmapCollection>().Single().BeatmapMD5Hashes.ToArray();
|
string[] hashes = updated.Realm.All<BeatmapCollection>().Single().BeatmapMD5Hashes.ToArray();
|
||||||
|
|
||||||
@ -593,7 +593,7 @@ namespace osu.Game.Tests.Database
|
|||||||
|
|
||||||
importBeforeUpdate.PerformWrite(s =>
|
importBeforeUpdate.PerformWrite(s =>
|
||||||
{
|
{
|
||||||
var beatmapCollection = s.Realm.Add(new BeatmapCollection("test collection"));
|
var beatmapCollection = s.Realm!.Add(new BeatmapCollection("test collection"));
|
||||||
originalHash = s.Beatmaps.Single(b => b.DifficultyName == "Hard").MD5Hash;
|
originalHash = s.Beatmaps.Single(b => b.DifficultyName == "Hard").MD5Hash;
|
||||||
|
|
||||||
beatmapCollection.BeatmapMD5Hashes.Add(originalHash);
|
beatmapCollection.BeatmapMD5Hashes.Add(originalHash);
|
||||||
@ -607,7 +607,7 @@ namespace osu.Game.Tests.Database
|
|||||||
|
|
||||||
importAfterUpdate.PerformRead(updated =>
|
importAfterUpdate.PerformRead(updated =>
|
||||||
{
|
{
|
||||||
updated.Realm.Refresh();
|
updated.Realm!.Refresh();
|
||||||
|
|
||||||
string[] hashes = updated.Realm.All<BeatmapCollection>().Single().BeatmapMD5Hashes.ToArray();
|
string[] hashes = updated.Realm.All<BeatmapCollection>().Single().BeatmapMD5Hashes.ToArray();
|
||||||
string updatedHash = updated.Beatmaps.Single(b => b.DifficultyName == "Hard").MD5Hash;
|
string updatedHash = updated.Beatmaps.Single(b => b.DifficultyName == "Hard").MD5Hash;
|
||||||
|
@ -128,7 +128,7 @@ namespace osu.Game.Tests.Database
|
|||||||
|
|
||||||
realm.RegisterCustomSubscription(r =>
|
realm.RegisterCustomSubscription(r =>
|
||||||
{
|
{
|
||||||
var subscription = r.All<BeatmapInfo>().QueryAsyncWithNotifications((_, _, _) =>
|
var subscription = r.All<BeatmapInfo>().QueryAsyncWithNotifications((_, _) =>
|
||||||
{
|
{
|
||||||
realm.Run(_ =>
|
realm.Run(_ =>
|
||||||
{
|
{
|
||||||
|
@ -355,7 +355,7 @@ namespace osu.Game.Tests.Database
|
|||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
void gotChange(IRealmCollection<BeatmapInfo> sender, ChangeSet changes, Exception error)
|
void gotChange(IRealmCollection<BeatmapInfo> sender, ChangeSet? changes)
|
||||||
{
|
{
|
||||||
changesTriggered++;
|
changesTriggered++;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@ -54,7 +53,7 @@ namespace osu.Game.Tests.Database
|
|||||||
registration.Dispose();
|
registration.Dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
void onChanged(IRealmCollection<BeatmapSetInfo> sender, ChangeSet? changes, Exception error)
|
void onChanged(IRealmCollection<BeatmapSetInfo> sender, ChangeSet? changes)
|
||||||
{
|
{
|
||||||
lastChanges = changes;
|
lastChanges = changes;
|
||||||
|
|
||||||
@ -92,7 +91,7 @@ namespace osu.Game.Tests.Database
|
|||||||
registration.Dispose();
|
registration.Dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
void onChanged(IRealmCollection<BeatmapSetInfo> sender, ChangeSet? changes, Exception error) => lastChanges = changes;
|
void onChanged(IRealmCollection<BeatmapSetInfo> sender, ChangeSet? changes) => lastChanges = changes;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -185,7 +184,7 @@ namespace osu.Game.Tests.Database
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
void onChanged(IRealmCollection<BeatmapSetInfo> sender, ChangeSet? changes, Exception error)
|
void onChanged(IRealmCollection<BeatmapSetInfo> sender, ChangeSet? changes)
|
||||||
{
|
{
|
||||||
if (changes == null)
|
if (changes == null)
|
||||||
resolvedItems = sender;
|
resolvedItems = sender;
|
||||||
|
@ -76,12 +76,12 @@ namespace osu.Game.Tests.Database
|
|||||||
Available = true,
|
Available = true,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
Assert.That(realm.Run(r => r.Find<RulesetInfo>(rulesetShortName).Available), Is.True);
|
Assert.That(realm.Run(r => r.Find<RulesetInfo>(rulesetShortName)!.Available), Is.True);
|
||||||
|
|
||||||
// Availability is updated on construction of a RealmRulesetStore
|
// Availability is updated on construction of a RealmRulesetStore
|
||||||
var _ = new RealmRulesetStore(realm, storage);
|
var _ = new RealmRulesetStore(realm, storage);
|
||||||
|
|
||||||
Assert.That(realm.Run(r => r.Find<RulesetInfo>(rulesetShortName).Available), Is.False);
|
Assert.That(realm.Run(r => r.Find<RulesetInfo>(rulesetShortName)!.Available), Is.False);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,18 +101,18 @@ namespace osu.Game.Tests.Database
|
|||||||
Available = true,
|
Available = true,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
Assert.That(realm.Run(r => r.Find<RulesetInfo>(rulesetShortName).Available), Is.True);
|
Assert.That(realm.Run(r => r.Find<RulesetInfo>(rulesetShortName)!.Available), Is.True);
|
||||||
|
|
||||||
// Availability is updated on construction of a RealmRulesetStore
|
// Availability is updated on construction of a RealmRulesetStore
|
||||||
var _ = new RealmRulesetStore(realm, storage);
|
var _ = new RealmRulesetStore(realm, storage);
|
||||||
|
|
||||||
Assert.That(realm.Run(r => r.Find<RulesetInfo>(rulesetShortName).Available), Is.False);
|
Assert.That(realm.Run(r => r.Find<RulesetInfo>(rulesetShortName)!.Available), Is.False);
|
||||||
|
|
||||||
// Simulate the ruleset getting updated
|
// Simulate the ruleset getting updated
|
||||||
LoadTestRuleset.Version = Ruleset.CURRENT_RULESET_API_VERSION;
|
LoadTestRuleset.Version = Ruleset.CURRENT_RULESET_API_VERSION;
|
||||||
var __ = new RealmRulesetStore(realm, storage);
|
var __ = new RealmRulesetStore(realm, storage);
|
||||||
|
|
||||||
Assert.That(realm.Run(r => r.Find<RulesetInfo>(rulesetShortName).Available), Is.True);
|
Assert.That(realm.Run(r => r.Find<RulesetInfo>(rulesetShortName)!.Available), Is.True);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ namespace osu.Game.Tests.Database
|
|||||||
|
|
||||||
realm.Run(innerRealm =>
|
realm.Run(innerRealm =>
|
||||||
{
|
{
|
||||||
var binding = innerRealm.ResolveReference(tsr);
|
var binding = innerRealm.ResolveReference(tsr)!;
|
||||||
innerRealm.Write(() => binding.KeyCombination = new KeyCombination(InputKey.BackSpace));
|
innerRealm.Write(() => binding.KeyCombination = new KeyCombination(InputKey.BackSpace));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -87,10 +87,10 @@ namespace osu.Game.Tests.Models
|
|||||||
var mock = new Mock<IScoreInfo>();
|
var mock = new Mock<IScoreInfo>();
|
||||||
|
|
||||||
mock.Setup(m => m.User).Returns(new APIUser { Username = "user" }); // TODO: temporary.
|
mock.Setup(m => m.User).Returns(new APIUser { Username = "user" }); // TODO: temporary.
|
||||||
mock.Setup(m => m.Beatmap.Metadata.Artist).Returns("artist");
|
mock.Setup(m => m.Beatmap!.Metadata.Artist).Returns("artist");
|
||||||
mock.Setup(m => m.Beatmap.Metadata.Title).Returns("title");
|
mock.Setup(m => m.Beatmap!.Metadata.Title).Returns("title");
|
||||||
mock.Setup(m => m.Beatmap.Metadata.Author.Username).Returns("author");
|
mock.Setup(m => m.Beatmap!.Metadata.Author.Username).Returns("author");
|
||||||
mock.Setup(m => m.Beatmap.DifficultyName).Returns("difficulty");
|
mock.Setup(m => m.Beatmap!.DifficultyName).Returns("difficulty");
|
||||||
|
|
||||||
Assert.That(mock.Object.GetDisplayString(), Is.EqualTo("user playing artist - title (author) [difficulty]"));
|
Assert.That(mock.Object.GetDisplayString(), Is.EqualTo("user playing artist - title (author) [difficulty]"));
|
||||||
}
|
}
|
||||||
|
@ -107,7 +107,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
base.SetUpSteps();
|
base.SetUpSteps();
|
||||||
|
|
||||||
AddStep("Add trigger source", () => Player.GameplayClockContainer.Add(sampleTriggerSource = new TestGameplaySampleTriggerSource(Player.DrawableRuleset.Playfield.HitObjectContainer)));
|
AddStep("Add trigger source", () => Player.DrawableRuleset.FrameStableComponents.Add(sampleTriggerSource = new TestGameplaySampleTriggerSource(Player.DrawableRuleset.Playfield.HitObjectContainer)));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -153,6 +153,14 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
waitForAliveObjectIndex(2);
|
waitForAliveObjectIndex(2);
|
||||||
checkValidObjectIndex(2);
|
checkValidObjectIndex(2);
|
||||||
|
|
||||||
|
// test rewinding
|
||||||
|
seekBeforeIndex(1);
|
||||||
|
waitForAliveObjectIndex(1);
|
||||||
|
checkValidObjectIndex(1);
|
||||||
|
|
||||||
|
seekBeforeIndex(1, 400);
|
||||||
|
checkValidObjectIndex(0);
|
||||||
|
|
||||||
seekBeforeIndex(3);
|
seekBeforeIndex(3);
|
||||||
waitForAliveObjectIndex(3);
|
waitForAliveObjectIndex(3);
|
||||||
checkValidObjectIndex(3);
|
checkValidObjectIndex(3);
|
||||||
|
@ -131,7 +131,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
AddAssert("results screen score has matching", () => (Player.GetChildScreen() as ResultsScreen)?.Score.Mods.First(), () => Is.EqualTo(playerMods.First()));
|
AddAssert("results screen score has matching", () => (Player.GetChildScreen() as ResultsScreen)?.Score.Mods.First(), () => Is.EqualTo(playerMods.First()));
|
||||||
|
|
||||||
AddUntilStep("score in database", () => Realm.Run(r => r.Find<ScoreInfo>(Player.Score.ScoreInfo.ID) != null));
|
AddUntilStep("score in database", () => Realm.Run(r => r.Find<ScoreInfo>(Player.Score.ScoreInfo.ID) != null));
|
||||||
AddUntilStep("databased score has correct mods", () => Realm.Run(r => r.Find<ScoreInfo>(Player.Score.ScoreInfo.ID)).Mods.First(), () => Is.EqualTo(playerMods.First()));
|
AddUntilStep("databased score has correct mods", () => Realm.Run(r => r.Find<ScoreInfo>(Player.Score.ScoreInfo.ID))!.Mods.First(), () => Is.EqualTo(playerMods.First()));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -33,7 +33,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
|||||||
AddStep("show excess mods score", () =>
|
AddStep("show excess mods score", () =>
|
||||||
{
|
{
|
||||||
var score = TestResources.CreateTestScoreInfo();
|
var score = TestResources.CreateTestScoreInfo();
|
||||||
score.Mods = score.BeatmapInfo.Ruleset.CreateInstance().CreateAllMods().ToArray();
|
score.Mods = score.BeatmapInfo!.Ruleset.CreateInstance().CreateAllMods().ToArray();
|
||||||
showPanel(CreateWorkingBeatmap(CreateBeatmap(new OsuRuleset().RulesetInfo)), score);
|
showPanel(CreateWorkingBeatmap(CreateBeatmap(new OsuRuleset().RulesetInfo)), score);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
|||||||
var author = new RealmUser { Username = "mapper_name" };
|
var author = new RealmUser { Username = "mapper_name" };
|
||||||
|
|
||||||
var score = TestResources.CreateTestScoreInfo(createTestBeatmap(author));
|
var score = TestResources.CreateTestScoreInfo(createTestBeatmap(author));
|
||||||
score.Mods = score.BeatmapInfo.Ruleset.CreateInstance().CreateAllMods().ToArray();
|
score.Mods = score.BeatmapInfo!.Ruleset.CreateInstance().CreateAllMods().ToArray();
|
||||||
|
|
||||||
showPanel(score);
|
showPanel(score);
|
||||||
});
|
});
|
||||||
|
@ -405,7 +405,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
|||||||
public UnrankedSoloResultsScreen(ScoreInfo score)
|
public UnrankedSoloResultsScreen(ScoreInfo score)
|
||||||
: base(score, true)
|
: base(score, true)
|
||||||
{
|
{
|
||||||
Score.BeatmapInfo.OnlineID = 0;
|
Score.BeatmapInfo!.OnlineID = 0;
|
||||||
Score.BeatmapInfo.Status = BeatmapOnlineStatus.Pending;
|
Score.BeatmapInfo.Status = BeatmapOnlineStatus.Pending;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,7 +163,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
InputManager.Key(Key.Enter);
|
InputManager.Key(Key.Enter);
|
||||||
});
|
});
|
||||||
|
|
||||||
AddUntilStep("wait for not current", () => !songSelect!.IsCurrentScreen());
|
waitForDismissed();
|
||||||
AddAssert("ensure selection changed", () => selected != Beatmap.Value);
|
AddAssert("ensure selection changed", () => selected != Beatmap.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,7 +186,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
InputManager.Key(Key.Down);
|
InputManager.Key(Key.Down);
|
||||||
});
|
});
|
||||||
|
|
||||||
AddUntilStep("wait for not current", () => !songSelect!.IsCurrentScreen());
|
waitForDismissed();
|
||||||
AddAssert("ensure selection didn't change", () => selected == Beatmap.Value);
|
AddAssert("ensure selection didn't change", () => selected == Beatmap.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,7 +215,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
InputManager.Key(Key.Enter);
|
InputManager.Key(Key.Enter);
|
||||||
});
|
});
|
||||||
|
|
||||||
AddUntilStep("wait for not current", () => !songSelect!.IsCurrentScreen());
|
waitForDismissed();
|
||||||
AddAssert("ensure selection changed", () => selected != Beatmap.Value);
|
AddAssert("ensure selection changed", () => selected != Beatmap.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,7 +244,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
InputManager.ReleaseButton(MouseButton.Left);
|
InputManager.ReleaseButton(MouseButton.Left);
|
||||||
});
|
});
|
||||||
|
|
||||||
AddUntilStep("wait for not current", () => !songSelect!.IsCurrentScreen());
|
waitForDismissed();
|
||||||
AddAssert("ensure selection didn't change", () => selected == Beatmap.Value);
|
AddAssert("ensure selection didn't change", () => selected == Beatmap.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,7 +257,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
createSongSelect();
|
createSongSelect();
|
||||||
|
|
||||||
AddStep("push child screen", () => Stack.Push(new TestSceneOsuScreenStack.TestScreen("test child")));
|
AddStep("push child screen", () => Stack.Push(new TestSceneOsuScreenStack.TestScreen("test child")));
|
||||||
AddUntilStep("wait for not current", () => !songSelect!.IsCurrentScreen());
|
waitForDismissed();
|
||||||
|
|
||||||
AddStep("return", () => songSelect!.MakeCurrent());
|
AddStep("return", () => songSelect!.MakeCurrent());
|
||||||
AddUntilStep("wait for current", () => songSelect!.IsCurrentScreen());
|
AddUntilStep("wait for current", () => songSelect!.IsCurrentScreen());
|
||||||
@ -275,7 +275,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
createSongSelect();
|
createSongSelect();
|
||||||
|
|
||||||
AddStep("push child screen", () => Stack.Push(new TestSceneOsuScreenStack.TestScreen("test child")));
|
AddStep("push child screen", () => Stack.Push(new TestSceneOsuScreenStack.TestScreen("test child")));
|
||||||
AddUntilStep("wait for not current", () => !songSelect!.IsCurrentScreen());
|
waitForDismissed();
|
||||||
|
|
||||||
AddStep("change convert setting", () => config.SetValue(OsuSetting.ShowConvertedBeatmaps, true));
|
AddStep("change convert setting", () => config.SetValue(OsuSetting.ShowConvertedBeatmaps, true));
|
||||||
|
|
||||||
@ -292,7 +292,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
createSongSelect();
|
createSongSelect();
|
||||||
|
|
||||||
AddStep("push child screen", () => Stack.Push(new TestSceneOsuScreenStack.TestScreen("test child")));
|
AddStep("push child screen", () => Stack.Push(new TestSceneOsuScreenStack.TestScreen("test child")));
|
||||||
AddUntilStep("wait for not current", () => !songSelect!.IsCurrentScreen());
|
waitForDismissed();
|
||||||
|
|
||||||
AddStep("update beatmap", () =>
|
AddStep("update beatmap", () =>
|
||||||
{
|
{
|
||||||
@ -1011,7 +1011,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
AddUntilStep("wait for results screen presented", () => !songSelect!.IsCurrentScreen());
|
waitForDismissed();
|
||||||
|
|
||||||
AddAssert("check beatmap is correct for score", () => Beatmap.Value.BeatmapInfo.MatchesOnlineID(getPresentBeatmap()));
|
AddAssert("check beatmap is correct for score", () => Beatmap.Value.BeatmapInfo.MatchesOnlineID(getPresentBeatmap()));
|
||||||
AddAssert("check ruleset is correct for score", () => Ruleset.Value.OnlineID == 0);
|
AddAssert("check ruleset is correct for score", () => Ruleset.Value.OnlineID == 0);
|
||||||
@ -1040,7 +1040,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
songSelect!.PresentScore(TestResources.CreateTestScoreInfo(getPresentBeatmap()));
|
songSelect!.PresentScore(TestResources.CreateTestScoreInfo(getPresentBeatmap()));
|
||||||
});
|
});
|
||||||
|
|
||||||
AddUntilStep("wait for results screen presented", () => !songSelect!.IsCurrentScreen());
|
waitForDismissed();
|
||||||
|
|
||||||
AddAssert("check beatmap is correct for score", () => Beatmap.Value.BeatmapInfo.MatchesOnlineID(getPresentBeatmap()));
|
AddAssert("check beatmap is correct for score", () => Beatmap.Value.BeatmapInfo.MatchesOnlineID(getPresentBeatmap()));
|
||||||
AddAssert("check ruleset is correct for score", () => Ruleset.Value.OnlineID == 0);
|
AddAssert("check ruleset is correct for score", () => Ruleset.Value.OnlineID == 0);
|
||||||
@ -1161,6 +1161,8 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
rulesets.Dispose();
|
rulesets.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void waitForDismissed() => AddUntilStep("wait for not current", () => !songSelect.AsNonNull().IsCurrentScreen());
|
||||||
|
|
||||||
private partial class TestSongSelect : PlaySongSelect
|
private partial class TestSongSelect : PlaySongSelect
|
||||||
{
|
{
|
||||||
public Action? StartRequested;
|
public Action? StartRequested;
|
||||||
|
@ -73,7 +73,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
|
|
||||||
var testPresets = createTestPresets();
|
var testPresets = createTestPresets();
|
||||||
foreach (var preset in testPresets)
|
foreach (var preset in testPresets)
|
||||||
preset.Ruleset = realm.Find<RulesetInfo>(preset.Ruleset.ShortName);
|
preset.Ruleset = realm.Find<RulesetInfo>(preset.Ruleset.ShortName)!;
|
||||||
|
|
||||||
realm.Add(testPresets);
|
realm.Add(testPresets);
|
||||||
});
|
});
|
||||||
@ -103,7 +103,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
new ManiaModNightcore(),
|
new ManiaModNightcore(),
|
||||||
new ManiaModHardRock()
|
new ManiaModHardRock()
|
||||||
},
|
},
|
||||||
Ruleset = r.Find<RulesetInfo>("mania")
|
Ruleset = r.Find<RulesetInfo>("mania")!
|
||||||
})));
|
})));
|
||||||
AddUntilStep("2 panels visible", () => this.ChildrenOfType<ModPresetPanel>().Count() == 2);
|
AddUntilStep("2 panels visible", () => this.ChildrenOfType<ModPresetPanel>().Count() == 2);
|
||||||
|
|
||||||
@ -115,7 +115,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
new OsuModHidden(),
|
new OsuModHidden(),
|
||||||
new OsuModHardRock()
|
new OsuModHardRock()
|
||||||
},
|
},
|
||||||
Ruleset = r.Find<RulesetInfo>("osu")
|
Ruleset = r.Find<RulesetInfo>("osu")!
|
||||||
})));
|
})));
|
||||||
AddUntilStep("2 panels visible", () => this.ChildrenOfType<ModPresetPanel>().Count() == 2);
|
AddUntilStep("2 panels visible", () => this.ChildrenOfType<ModPresetPanel>().Count() == 2);
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
{
|
{
|
||||||
Name = "AR0",
|
Name = "AR0",
|
||||||
Description = "Too... many... circles...",
|
Description = "Too... many... circles...",
|
||||||
Ruleset = r.Find<RulesetInfo>(OsuRuleset.SHORT_NAME),
|
Ruleset = r.Find<RulesetInfo>(OsuRuleset.SHORT_NAME)!,
|
||||||
Mods = new[]
|
Mods = new[]
|
||||||
{
|
{
|
||||||
new OsuModDifficultyAdjust
|
new OsuModDifficultyAdjust
|
||||||
@ -73,7 +73,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
{
|
{
|
||||||
Name = "Half Time 0.5x",
|
Name = "Half Time 0.5x",
|
||||||
Description = "Very slow",
|
Description = "Very slow",
|
||||||
Ruleset = r.Find<RulesetInfo>(OsuRuleset.SHORT_NAME),
|
Ruleset = r.Find<RulesetInfo>(OsuRuleset.SHORT_NAME)!,
|
||||||
Mods = new[]
|
Mods = new[]
|
||||||
{
|
{
|
||||||
new OsuModHalfTime
|
new OsuModHalfTime
|
||||||
|
@ -52,6 +52,32 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
notificationOverlay.UnreadCount.ValueChanged += count => { displayedCount.Text = $"unread count: {count.NewValue}"; };
|
notificationOverlay.UnreadCount.ValueChanged += count => { displayedCount.Text = $"unread count: {count.NewValue}"; };
|
||||||
});
|
});
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestBasicFlow()
|
||||||
|
{
|
||||||
|
setState(Visibility.Visible);
|
||||||
|
AddStep(@"simple #1", sendHelloNotification);
|
||||||
|
AddStep(@"simple #2", sendAmazingNotification);
|
||||||
|
AddStep(@"progress #1", sendUploadProgress);
|
||||||
|
AddStep(@"progress #2", sendDownloadProgress);
|
||||||
|
|
||||||
|
checkProgressingCount(2);
|
||||||
|
|
||||||
|
setState(Visibility.Hidden);
|
||||||
|
|
||||||
|
AddRepeatStep(@"add many simple", sendManyNotifications, 3);
|
||||||
|
|
||||||
|
waitForCompletion();
|
||||||
|
|
||||||
|
AddStep(@"progress #3", sendUploadProgress);
|
||||||
|
|
||||||
|
checkProgressingCount(1);
|
||||||
|
|
||||||
|
checkDisplayedCount(33);
|
||||||
|
|
||||||
|
waitForCompletion();
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestForwardWithFlingRight()
|
public void TestForwardWithFlingRight()
|
||||||
{
|
{
|
||||||
@ -411,32 +437,6 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
AddUntilStep("wait for update applied", () => applyUpdate);
|
AddUntilStep("wait for update applied", () => applyUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestBasicFlow()
|
|
||||||
{
|
|
||||||
setState(Visibility.Visible);
|
|
||||||
AddStep(@"simple #1", sendHelloNotification);
|
|
||||||
AddStep(@"simple #2", sendAmazingNotification);
|
|
||||||
AddStep(@"progress #1", sendUploadProgress);
|
|
||||||
AddStep(@"progress #2", sendDownloadProgress);
|
|
||||||
|
|
||||||
checkProgressingCount(2);
|
|
||||||
|
|
||||||
setState(Visibility.Hidden);
|
|
||||||
|
|
||||||
AddRepeatStep(@"add many simple", sendManyNotifications, 3);
|
|
||||||
|
|
||||||
waitForCompletion();
|
|
||||||
|
|
||||||
AddStep(@"progress #3", sendUploadProgress);
|
|
||||||
|
|
||||||
checkProgressingCount(1);
|
|
||||||
|
|
||||||
checkDisplayedCount(33);
|
|
||||||
|
|
||||||
waitForCompletion();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestImportantWhileClosed()
|
public void TestImportantWhileClosed()
|
||||||
{
|
{
|
||||||
|
@ -9,7 +9,6 @@ using System.Linq;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Extensions;
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
@ -94,7 +93,7 @@ namespace osu.Game.Tournament
|
|||||||
Task.Run(readBracket);
|
Task.Run(readBracket);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readBracket()
|
private async Task readBracket()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -102,7 +101,7 @@ namespace osu.Game.Tournament
|
|||||||
{
|
{
|
||||||
using (Stream stream = storage.GetStream(BRACKET_FILENAME, FileAccess.Read, FileMode.Open))
|
using (Stream stream = storage.GetStream(BRACKET_FILENAME, FileAccess.Read, FileMode.Open))
|
||||||
using (var sr = new StreamReader(stream))
|
using (var sr = new StreamReader(stream))
|
||||||
ladder = JsonConvert.DeserializeObject<LadderInfo>(sr.ReadToEnd(), new JsonPointConverter());
|
ladder = JsonConvert.DeserializeObject<LadderInfo>(await sr.ReadToEndAsync().ConfigureAwait(false), new JsonPointConverter());
|
||||||
}
|
}
|
||||||
|
|
||||||
ladder ??= new LadderInfo();
|
ladder ??= new LadderInfo();
|
||||||
@ -166,8 +165,8 @@ namespace osu.Game.Tournament
|
|||||||
}
|
}
|
||||||
|
|
||||||
addedInfo |= addPlayers();
|
addedInfo |= addPlayers();
|
||||||
addedInfo |= addRoundBeatmaps();
|
addedInfo |= await addRoundBeatmaps().ConfigureAwait(false);
|
||||||
addedInfo |= addSeedingBeatmaps();
|
addedInfo |= await addSeedingBeatmaps().ConfigureAwait(false);
|
||||||
|
|
||||||
if (addedInfo)
|
if (addedInfo)
|
||||||
saveChanges();
|
saveChanges();
|
||||||
@ -233,7 +232,7 @@ namespace osu.Game.Tournament
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Add missing beatmap info based on beatmap IDs
|
/// Add missing beatmap info based on beatmap IDs
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private bool addRoundBeatmaps()
|
private async Task<bool> addRoundBeatmaps()
|
||||||
{
|
{
|
||||||
var beatmapsRequiringPopulation = ladder.Rounds
|
var beatmapsRequiringPopulation = ladder.Rounds
|
||||||
.SelectMany(r => r.Beatmaps)
|
.SelectMany(r => r.Beatmaps)
|
||||||
@ -246,7 +245,7 @@ namespace osu.Game.Tournament
|
|||||||
{
|
{
|
||||||
var b = beatmapsRequiringPopulation[i];
|
var b = beatmapsRequiringPopulation[i];
|
||||||
|
|
||||||
b.Beatmap = new TournamentBeatmap(beatmapCache.GetBeatmapAsync(b.ID).GetResultSafely() ?? new APIBeatmap());
|
b.Beatmap = new TournamentBeatmap(await beatmapCache.GetBeatmapAsync(b.ID).ConfigureAwait(false) ?? new APIBeatmap());
|
||||||
|
|
||||||
updateLoadProgressMessage($"Populating round beatmaps ({i} / {beatmapsRequiringPopulation.Count})");
|
updateLoadProgressMessage($"Populating round beatmaps ({i} / {beatmapsRequiringPopulation.Count})");
|
||||||
}
|
}
|
||||||
@ -257,7 +256,7 @@ namespace osu.Game.Tournament
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Add missing beatmap info based on beatmap IDs
|
/// Add missing beatmap info based on beatmap IDs
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private bool addSeedingBeatmaps()
|
private async Task<bool> addSeedingBeatmaps()
|
||||||
{
|
{
|
||||||
var beatmapsRequiringPopulation = ladder.Teams
|
var beatmapsRequiringPopulation = ladder.Teams
|
||||||
.SelectMany(r => r.SeedingResults)
|
.SelectMany(r => r.SeedingResults)
|
||||||
@ -271,7 +270,7 @@ namespace osu.Game.Tournament
|
|||||||
{
|
{
|
||||||
var b = beatmapsRequiringPopulation[i];
|
var b = beatmapsRequiringPopulation[i];
|
||||||
|
|
||||||
b.Beatmap = new TournamentBeatmap(beatmapCache.GetBeatmapAsync(b.ID).GetResultSafely() ?? new APIBeatmap());
|
b.Beatmap = new TournamentBeatmap(await beatmapCache.GetBeatmapAsync(b.ID).ConfigureAwait(false) ?? new APIBeatmap());
|
||||||
|
|
||||||
updateLoadProgressMessage($"Populating seeding beatmaps ({i} / {beatmapsRequiringPopulation.Count})");
|
updateLoadProgressMessage($"Populating seeding beatmaps ({i} / {beatmapsRequiringPopulation.Count})");
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,7 @@ namespace osu.Game
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r.Find<RulesetInfo>(ruleset.ShortName).LastAppliedDifficultyVersion = currentVersion;
|
r.Find<RulesetInfo>(ruleset.ShortName)!.LastAppliedDifficultyVersion = currentVersion;
|
||||||
});
|
});
|
||||||
|
|
||||||
Logger.Log($"Finished resetting {countReset} beatmap sets for {ruleset.Name}");
|
Logger.Log($"Finished resetting {countReset} beatmap sets for {ruleset.Name}");
|
||||||
@ -163,8 +163,12 @@ namespace osu.Game
|
|||||||
{
|
{
|
||||||
foreach (var score in r.All<ScoreInfo>())
|
foreach (var score in r.All<ScoreInfo>())
|
||||||
{
|
{
|
||||||
if (score.Statistics.Sum(kvp => kvp.Value) > 0 && score.MaximumStatistics.Sum(kvp => kvp.Value) == 0)
|
if (score.BeatmapInfo != null
|
||||||
|
&& score.Statistics.Sum(kvp => kvp.Value) > 0
|
||||||
|
&& score.MaximumStatistics.Sum(kvp => kvp.Value) == 0)
|
||||||
|
{
|
||||||
scoreIds.Add(score.ID);
|
scoreIds.Add(score.ID);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -184,7 +188,7 @@ namespace osu.Game
|
|||||||
// ReSharper disable once MethodHasAsyncOverload
|
// ReSharper disable once MethodHasAsyncOverload
|
||||||
realmAccess.Write(r =>
|
realmAccess.Write(r =>
|
||||||
{
|
{
|
||||||
r.Find<ScoreInfo>(id).MaximumStatisticsJson = JsonConvert.SerializeObject(score.MaximumStatistics);
|
r.Find<ScoreInfo>(id)!.MaximumStatisticsJson = JsonConvert.SerializeObject(score.MaximumStatistics);
|
||||||
});
|
});
|
||||||
|
|
||||||
Logger.Log($"Populated maximum statistics for score {id}");
|
Logger.Log($"Populated maximum statistics for score {id}");
|
||||||
@ -204,7 +208,9 @@ namespace osu.Game
|
|||||||
{
|
{
|
||||||
Logger.Log("Querying for scores that need total score conversion...");
|
Logger.Log("Querying for scores that need total score conversion...");
|
||||||
|
|
||||||
HashSet<Guid> scoreIds = realmAccess.Run(r => new HashSet<Guid>(r.All<ScoreInfo>().Where(s => s.TotalScoreVersion == 30000002).AsEnumerable().Select(s => s.ID)));
|
HashSet<Guid> scoreIds = realmAccess.Run(r => new HashSet<Guid>(r.All<ScoreInfo>()
|
||||||
|
.Where(s => s.BeatmapInfo != null && s.TotalScoreVersion == 30000002)
|
||||||
|
.AsEnumerable().Select(s => s.ID)));
|
||||||
|
|
||||||
Logger.Log($"Found {scoreIds.Count} scores which require total score conversion.");
|
Logger.Log($"Found {scoreIds.Count} scores which require total score conversion.");
|
||||||
|
|
||||||
@ -237,7 +243,7 @@ namespace osu.Game
|
|||||||
// ReSharper disable once MethodHasAsyncOverload
|
// ReSharper disable once MethodHasAsyncOverload
|
||||||
realmAccess.Write(r =>
|
realmAccess.Write(r =>
|
||||||
{
|
{
|
||||||
ScoreInfo s = r.Find<ScoreInfo>(id);
|
ScoreInfo s = r.Find<ScoreInfo>(id)!;
|
||||||
s.TotalScore = newTotalScore;
|
s.TotalScore = newTotalScore;
|
||||||
s.TotalScoreVersion = LegacyScoreEncoder.LATEST_VERSION;
|
s.TotalScoreVersion = LegacyScoreEncoder.LATEST_VERSION;
|
||||||
});
|
});
|
||||||
|
@ -20,7 +20,6 @@ using osu.Game.IO;
|
|||||||
using osu.Game.IO.Archives;
|
using osu.Game.IO.Archives;
|
||||||
using osu.Game.Overlays.Notifications;
|
using osu.Game.Overlays.Notifications;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Scoring;
|
|
||||||
using Realms;
|
using Realms;
|
||||||
|
|
||||||
namespace osu.Game.Beatmaps
|
namespace osu.Game.Beatmaps
|
||||||
@ -69,7 +68,7 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
Logger.Log($"Beatmap \"{updated}\" update completed successfully", LoggingTarget.Database);
|
Logger.Log($"Beatmap \"{updated}\" update completed successfully", LoggingTarget.Database);
|
||||||
|
|
||||||
original = realm.Find<BeatmapSetInfo>(original.ID);
|
original = realm!.Find<BeatmapSetInfo>(original.ID)!;
|
||||||
|
|
||||||
// Generally the import process will do this for us if the OnlineIDs match,
|
// Generally the import process will do this for us if the OnlineIDs match,
|
||||||
// but that isn't a guarantee (ie. if the .osu file doesn't have OnlineIDs populated).
|
// but that isn't a guarantee (ie. if the .osu file doesn't have OnlineIDs populated).
|
||||||
@ -210,8 +209,7 @@ namespace osu.Game.Beatmaps
|
|||||||
// Let's reattach any matching scores that exist in the database, based on hash.
|
// Let's reattach any matching scores that exist in the database, based on hash.
|
||||||
foreach (BeatmapInfo beatmap in model.Beatmaps)
|
foreach (BeatmapInfo beatmap in model.Beatmaps)
|
||||||
{
|
{
|
||||||
foreach (var score in realm.All<ScoreInfo>().Where(score => score.BeatmapHash == beatmap.Hash))
|
beatmap.UpdateLocalScores(realm);
|
||||||
score.BeatmapInfo = beatmap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessBeatmap?.Invoke(model, parameters.Batch ? MetadataLookupScope.LocalCacheFirst : MetadataLookupScope.OnlineFirst);
|
ProcessBeatmap?.Invoke(model, parameters.Batch ? MetadataLookupScope.LocalCacheFirst : MetadataLookupScope.OnlineFirst);
|
||||||
|
@ -234,6 +234,22 @@ namespace osu.Game.Beatmaps
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Local scores are retained separate from a beatmap's lifetime, matched via <see cref="ScoreInfo.BeatmapHash"/>.
|
||||||
|
/// Therefore we need to detach / reattach scores when a beatmap is edited or imported.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="realm">A realm instance in an active write transaction.</param>
|
||||||
|
public void UpdateLocalScores(Realm realm)
|
||||||
|
{
|
||||||
|
// first disassociate any scores which are already attached and no longer valid.
|
||||||
|
foreach (var score in Scores)
|
||||||
|
score.BeatmapInfo = null;
|
||||||
|
|
||||||
|
// then attach any scores which match the new hash.
|
||||||
|
foreach (var score in realm.All<ScoreInfo>().Where(s => s.BeatmapHash == Hash))
|
||||||
|
score.BeatmapInfo = this;
|
||||||
|
}
|
||||||
|
|
||||||
IBeatmapMetadataInfo IBeatmapInfo.Metadata => Metadata;
|
IBeatmapMetadataInfo IBeatmapInfo.Metadata => Metadata;
|
||||||
IBeatmapSetInfo? IBeatmapInfo.BeatmapSet => BeatmapSet;
|
IBeatmapSetInfo? IBeatmapInfo.BeatmapSet => BeatmapSet;
|
||||||
IRulesetInfo IBeatmapInfo.Ruleset => Ruleset;
|
IRulesetInfo IBeatmapInfo.Ruleset => Ruleset;
|
||||||
|
@ -208,7 +208,7 @@ namespace osu.Game.Beatmaps
|
|||||||
using (var transaction = r.BeginWrite())
|
using (var transaction = r.BeginWrite())
|
||||||
{
|
{
|
||||||
if (!beatmapInfo.IsManaged)
|
if (!beatmapInfo.IsManaged)
|
||||||
beatmapInfo = r.Find<BeatmapInfo>(beatmapInfo.ID);
|
beatmapInfo = r.Find<BeatmapInfo>(beatmapInfo.ID)!;
|
||||||
|
|
||||||
beatmapInfo.Hidden = true;
|
beatmapInfo.Hidden = true;
|
||||||
transaction.Commit();
|
transaction.Commit();
|
||||||
@ -227,7 +227,7 @@ namespace osu.Game.Beatmaps
|
|||||||
using (var transaction = r.BeginWrite())
|
using (var transaction = r.BeginWrite())
|
||||||
{
|
{
|
||||||
if (!beatmapInfo.IsManaged)
|
if (!beatmapInfo.IsManaged)
|
||||||
beatmapInfo = r.Find<BeatmapInfo>(beatmapInfo.ID);
|
beatmapInfo = r.Find<BeatmapInfo>(beatmapInfo.ID)!;
|
||||||
|
|
||||||
beatmapInfo.Hidden = false;
|
beatmapInfo.Hidden = false;
|
||||||
transaction.Commit();
|
transaction.Commit();
|
||||||
@ -330,7 +330,7 @@ namespace osu.Game.Beatmaps
|
|||||||
Realm.Write(r =>
|
Realm.Write(r =>
|
||||||
{
|
{
|
||||||
if (!beatmapInfo.IsManaged)
|
if (!beatmapInfo.IsManaged)
|
||||||
beatmapInfo = r.Find<BeatmapInfo>(beatmapInfo.ID);
|
beatmapInfo = r.Find<BeatmapInfo>(beatmapInfo.ID)!;
|
||||||
|
|
||||||
Debug.Assert(beatmapInfo.BeatmapSet != null);
|
Debug.Assert(beatmapInfo.BeatmapSet != null);
|
||||||
Debug.Assert(beatmapInfo.File != null);
|
Debug.Assert(beatmapInfo.File != null);
|
||||||
@ -460,13 +460,16 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
Realm.Write(r =>
|
Realm.Write(r =>
|
||||||
{
|
{
|
||||||
var liveBeatmapSet = r.Find<BeatmapSetInfo>(setInfo.ID);
|
var liveBeatmapSet = r.Find<BeatmapSetInfo>(setInfo.ID)!;
|
||||||
|
|
||||||
setInfo.CopyChangesToRealm(liveBeatmapSet);
|
setInfo.CopyChangesToRealm(liveBeatmapSet);
|
||||||
|
|
||||||
if (transferCollections)
|
if (transferCollections)
|
||||||
beatmapInfo.TransferCollectionReferences(r, oldMd5Hash);
|
beatmapInfo.TransferCollectionReferences(r, oldMd5Hash);
|
||||||
|
|
||||||
|
liveBeatmapSet.Beatmaps.Single(b => b.ID == beatmapInfo.ID)
|
||||||
|
.UpdateLocalScores(r);
|
||||||
|
|
||||||
// do not look up metadata.
|
// do not look up metadata.
|
||||||
// this is a locally-modified set now, so looking up metadata is busy work at best and harmful at worst.
|
// this is a locally-modified set now, so looking up metadata is busy work at best and harmful at worst.
|
||||||
ProcessBeatmap?.Invoke(liveBeatmapSet, MetadataLookupScope.None);
|
ProcessBeatmap?.Invoke(liveBeatmapSet, MetadataLookupScope.None);
|
||||||
|
@ -52,7 +52,7 @@ namespace osu.Game.Beatmaps
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="beatmapSet">The managed beatmap set to update. A transaction will be opened to apply changes.</param>
|
/// <param name="beatmapSet">The managed beatmap set to update. A transaction will be opened to apply changes.</param>
|
||||||
/// <param name="lookupScope">The preferred scope to use for metadata lookup.</param>
|
/// <param name="lookupScope">The preferred scope to use for metadata lookup.</param>
|
||||||
public void Process(BeatmapSetInfo beatmapSet, MetadataLookupScope lookupScope = MetadataLookupScope.LocalCacheFirst) => beatmapSet.Realm.Write(r =>
|
public void Process(BeatmapSetInfo beatmapSet, MetadataLookupScope lookupScope = MetadataLookupScope.LocalCacheFirst) => beatmapSet.Realm!.Write(_ =>
|
||||||
{
|
{
|
||||||
// Before we use below, we want to invalidate.
|
// Before we use below, we want to invalidate.
|
||||||
workingBeatmapCache.Invalidate(beatmapSet);
|
workingBeatmapCache.Invalidate(beatmapSet);
|
||||||
|
@ -59,7 +59,7 @@ namespace osu.Game.Collections
|
|||||||
Current.BindValueChanged(selectionChanged);
|
Current.BindValueChanged(selectionChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void collectionsChanged(IRealmCollection<BeatmapCollection> collections, ChangeSet? changes, Exception error)
|
private void collectionsChanged(IRealmCollection<BeatmapCollection> collections, ChangeSet? changes)
|
||||||
{
|
{
|
||||||
var selectedItem = SelectedItem?.Value?.Collection;
|
var selectedItem = SelectedItem?.Value?.Collection;
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ namespace osu.Game.Collections
|
|||||||
realmSubscription = realm.RegisterForNotifications(r => r.All<BeatmapCollection>().OrderBy(c => c.Name), collectionsChanged);
|
realmSubscription = realm.RegisterForNotifications(r => r.All<BeatmapCollection>().OrderBy(c => c.Name), collectionsChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void collectionsChanged(IRealmCollection<BeatmapCollection> collections, ChangeSet? changes, Exception error)
|
private void collectionsChanged(IRealmCollection<BeatmapCollection> collections, ChangeSet? changes)
|
||||||
{
|
{
|
||||||
Items.Clear();
|
Items.Clear();
|
||||||
Items.AddRange(collections.AsEnumerable().Select(c => c.ToLive(realm)));
|
Items.AddRange(collections.AsEnumerable().Select(c => c.ToLive(realm)));
|
||||||
|
@ -197,7 +197,7 @@ namespace osu.Game.Collections
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void deleteCollection() => collection.PerformWrite(c => c.Realm.Remove(c));
|
private void deleteCollection() => collection.PerformWrite(c => c.Realm!.Remove(c));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -129,6 +129,7 @@ namespace osu.Game.Configuration
|
|||||||
SetDefault(OsuSetting.ShowHealthDisplayWhenCantFail, true);
|
SetDefault(OsuSetting.ShowHealthDisplayWhenCantFail, true);
|
||||||
SetDefault(OsuSetting.FadePlayfieldWhenHealthLow, true);
|
SetDefault(OsuSetting.FadePlayfieldWhenHealthLow, true);
|
||||||
SetDefault(OsuSetting.KeyOverlay, false);
|
SetDefault(OsuSetting.KeyOverlay, false);
|
||||||
|
SetDefault(OsuSetting.ReplaySettingsOverlay, true);
|
||||||
SetDefault(OsuSetting.GameplayLeaderboard, true);
|
SetDefault(OsuSetting.GameplayLeaderboard, true);
|
||||||
SetDefault(OsuSetting.AlwaysPlayFirstComboBreak, true);
|
SetDefault(OsuSetting.AlwaysPlayFirstComboBreak, true);
|
||||||
|
|
||||||
@ -382,6 +383,7 @@ namespace osu.Game.Configuration
|
|||||||
SafeAreaConsiderations,
|
SafeAreaConsiderations,
|
||||||
ComboColourNormalisationAmount,
|
ComboColourNormalisationAmount,
|
||||||
ProfileCoverExpanded,
|
ProfileCoverExpanded,
|
||||||
EditorLimitedDistanceSnap
|
EditorLimitedDistanceSnap,
|
||||||
|
ReplaySettingsOverlay
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,8 @@ namespace osu.Game.Database
|
|||||||
IEnumerator IEnumerable.GetEnumerator() => emptySet.GetEnumerator();
|
IEnumerator IEnumerable.GetEnumerator() => emptySet.GetEnumerator();
|
||||||
public int Count => emptySet.Count;
|
public int Count => emptySet.Count;
|
||||||
public T this[int index] => emptySet[index];
|
public T this[int index] => emptySet[index];
|
||||||
public int IndexOf(object item) => emptySet.IndexOf((T)item);
|
public int IndexOf(object? item) => item == null ? -1 : emptySet.IndexOf((T)item);
|
||||||
public bool Contains(object item) => emptySet.Contains((T)item);
|
public bool Contains(object? item) => item != null && emptySet.Contains((T)item);
|
||||||
|
|
||||||
public event NotifyCollectionChangedEventHandler? CollectionChanged
|
public event NotifyCollectionChangedEventHandler? CollectionChanged
|
||||||
{
|
{
|
||||||
|
@ -34,13 +34,13 @@ namespace osu.Game.Database
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void DeleteFile(TModel item, RealmNamedFileUsage file) =>
|
public void DeleteFile(TModel item, RealmNamedFileUsage file) =>
|
||||||
performFileOperation(item, managed => DeleteFile(managed, managed.Files.First(f => f.Filename == file.Filename), managed.Realm));
|
performFileOperation(item, managed => DeleteFile(managed, managed.Files.First(f => f.Filename == file.Filename), managed.Realm!));
|
||||||
|
|
||||||
public void ReplaceFile(TModel item, RealmNamedFileUsage file, Stream contents) =>
|
public void ReplaceFile(TModel item, RealmNamedFileUsage file, Stream contents) =>
|
||||||
performFileOperation(item, managed => ReplaceFile(file, contents, managed.Realm));
|
performFileOperation(item, managed => ReplaceFile(file, contents, managed.Realm!));
|
||||||
|
|
||||||
public void AddFile(TModel item, Stream contents, string filename) =>
|
public void AddFile(TModel item, Stream contents, string filename) =>
|
||||||
performFileOperation(item, managed => AddFile(managed, contents, filename, managed.Realm));
|
performFileOperation(item, managed => AddFile(managed, contents, filename, managed.Realm!));
|
||||||
|
|
||||||
private void performFileOperation(TModel item, Action<TModel> operation)
|
private void performFileOperation(TModel item, Action<TModel> operation)
|
||||||
{
|
{
|
||||||
@ -178,13 +178,14 @@ namespace osu.Game.Database
|
|||||||
// (ie. if an async import finished very recently).
|
// (ie. if an async import finished very recently).
|
||||||
return Realm.Write(realm =>
|
return Realm.Write(realm =>
|
||||||
{
|
{
|
||||||
if (!item.IsManaged)
|
TModel? processableItem = item;
|
||||||
item = realm.Find<TModel>(item.ID);
|
if (!processableItem.IsManaged)
|
||||||
|
processableItem = realm.Find<TModel>(item.ID);
|
||||||
|
|
||||||
if (item?.DeletePending != false)
|
if (processableItem?.DeletePending != false)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
item.DeletePending = true;
|
processableItem.DeletePending = true;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -195,13 +196,14 @@ namespace osu.Game.Database
|
|||||||
// (ie. if an async import finished very recently).
|
// (ie. if an async import finished very recently).
|
||||||
Realm.Write(realm =>
|
Realm.Write(realm =>
|
||||||
{
|
{
|
||||||
if (!item.IsManaged)
|
TModel? processableItem = item;
|
||||||
item = realm.Find<TModel>(item.ID);
|
if (!processableItem.IsManaged)
|
||||||
|
processableItem = realm.Find<TModel>(item.ID);
|
||||||
|
|
||||||
if (item?.DeletePending != true)
|
if (processableItem?.DeletePending != true)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
item.DeletePending = false;
|
processableItem.DeletePending = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -535,7 +535,7 @@ namespace osu.Game.Database
|
|||||||
lock (notificationsResetMap)
|
lock (notificationsResetMap)
|
||||||
{
|
{
|
||||||
// Store an action which is used when blocking to ensure consumers don't use results of a stale changeset firing.
|
// Store an action which is used when blocking to ensure consumers don't use results of a stale changeset firing.
|
||||||
notificationsResetMap.Add(action, () => callback(new EmptyRealmSet<T>(), null, null));
|
notificationsResetMap.Add(action, () => callback(new EmptyRealmSet<T>(), null));
|
||||||
}
|
}
|
||||||
|
|
||||||
return RegisterCustomSubscription(action);
|
return RegisterCustomSubscription(action);
|
||||||
@ -755,10 +755,10 @@ namespace osu.Game.Database
|
|||||||
|
|
||||||
for (int i = 0; i < itemCount; i++)
|
for (int i = 0; i < itemCount; i++)
|
||||||
{
|
{
|
||||||
dynamic? oldItem = oldItems.ElementAt(i);
|
dynamic oldItem = oldItems.ElementAt(i);
|
||||||
dynamic? newItem = newItems.ElementAt(i);
|
dynamic newItem = newItems.ElementAt(i);
|
||||||
|
|
||||||
long? nullableOnlineID = oldItem?.OnlineID;
|
long? nullableOnlineID = oldItem.OnlineID;
|
||||||
newItem.OnlineID = (int)(nullableOnlineID ?? -1);
|
newItem.OnlineID = (int)(nullableOnlineID ?? -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -795,7 +795,7 @@ namespace osu.Game.Database
|
|||||||
|
|
||||||
for (int i = 0; i < metadataCount; i++)
|
for (int i = 0; i < metadataCount; i++)
|
||||||
{
|
{
|
||||||
dynamic? oldItem = oldMetadata.ElementAt(i);
|
dynamic oldItem = oldMetadata.ElementAt(i);
|
||||||
var newItem = newMetadata.ElementAt(i);
|
var newItem = newMetadata.ElementAt(i);
|
||||||
|
|
||||||
string username = oldItem.Author;
|
string username = oldItem.Author;
|
||||||
@ -818,7 +818,7 @@ namespace osu.Game.Database
|
|||||||
|
|
||||||
for (int i = 0; i < newSettings.Count; i++)
|
for (int i = 0; i < newSettings.Count; i++)
|
||||||
{
|
{
|
||||||
dynamic? oldItem = oldSettings.ElementAt(i);
|
dynamic oldItem = oldSettings.ElementAt(i);
|
||||||
var newItem = newSettings.ElementAt(i);
|
var newItem = newSettings.ElementAt(i);
|
||||||
|
|
||||||
long rulesetId = oldItem.RulesetID;
|
long rulesetId = oldItem.RulesetID;
|
||||||
@ -843,7 +843,7 @@ namespace osu.Game.Database
|
|||||||
|
|
||||||
for (int i = 0; i < newKeyBindings.Count; i++)
|
for (int i = 0; i < newKeyBindings.Count; i++)
|
||||||
{
|
{
|
||||||
dynamic? oldItem = oldKeyBindings.ElementAt(i);
|
dynamic oldItem = oldKeyBindings.ElementAt(i);
|
||||||
var newItem = newKeyBindings.ElementAt(i);
|
var newItem = newKeyBindings.ElementAt(i);
|
||||||
|
|
||||||
if (oldItem.RulesetID == null)
|
if (oldItem.RulesetID == null)
|
||||||
@ -897,7 +897,7 @@ namespace osu.Game.Database
|
|||||||
var scores = migration.NewRealm.All<ScoreInfo>();
|
var scores = migration.NewRealm.All<ScoreInfo>();
|
||||||
|
|
||||||
foreach (var score in scores)
|
foreach (var score in scores)
|
||||||
score.BeatmapHash = score.BeatmapInfo.Hash;
|
score.BeatmapHash = score.BeatmapInfo?.Hash ?? string.Empty;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using osu.Framework.Development;
|
using osu.Framework.Development;
|
||||||
|
using osu.Framework.Extensions.ObjectExtensions;
|
||||||
using osu.Framework.Statistics;
|
using osu.Framework.Statistics;
|
||||||
using Realms;
|
using Realms;
|
||||||
|
|
||||||
@ -104,7 +105,7 @@ namespace osu.Game.Database
|
|||||||
|
|
||||||
PerformRead(t =>
|
PerformRead(t =>
|
||||||
{
|
{
|
||||||
using (var transaction = t.Realm.BeginWrite())
|
using (var transaction = t.Realm!.BeginWrite())
|
||||||
{
|
{
|
||||||
perform(t);
|
perform(t);
|
||||||
transaction.Commit();
|
transaction.Commit();
|
||||||
@ -133,7 +134,7 @@ namespace osu.Game.Database
|
|||||||
{
|
{
|
||||||
Debug.Assert(ThreadSafety.IsUpdateThread);
|
Debug.Assert(ThreadSafety.IsUpdateThread);
|
||||||
|
|
||||||
if (dataIsFromUpdateThread && !data.Realm.IsClosed)
|
if (dataIsFromUpdateThread && !data.Realm.AsNonNull().IsClosed)
|
||||||
{
|
{
|
||||||
RealmLiveStatistics.USAGE_UPDATE_IMMEDIATE.Value++;
|
RealmLiveStatistics.USAGE_UPDATE_IMMEDIATE.Value++;
|
||||||
return;
|
return;
|
||||||
@ -154,7 +155,7 @@ namespace osu.Game.Database
|
|||||||
// To ensure that behaviour matches what we'd expect (the object *is* available), force
|
// To ensure that behaviour matches what we'd expect (the object *is* available), force
|
||||||
// a refresh to bring in any off-thread changes immediately.
|
// a refresh to bring in any off-thread changes immediately.
|
||||||
realm.Refresh();
|
realm.Refresh();
|
||||||
found = realm.Find<T>(ID);
|
found = realm.Find<T>(ID)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
return found;
|
return found;
|
||||||
|
@ -43,7 +43,7 @@ namespace osu.Game.Database
|
|||||||
.ForMember(s => s.BeatmapSet, cc => cc.Ignore())
|
.ForMember(s => s.BeatmapSet, cc => cc.Ignore())
|
||||||
.AfterMap((s, d) =>
|
.AfterMap((s, d) =>
|
||||||
{
|
{
|
||||||
d.Ruleset = d.Realm.Find<RulesetInfo>(s.Ruleset.ShortName);
|
d.Ruleset = d.Realm!.Find<RulesetInfo>(s.Ruleset.ShortName)!;
|
||||||
copyChangesToRealm(s.Difficulty, d.Difficulty);
|
copyChangesToRealm(s.Difficulty, d.Difficulty);
|
||||||
copyChangesToRealm(s.Metadata, d.Metadata);
|
copyChangesToRealm(s.Metadata, d.Metadata);
|
||||||
});
|
});
|
||||||
@ -57,7 +57,7 @@ namespace osu.Game.Database
|
|||||||
// Importantly, search all of realm for the beatmap (not just the set's beatmaps).
|
// Importantly, search all of realm for the beatmap (not just the set's beatmaps).
|
||||||
// It may have gotten detached, and if that's the case let's use this opportunity to fix
|
// It may have gotten detached, and if that's the case let's use this opportunity to fix
|
||||||
// things up.
|
// things up.
|
||||||
var existingBeatmap = d.Realm.Find<BeatmapInfo>(beatmap.ID);
|
var existingBeatmap = d.Realm!.Find<BeatmapInfo>(beatmap.ID);
|
||||||
|
|
||||||
if (existingBeatmap != null)
|
if (existingBeatmap != null)
|
||||||
{
|
{
|
||||||
@ -77,7 +77,7 @@ namespace osu.Game.Database
|
|||||||
{
|
{
|
||||||
ID = beatmap.ID,
|
ID = beatmap.ID,
|
||||||
BeatmapSet = d,
|
BeatmapSet = d,
|
||||||
Ruleset = d.Realm.Find<RulesetInfo>(beatmap.Ruleset.ShortName)
|
Ruleset = d.Realm.Find<RulesetInfo>(beatmap.Ruleset.ShortName)!
|
||||||
};
|
};
|
||||||
|
|
||||||
d.Beatmaps.Add(newBeatmap);
|
d.Beatmaps.Add(newBeatmap);
|
||||||
@ -282,12 +282,10 @@ namespace osu.Game.Database
|
|||||||
/// <returns>
|
/// <returns>
|
||||||
/// A subscription token. It must be kept alive for as long as you want to receive change notifications.
|
/// A subscription token. It must be kept alive for as long as you want to receive change notifications.
|
||||||
/// To stop receiving notifications, call <see cref="M:System.IDisposable.Dispose" />.
|
/// To stop receiving notifications, call <see cref="M:System.IDisposable.Dispose" />.
|
||||||
///
|
|
||||||
/// May be null in the case the provided collection is not managed.
|
|
||||||
/// </returns>
|
/// </returns>
|
||||||
/// <seealso cref="M:Realms.CollectionExtensions.SubscribeForNotifications``1(System.Collections.Generic.IList{``0},Realms.NotificationCallbackDelegate{``0})" />
|
/// <seealso cref="M:Realms.CollectionExtensions.SubscribeForNotifications``1(System.Collections.Generic.IList{``0},Realms.NotificationCallbackDelegate{``0})" />
|
||||||
/// <seealso cref="M:Realms.CollectionExtensions.SubscribeForNotifications``1(System.Linq.IQueryable{``0},Realms.NotificationCallbackDelegate{``0})" />
|
/// <seealso cref="M:Realms.CollectionExtensions.SubscribeForNotifications``1(System.Linq.IQueryable{``0},Realms.NotificationCallbackDelegate{``0})" />
|
||||||
public static IDisposable? QueryAsyncWithNotifications<T>(this IRealmCollection<T> collection, NotificationCallbackDelegate<T> callback)
|
public static IDisposable QueryAsyncWithNotifications<T>(this IRealmCollection<T> collection, NotificationCallbackDelegate<T> callback)
|
||||||
where T : RealmObjectBase
|
where T : RealmObjectBase
|
||||||
{
|
{
|
||||||
if (!RealmAccess.CurrentThreadSubscriptionsAllowed)
|
if (!RealmAccess.CurrentThreadSubscriptionsAllowed)
|
||||||
|
@ -51,7 +51,7 @@ namespace osu.Game.Input.Bindings
|
|||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
realmSubscription = realm.RegisterForNotifications(queryRealmKeyBindings, (sender, _, _) =>
|
realmSubscription = realm.RegisterForNotifications(queryRealmKeyBindings, (sender, _) =>
|
||||||
{
|
{
|
||||||
// The first fire of this is a bit redundant as this is being called in base.LoadComplete,
|
// The first fire of this is a bit redundant as this is being called in base.LoadComplete,
|
||||||
// but this is safest in case the subscription is restored after a context recycle.
|
// but this is safest in case the subscription is restored after a context recycle.
|
||||||
|
@ -129,6 +129,7 @@ namespace osu.Game.Input.Bindings
|
|||||||
new KeyBinding(InputKey.MouseMiddle, GlobalAction.TogglePauseReplay),
|
new KeyBinding(InputKey.MouseMiddle, GlobalAction.TogglePauseReplay),
|
||||||
new KeyBinding(InputKey.Left, GlobalAction.SeekReplayBackward),
|
new KeyBinding(InputKey.Left, GlobalAction.SeekReplayBackward),
|
||||||
new KeyBinding(InputKey.Right, GlobalAction.SeekReplayForward),
|
new KeyBinding(InputKey.Right, GlobalAction.SeekReplayForward),
|
||||||
|
new KeyBinding(new[] { InputKey.Control, InputKey.H }, GlobalAction.ToggleReplaySettings),
|
||||||
};
|
};
|
||||||
|
|
||||||
public IEnumerable<KeyBinding> SongSelectKeyBindings => new[]
|
public IEnumerable<KeyBinding> SongSelectKeyBindings => new[]
|
||||||
@ -374,5 +375,8 @@ namespace osu.Game.Input.Bindings
|
|||||||
|
|
||||||
[LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ExportReplay))]
|
[LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ExportReplay))]
|
||||||
ExportReplay,
|
ExportReplay,
|
||||||
|
|
||||||
|
[LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ToggleReplaySettings))]
|
||||||
|
ToggleReplaySettings,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,10 +65,15 @@ namespace osu.Game.Localisation
|
|||||||
public static LocalisableString HUDVisibilityMode => new TranslatableString(getKey(@"hud_visibility_mode"), @"HUD overlay visibility mode");
|
public static LocalisableString HUDVisibilityMode => new TranslatableString(getKey(@"hud_visibility_mode"), @"HUD overlay visibility mode");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// "Show health display even when you can't fail"
|
/// "Show health display even when you can't fail"
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString ShowHealthDisplayWhenCantFail => new TranslatableString(getKey(@"show_health_display_when_cant_fail"), @"Show health display even when you can't fail");
|
public static LocalisableString ShowHealthDisplayWhenCantFail => new TranslatableString(getKey(@"show_health_display_when_cant_fail"), @"Show health display even when you can't fail");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Show replay settings overlay"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString ShowReplaySettingsOverlay => new TranslatableString(getKey(@"show_replay_settings_overlay"), @"Show replay settings overlay");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// "Fade playfield to red when health is low"
|
/// "Fade playfield to red when health is low"
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -134,6 +139,6 @@ namespace osu.Game.Localisation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString ClassicScoreDisplay => new TranslatableString(getKey(@"classic_score_display"), @"Classic");
|
public static LocalisableString ClassicScoreDisplay => new TranslatableString(getKey(@"classic_score_display"), @"Classic");
|
||||||
|
|
||||||
private static string getKey(string key) => $"{prefix}:{key}";
|
private static string getKey(string key) => $@"{prefix}:{key}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -324,6 +324,11 @@ namespace osu.Game.Localisation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString ToggleChatFocus => new TranslatableString(getKey(@"toggle_chat_focus"), @"Toggle chat focus");
|
public static LocalisableString ToggleChatFocus => new TranslatableString(getKey(@"toggle_chat_focus"), @"Toggle chat focus");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Toggle replay settings"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString ToggleReplaySettings => new TranslatableString(getKey(@"toggle_replay_settings"), @"Toggle replay settings");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// "Save replay"
|
/// "Save replay"
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -29,11 +29,6 @@ namespace osu.Game.Localisation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString ClearAll => new TranslatableString(getKey(@"clear_all"), @"Clear All");
|
public static LocalisableString ClearAll => new TranslatableString(getKey(@"clear_all"), @"Clear All");
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// "Cancel All"
|
|
||||||
/// </summary>
|
|
||||||
public static LocalisableString CancelAll => new TranslatableString(getKey(@"cancel_all"), @"Cancel All");
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// "Your battery level is low! Charge your device to prevent interruptions during gameplay."
|
/// "Your battery level is low! Charge your device to prevent interruptions during gameplay."
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -40,7 +40,7 @@ namespace osu.Game.Online
|
|||||||
// Used to interact with manager classes that don't support interface types. Will eventually be replaced.
|
// Used to interact with manager classes that don't support interface types. Will eventually be replaced.
|
||||||
var beatmapSetInfo = new BeatmapSetInfo { OnlineID = TrackedItem.OnlineID };
|
var beatmapSetInfo = new BeatmapSetInfo { OnlineID = TrackedItem.OnlineID };
|
||||||
|
|
||||||
realmSubscription = realm.RegisterForNotifications(r => r.All<BeatmapSetInfo>().Where(s => s.OnlineID == TrackedItem.OnlineID && !s.DeletePending), (items, _, _) =>
|
realmSubscription = realm.RegisterForNotifications(r => r.All<BeatmapSetInfo>().Where(s => s.OnlineID == TrackedItem.OnlineID && !s.DeletePending), (items, _) =>
|
||||||
{
|
{
|
||||||
if (items.Any())
|
if (items.Any())
|
||||||
Schedule(() => UpdateState(DownloadState.LocallyAvailable));
|
Schedule(() => UpdateState(DownloadState.LocallyAvailable));
|
||||||
|
@ -171,6 +171,8 @@ namespace osu.Game.Online.Chat
|
|||||||
|
|
||||||
public abstract partial class HighlightMessageNotification : SimpleNotification
|
public abstract partial class HighlightMessageNotification : SimpleNotification
|
||||||
{
|
{
|
||||||
|
public override string PopInSampleName => "UI/notification-mention";
|
||||||
|
|
||||||
protected HighlightMessageNotification(Message message, Channel channel)
|
protected HighlightMessageNotification(Message message, Channel channel)
|
||||||
{
|
{
|
||||||
this.message = message;
|
this.message = message;
|
||||||
|
@ -107,7 +107,7 @@ namespace osu.Game.Online.Rooms
|
|||||||
|
|
||||||
// handles changes to hash that didn't occur from the import process (ie. a user editing the beatmap in the editor, somehow).
|
// handles changes to hash that didn't occur from the import process (ie. a user editing the beatmap in the editor, somehow).
|
||||||
realmSubscription?.Dispose();
|
realmSubscription?.Dispose();
|
||||||
realmSubscription = realm.RegisterForNotifications(_ => filteredBeatmaps(), (_, changes, _) =>
|
realmSubscription = realm.RegisterForNotifications(_ => filteredBeatmaps(), (_, changes) =>
|
||||||
{
|
{
|
||||||
if (changes == null)
|
if (changes == null)
|
||||||
return;
|
return;
|
||||||
|
@ -48,7 +48,7 @@ namespace osu.Game.Online
|
|||||||
realmSubscription = realm.RegisterForNotifications(r => r.All<ScoreInfo>().Where(s =>
|
realmSubscription = realm.RegisterForNotifications(r => r.All<ScoreInfo>().Where(s =>
|
||||||
((s.OnlineID > 0 && s.OnlineID == TrackedItem.OnlineID)
|
((s.OnlineID > 0 && s.OnlineID == TrackedItem.OnlineID)
|
||||||
|| (!string.IsNullOrEmpty(s.Hash) && s.Hash == TrackedItem.Hash))
|
|| (!string.IsNullOrEmpty(s.Hash) && s.Hash == TrackedItem.Hash))
|
||||||
&& !s.DeletePending), (items, _, _) =>
|
&& !s.DeletePending), (items, _) =>
|
||||||
{
|
{
|
||||||
if (items.Any())
|
if (items.Any())
|
||||||
Schedule(() => UpdateState(DownloadState.LocallyAvailable));
|
Schedule(() => UpdateState(DownloadState.LocallyAvailable));
|
||||||
|
@ -185,7 +185,7 @@ namespace osu.Game.Online.Spectator
|
|||||||
IsPlaying = true;
|
IsPlaying = true;
|
||||||
|
|
||||||
// transfer state at point of beginning play
|
// transfer state at point of beginning play
|
||||||
currentState.BeatmapID = score.ScoreInfo.BeatmapInfo.OnlineID;
|
currentState.BeatmapID = score.ScoreInfo.BeatmapInfo!.OnlineID;
|
||||||
currentState.RulesetID = score.ScoreInfo.RulesetID;
|
currentState.RulesetID = score.ScoreInfo.RulesetID;
|
||||||
currentState.Mods = score.ScoreInfo.Mods.Select(m => new APIMod(m)).ToArray();
|
currentState.Mods = score.ScoreInfo.Mods.Select(m => new APIMod(m)).ToArray();
|
||||||
currentState.State = SpectatedUserState.Playing;
|
currentState.State = SpectatedUserState.Playing;
|
||||||
|
@ -289,9 +289,9 @@ namespace osu.Game
|
|||||||
{
|
{
|
||||||
base.SetHost(host);
|
base.SetHost(host);
|
||||||
|
|
||||||
if (host.Window is SDL2Window sdlWindow)
|
if (host.Window != null)
|
||||||
{
|
{
|
||||||
sdlWindow.DragDrop += path =>
|
host.Window.DragDrop += path =>
|
||||||
{
|
{
|
||||||
// on macOS/iOS, URL associations are handled via SDL_DROPFILE events.
|
// on macOS/iOS, URL associations are handled via SDL_DROPFILE events.
|
||||||
if (path.StartsWith(OSU_PROTOCOL, StringComparison.Ordinal))
|
if (path.StartsWith(OSU_PROTOCOL, StringComparison.Ordinal))
|
||||||
|
@ -163,7 +163,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
|||||||
},
|
},
|
||||||
username,
|
username,
|
||||||
#pragma warning disable 618
|
#pragma warning disable 618
|
||||||
new StatisticText(score.MaxCombo, score.BeatmapInfo.MaxCombo, @"0\x"),
|
new StatisticText(score.MaxCombo, score.BeatmapInfo!.MaxCombo, @"0\x"),
|
||||||
#pragma warning restore 618
|
#pragma warning restore 618
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -123,7 +123,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
|||||||
accuracyColumn.Text = value.DisplayAccuracy;
|
accuracyColumn.Text = value.DisplayAccuracy;
|
||||||
maxComboColumn.Text = value.MaxCombo.ToLocalisableString(@"0\x");
|
maxComboColumn.Text = value.MaxCombo.ToLocalisableString(@"0\x");
|
||||||
|
|
||||||
ppColumn.Alpha = value.BeatmapInfo.Status.GrantsPerformancePoints() ? 1 : 0;
|
ppColumn.Alpha = value.BeatmapInfo!.Status.GrantsPerformancePoints() ? 1 : 0;
|
||||||
|
|
||||||
if (value.PP is double pp)
|
if (value.PP is double pp)
|
||||||
ppColumn.Text = pp.ToLocalisableString(@"N0");
|
ppColumn.Text = pp.ToLocalisableString(@"N0");
|
||||||
|
@ -225,7 +225,12 @@ namespace osu.Game.Overlays.Dialog
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Programmatically clicks the first button of the provided type.
|
/// Programmatically clicks the first button of the provided type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void PerformAction<T>() where T : PopupDialogButton => Buttons.OfType<T>().First().TriggerClick();
|
public void PerformAction<T>() where T : PopupDialogButton
|
||||||
|
{
|
||||||
|
// Buttons are regularly added in BDL or LoadComplete, so let's schedule to ensure
|
||||||
|
// they are ready to be pressed.
|
||||||
|
Schedule(() => Buttons.OfType<T>().First().TriggerClick());
|
||||||
|
}
|
||||||
|
|
||||||
protected override bool OnKeyDown(KeyDownEvent e)
|
protected override bool OnKeyDown(KeyDownEvent e)
|
||||||
{
|
{
|
||||||
|
@ -123,7 +123,7 @@ namespace osu.Game.Overlays.FirstRunSetup
|
|||||||
beatmapSubscription?.Dispose();
|
beatmapSubscription?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void beatmapsChanged(IRealmCollection<BeatmapSetInfo> sender, ChangeSet? changes, Exception error) => Schedule(() =>
|
private void beatmapsChanged(IRealmCollection<BeatmapSetInfo> sender, ChangeSet? changes) => Schedule(() =>
|
||||||
{
|
{
|
||||||
currentlyLoadedBeatmaps.Text = FirstRunSetupBeatmapScreenStrings.CurrentlyLoadedBeatmaps(sender.Count);
|
currentlyLoadedBeatmaps.Text = FirstRunSetupBeatmapScreenStrings.CurrentlyLoadedBeatmaps(sender.Count);
|
||||||
|
|
||||||
|
@ -42,8 +42,8 @@ namespace osu.Game.Overlays
|
|||||||
IEnumerable<Notification> AllNotifications { get; }
|
IEnumerable<Notification> AllNotifications { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// All ongoing operations (ie. any <see cref="ProgressNotification"/> not in a completed state).
|
/// All ongoing operations (ie. any <see cref="ProgressNotification"/> not in a completed or cancelled state).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IEnumerable<ProgressNotification> OngoingOperations => AllNotifications.OfType<ProgressNotification>().Where(p => p.State != ProgressNotificationState.Completed && p.State != ProgressNotificationState.Cancelled);
|
public IEnumerable<ProgressNotification> OngoingOperations => AllNotifications.OfType<ProgressNotification>().Where(p => p.Ongoing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,7 @@ namespace osu.Game.Overlays.Mods
|
|||||||
Name = nameTextBox.Current.Value,
|
Name = nameTextBox.Current.Value,
|
||||||
Description = descriptionTextBox.Current.Value,
|
Description = descriptionTextBox.Current.Value,
|
||||||
Mods = selectedMods.Value.ToArray(),
|
Mods = selectedMods.Value.ToArray(),
|
||||||
Ruleset = r.Find<RulesetInfo>(ruleset.Value.ShortName)
|
Ruleset = r.Find<RulesetInfo>(ruleset.Value.ShortName)!
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this.HidePopover();
|
this.HidePopover();
|
||||||
|
@ -61,7 +61,7 @@ namespace osu.Game.Overlays.Mods
|
|||||||
private Task? latestLoadTask;
|
private Task? latestLoadTask;
|
||||||
internal bool ItemsLoaded => latestLoadTask?.IsCompleted == true;
|
internal bool ItemsLoaded => latestLoadTask?.IsCompleted == true;
|
||||||
|
|
||||||
private void asyncLoadPanels(IRealmCollection<ModPreset> presets, ChangeSet changes, Exception error)
|
private void asyncLoadPanels(IRealmCollection<ModPreset> presets, ChangeSet? changes)
|
||||||
{
|
{
|
||||||
cancellationTokenSource?.Cancel();
|
cancellationTokenSource?.Cancel();
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ namespace osu.Game.Overlays.Music
|
|||||||
beatmap.BindValueChanged(working => list.SelectedSet.Value = working.NewValue.BeatmapSetInfo.ToLive(realm), true);
|
beatmap.BindValueChanged(working => list.SelectedSet.Value = working.NewValue.BeatmapSetInfo.ToLive(realm), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void beatmapsChanged(IRealmCollection<BeatmapSetInfo> sender, ChangeSet changes, Exception error)
|
private void beatmapsChanged(IRealmCollection<BeatmapSetInfo> sender, ChangeSet changes)
|
||||||
{
|
{
|
||||||
if (changes == null)
|
if (changes == null)
|
||||||
{
|
{
|
||||||
|
@ -108,8 +108,8 @@ namespace osu.Game.Overlays
|
|||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
new NotificationSection(AccountsStrings.NotificationsTitle, new[] { typeof(SimpleNotification) }, NotificationsStrings.ClearAll),
|
new NotificationSection(AccountsStrings.NotificationsTitle, new[] { typeof(SimpleNotification) }),
|
||||||
new NotificationSection(NotificationsStrings.RunningTasks, new[] { typeof(ProgressNotification) }, NotificationsStrings.CancelAll),
|
new NotificationSection(NotificationsStrings.RunningTasks, new[] { typeof(ProgressNotification) }),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -169,7 +169,7 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
Logger.Log($"⚠️ {notification.Text}");
|
Logger.Log($"⚠️ {notification.Text}");
|
||||||
|
|
||||||
notification.Closed += notificationClosed;
|
notification.Closed += () => notificationClosed(notification);
|
||||||
|
|
||||||
if (notification is IHasCompletionTarget hasCompletionTarget)
|
if (notification is IHasCompletionTarget hasCompletionTarget)
|
||||||
hasCompletionTarget.CompletionTarget = Post;
|
hasCompletionTarget.CompletionTarget = Post;
|
||||||
@ -229,17 +229,20 @@ namespace osu.Game.Overlays
|
|||||||
mainContent.FadeEdgeEffectTo(0, WaveContainer.DISAPPEAR_DURATION, Easing.In);
|
mainContent.FadeEdgeEffectTo(0, WaveContainer.DISAPPEAR_DURATION, Easing.In);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notificationClosed() => Schedule(() =>
|
private void notificationClosed(Notification notification) => Schedule(() =>
|
||||||
{
|
{
|
||||||
updateCounts();
|
updateCounts();
|
||||||
|
|
||||||
// this debounce is currently shared between popin/popout sounds, which means one could potentially not play when the user is expecting it.
|
// this debounce is currently shared between popin/popout sounds, which means one could potentially not play when the user is expecting it.
|
||||||
// popout is constant across all notification types, and should therefore be handled using playback concurrency instead, but seems broken at the moment.
|
// popout is constant across all notification types, and should therefore be handled using playback concurrency instead, but seems broken at the moment.
|
||||||
playDebouncedSample("UI/overlay-pop-out");
|
playDebouncedSample(notification.PopOutSampleName);
|
||||||
});
|
});
|
||||||
|
|
||||||
private void playDebouncedSample(string sampleName)
|
private void playDebouncedSample(string sampleName)
|
||||||
{
|
{
|
||||||
|
if (string.IsNullOrEmpty(sampleName))
|
||||||
|
return;
|
||||||
|
|
||||||
if (lastSamplePlayback == null || Time.Current - lastSamplePlayback > OsuGameBase.SAMPLE_DEBOUNCE_TIME)
|
if (lastSamplePlayback == null || Time.Current - lastSamplePlayback > OsuGameBase.SAMPLE_DEBOUNCE_TIME)
|
||||||
{
|
{
|
||||||
audio.Samples.Get(sampleName)?.Play();
|
audio.Samples.Get(sampleName)?.Play();
|
||||||
|
@ -50,7 +50,8 @@ namespace osu.Game.Overlays.Notifications
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual bool DisplayOnTop => true;
|
public virtual bool DisplayOnTop => true;
|
||||||
|
|
||||||
public virtual string PopInSampleName => "UI/notification-pop-in";
|
public virtual string PopInSampleName => "UI/notification-default";
|
||||||
|
public virtual string PopOutSampleName => "UI/overlay-pop-out";
|
||||||
|
|
||||||
protected NotificationLight Light;
|
protected NotificationLight Light;
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ using osu.Framework.Localisation;
|
|||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Localisation;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Notifications
|
namespace osu.Game.Overlays.Notifications
|
||||||
@ -38,15 +39,12 @@ namespace osu.Game.Overlays.Notifications
|
|||||||
|
|
||||||
public IEnumerable<Type> AcceptedNotificationTypes { get; }
|
public IEnumerable<Type> AcceptedNotificationTypes { get; }
|
||||||
|
|
||||||
private readonly LocalisableString clearButtonText;
|
|
||||||
|
|
||||||
private readonly LocalisableString titleText;
|
private readonly LocalisableString titleText;
|
||||||
|
|
||||||
public NotificationSection(LocalisableString title, IEnumerable<Type> acceptedNotificationTypes, LocalisableString clearButtonText)
|
public NotificationSection(LocalisableString title, IEnumerable<Type> acceptedNotificationTypes)
|
||||||
{
|
{
|
||||||
AcceptedNotificationTypes = acceptedNotificationTypes.ToArray();
|
AcceptedNotificationTypes = acceptedNotificationTypes.ToArray();
|
||||||
|
|
||||||
this.clearButtonText = clearButtonText.ToUpper();
|
|
||||||
titleText = title;
|
titleText = title;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,7 +73,7 @@ namespace osu.Game.Overlays.Notifications
|
|||||||
{
|
{
|
||||||
new ClearAllButton
|
new ClearAllButton
|
||||||
{
|
{
|
||||||
Text = clearButtonText,
|
Text = NotificationsStrings.ClearAll.ToUpper(),
|
||||||
Anchor = Anchor.TopRight,
|
Anchor = Anchor.TopRight,
|
||||||
Origin = Anchor.TopRight,
|
Origin = Anchor.TopRight,
|
||||||
Action = clearAll
|
Action = clearAll
|
||||||
@ -115,10 +113,11 @@ namespace osu.Game.Overlays.Notifications
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clearAll()
|
private void clearAll() => notifications.Children.ForEach(c =>
|
||||||
{
|
{
|
||||||
notifications.Children.ForEach(c => c.Close(true));
|
if (c is not ProgressNotification p || !p.Ongoing)
|
||||||
}
|
c.Close(true);
|
||||||
|
});
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
|
@ -10,6 +10,8 @@ namespace osu.Game.Overlays.Notifications
|
|||||||
{
|
{
|
||||||
public partial class ProgressCompletionNotification : SimpleNotification
|
public partial class ProgressCompletionNotification : SimpleNotification
|
||||||
{
|
{
|
||||||
|
public override string PopInSampleName => "UI/notification-done";
|
||||||
|
|
||||||
public ProgressCompletionNotification()
|
public ProgressCompletionNotification()
|
||||||
{
|
{
|
||||||
Icon = FontAwesome.Solid.Check;
|
Icon = FontAwesome.Solid.Check;
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Audio;
|
||||||
|
using osu.Framework.Audio.Sample;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Colour;
|
using osu.Framework.Graphics.Colour;
|
||||||
@ -25,8 +27,15 @@ namespace osu.Game.Overlays.Notifications
|
|||||||
|
|
||||||
public Func<bool>? CancelRequested { get; set; }
|
public Func<bool>? CancelRequested { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the operation represented by the <see cref="ProgressNotification"/> is still ongoing.
|
||||||
|
/// </summary>
|
||||||
|
public bool Ongoing => State != ProgressNotificationState.Completed && State != ProgressNotificationState.Cancelled;
|
||||||
|
|
||||||
protected override bool AllowFlingDismiss => false;
|
protected override bool AllowFlingDismiss => false;
|
||||||
|
|
||||||
|
public override string PopOutSampleName => State is ProgressNotificationState.Cancelled ? base.PopOutSampleName : "";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The function to post completion notifications back to.
|
/// The function to post completion notifications back to.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -122,6 +131,7 @@ namespace osu.Game.Overlays.Notifications
|
|||||||
cancellationTokenSource.Cancel();
|
cancellationTokenSource.Cancel();
|
||||||
|
|
||||||
IconContent.FadeColour(ColourInfo.GradientVertical(Color4.Gray, Color4.Gray.Lighten(0.5f)), colour_fade_duration);
|
IconContent.FadeColour(ColourInfo.GradientVertical(Color4.Gray, Color4.Gray.Lighten(0.5f)), colour_fade_duration);
|
||||||
|
cancelSample?.Play();
|
||||||
loadingSpinner.Hide();
|
loadingSpinner.Hide();
|
||||||
|
|
||||||
var icon = new SpriteIcon
|
var icon = new SpriteIcon
|
||||||
@ -190,6 +200,8 @@ namespace osu.Game.Overlays.Notifications
|
|||||||
|
|
||||||
private LoadingSpinner loadingSpinner = null!;
|
private LoadingSpinner loadingSpinner = null!;
|
||||||
|
|
||||||
|
private Sample? cancelSample;
|
||||||
|
|
||||||
private readonly TextFlowContainer textDrawable;
|
private readonly TextFlowContainer textDrawable;
|
||||||
|
|
||||||
public ProgressNotification()
|
public ProgressNotification()
|
||||||
@ -217,7 +229,7 @@ namespace osu.Game.Overlays.Notifications
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load(OsuColour colours, AudioManager audioManager)
|
||||||
{
|
{
|
||||||
colourQueued = colours.YellowDark;
|
colourQueued = colours.YellowDark;
|
||||||
colourActive = colours.Blue;
|
colourActive = colours.Blue;
|
||||||
@ -236,6 +248,8 @@ namespace osu.Game.Overlays.Notifications
|
|||||||
Size = new Vector2(loading_spinner_size),
|
Size = new Vector2(loading_spinner_size),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
cancelSample = audioManager.Samples.Get(@"UI/notification-cancel");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Close(bool runFlingAnimation)
|
public override void Close(bool runFlingAnimation)
|
||||||
|
@ -7,7 +7,7 @@ namespace osu.Game.Overlays.Notifications
|
|||||||
{
|
{
|
||||||
public partial class SimpleErrorNotification : SimpleNotification
|
public partial class SimpleErrorNotification : SimpleNotification
|
||||||
{
|
{
|
||||||
public override string PopInSampleName => "UI/error-notification-pop-in";
|
public override string PopInSampleName => "UI/notification-error";
|
||||||
|
|
||||||
public SimpleErrorNotification()
|
public SimpleErrorNotification()
|
||||||
{
|
{
|
||||||
|
@ -25,10 +25,9 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay
|
|||||||
},
|
},
|
||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
ClassicDefault = false,
|
LabelText = GameplaySettingsStrings.ShowReplaySettingsOverlay,
|
||||||
LabelText = GameplaySettingsStrings.ShowHealthDisplayWhenCantFail,
|
Current = config.GetBindable<bool>(OsuSetting.ReplaySettingsOverlay),
|
||||||
Current = config.GetBindable<bool>(OsuSetting.ShowHealthDisplayWhenCantFail),
|
Keywords = new[] { "hide" },
|
||||||
Keywords = new[] { "hp", "bar" }
|
|
||||||
},
|
},
|
||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
@ -41,6 +40,13 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay
|
|||||||
LabelText = GameplaySettingsStrings.AlwaysShowGameplayLeaderboard,
|
LabelText = GameplaySettingsStrings.AlwaysShowGameplayLeaderboard,
|
||||||
Current = config.GetBindable<bool>(OsuSetting.GameplayLeaderboard),
|
Current = config.GetBindable<bool>(OsuSetting.GameplayLeaderboard),
|
||||||
},
|
},
|
||||||
|
new SettingsCheckbox
|
||||||
|
{
|
||||||
|
ClassicDefault = false,
|
||||||
|
LabelText = GameplaySettingsStrings.ShowHealthDisplayWhenCantFail,
|
||||||
|
Current = config.GetBindable<bool>(OsuSetting.ShowHealthDisplayWhenCantFail),
|
||||||
|
Keywords = new[] { "hp", "bar" }
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -440,7 +440,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateStoreFromButton(KeyButton button) =>
|
private void updateStoreFromButton(KeyButton button) =>
|
||||||
realm.WriteAsync(r => r.Find<RealmKeyBinding>(button.KeyBinding.ID).KeyCombinationString = button.KeyBinding.KeyCombinationString);
|
realm.WriteAsync(r => r.Find<RealmKeyBinding>(button.KeyBinding.ID)!.KeyCombinationString = button.KeyBinding.KeyCombinationString);
|
||||||
|
|
||||||
private void updateIsDefaultValue()
|
private void updateIsDefaultValue()
|
||||||
{
|
{
|
||||||
|
@ -92,7 +92,7 @@ namespace osu.Game.Overlays.Settings.Sections
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void skinsChanged(IRealmCollection<SkinInfo> sender, ChangeSet changes, Exception error)
|
private void skinsChanged(IRealmCollection<SkinInfo> sender, ChangeSet changes)
|
||||||
{
|
{
|
||||||
// This can only mean that realm is recycling, else we would see the protected skins.
|
// This can only mean that realm is recycling, else we would see the protected skins.
|
||||||
// Because we are using `Live<>` in this class, we don't need to worry about this scenario too much.
|
// Because we are using `Live<>` in this class, we don't need to worry about this scenario too much.
|
||||||
|
@ -24,6 +24,7 @@ using osu.Game.Rulesets.Objects.Pooling;
|
|||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
|
using osu.Game.Screens.Play;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
@ -688,7 +689,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
protected bool UpdateResult(bool userTriggered)
|
protected bool UpdateResult(bool userTriggered)
|
||||||
{
|
{
|
||||||
// It's possible for input to get into a bad state when rewinding gameplay, so results should not be processed
|
// It's possible for input to get into a bad state when rewinding gameplay, so results should not be processed
|
||||||
if (Time.Elapsed < 0)
|
if ((Clock as IGameplayClock)?.IsRewinding == true)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (Judged)
|
if (Judged)
|
||||||
|
@ -28,7 +28,7 @@ namespace osu.Game.Scoring
|
|||||||
|
|
||||||
double? PP { get; }
|
double? PP { get; }
|
||||||
|
|
||||||
IBeatmapInfo Beatmap { get; }
|
IBeatmapInfo? Beatmap { get; }
|
||||||
|
|
||||||
IRulesetInfo Ruleset { get; }
|
IRulesetInfo Ruleset { get; }
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ namespace osu.Game.Scoring.Legacy
|
|||||||
{
|
{
|
||||||
sw.Write((byte)(score.ScoreInfo.Ruleset.OnlineID));
|
sw.Write((byte)(score.ScoreInfo.Ruleset.OnlineID));
|
||||||
sw.Write(LATEST_VERSION);
|
sw.Write(LATEST_VERSION);
|
||||||
sw.Write(score.ScoreInfo.BeatmapInfo.MD5Hash);
|
sw.Write(score.ScoreInfo.BeatmapInfo!.MD5Hash);
|
||||||
sw.Write(score.ScoreInfo.User.Username);
|
sw.Write(score.ScoreInfo.User.Username);
|
||||||
sw.Write(FormattableString.Invariant($"lazer-{score.ScoreInfo.User.Username}-{score.ScoreInfo.Date}").ComputeMD5Hash());
|
sw.Write(FormattableString.Invariant($"lazer-{score.ScoreInfo.User.Username}-{score.ScoreInfo.Date}").ComputeMD5Hash());
|
||||||
sw.Write((ushort)(score.ScoreInfo.GetCount300() ?? 0));
|
sw.Write((ushort)(score.ScoreInfo.GetCount300() ?? 0));
|
||||||
|
@ -64,12 +64,14 @@ namespace osu.Game.Scoring
|
|||||||
|
|
||||||
protected override void Populate(ScoreInfo model, ArchiveReader? archive, Realm realm, CancellationToken cancellationToken = default)
|
protected override void Populate(ScoreInfo model, ArchiveReader? archive, Realm realm, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
|
Debug.Assert(model.BeatmapInfo != null);
|
||||||
|
|
||||||
// Ensure the beatmap is not detached.
|
// Ensure the beatmap is not detached.
|
||||||
if (!model.BeatmapInfo.IsManaged)
|
if (!model.BeatmapInfo.IsManaged)
|
||||||
model.BeatmapInfo = realm.Find<BeatmapInfo>(model.BeatmapInfo.ID);
|
model.BeatmapInfo = realm.Find<BeatmapInfo>(model.BeatmapInfo.ID)!;
|
||||||
|
|
||||||
if (!model.Ruleset.IsManaged)
|
if (!model.Ruleset.IsManaged)
|
||||||
model.Ruleset = realm.Find<RulesetInfo>(model.Ruleset.ShortName);
|
model.Ruleset = realm.Find<RulesetInfo>(model.Ruleset.ShortName)!;
|
||||||
|
|
||||||
// These properties are known to be non-null, but these final checks ensure a null hasn't come from somewhere (or the refetch has failed).
|
// These properties are known to be non-null, but these final checks ensure a null hasn't come from somewhere (or the refetch has failed).
|
||||||
// Under no circumstance do we want these to be written to realm as null.
|
// Under no circumstance do we want these to be written to realm as null.
|
||||||
@ -101,10 +103,12 @@ namespace osu.Game.Scoring
|
|||||||
/// <param name="score">The score to populate the statistics of.</param>
|
/// <param name="score">The score to populate the statistics of.</param>
|
||||||
public void PopulateMaximumStatistics(ScoreInfo score)
|
public void PopulateMaximumStatistics(ScoreInfo score)
|
||||||
{
|
{
|
||||||
|
Debug.Assert(score.BeatmapInfo != null);
|
||||||
|
|
||||||
if (score.MaximumStatistics.Select(kvp => kvp.Value).Sum() > 0)
|
if (score.MaximumStatistics.Select(kvp => kvp.Value).Sum() > 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var beatmap = score.BeatmapInfo.Detach();
|
var beatmap = score.BeatmapInfo!.Detach();
|
||||||
var ruleset = score.Ruleset.Detach();
|
var ruleset = score.Ruleset.Detach();
|
||||||
var rulesetInstance = ruleset.CreateInstance();
|
var rulesetInstance = ruleset.CreateInstance();
|
||||||
|
|
||||||
|
@ -35,9 +35,16 @@ namespace osu.Game.Scoring
|
|||||||
/// The <see cref="BeatmapInfo"/> this score was made against.
|
/// The <see cref="BeatmapInfo"/> this score was made against.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// When setting this, make sure to also set <see cref="BeatmapHash"/> to allow relational consistency when a beatmap is potentially changed.
|
/// <para>
|
||||||
|
/// This property may be <see langword="null"/> if the score was set on a beatmap (or a version of the beatmap) that is not available locally
|
||||||
|
/// e.g. due to online updates, or local modifications to the beatmap.
|
||||||
|
/// The property will only link to a <see cref="BeatmapInfo"/> if its <see cref="Beatmaps.BeatmapInfo.Hash"/> matches <see cref="BeatmapHash"/>.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// Due to the above, whenever setting this, make sure to also set <see cref="BeatmapHash"/> to allow relational consistency when a beatmap is potentially changed.
|
||||||
|
/// </para>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public BeatmapInfo BeatmapInfo { get; set; } = null!;
|
public BeatmapInfo? BeatmapInfo { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The <see cref="osu.Game.Beatmaps.BeatmapInfo.Hash"/> at the point in time when the score was set.
|
/// The <see cref="osu.Game.Beatmaps.BeatmapInfo.Hash"/> at the point in time when the score was set.
|
||||||
@ -150,14 +157,12 @@ namespace osu.Game.Scoring
|
|||||||
public int RankInt { get; set; }
|
public int RankInt { get; set; }
|
||||||
|
|
||||||
IRulesetInfo IScoreInfo.Ruleset => Ruleset;
|
IRulesetInfo IScoreInfo.Ruleset => Ruleset;
|
||||||
IBeatmapInfo IScoreInfo.Beatmap => BeatmapInfo;
|
IBeatmapInfo? IScoreInfo.Beatmap => BeatmapInfo;
|
||||||
IUser IScoreInfo.User => User;
|
IUser IScoreInfo.User => User;
|
||||||
IEnumerable<INamedFileUsage> IHasNamedFiles.Files => Files;
|
IEnumerable<INamedFileUsage> IHasNamedFiles.Files => Files;
|
||||||
|
|
||||||
#region Properties required to make things work with existing usages
|
#region Properties required to make things work with existing usages
|
||||||
|
|
||||||
public Guid BeatmapInfoID => BeatmapInfo.ID;
|
|
||||||
|
|
||||||
public int UserID => RealmUser.OnlineID;
|
public int UserID => RealmUser.OnlineID;
|
||||||
|
|
||||||
public int RulesetID => Ruleset.OnlineID;
|
public int RulesetID => Ruleset.OnlineID;
|
||||||
|
@ -13,7 +13,7 @@ namespace osu.Game.Scoring
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A user-presentable display title representing this score.
|
/// A user-presentable display title representing this score.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string GetDisplayTitle(this IScoreInfo scoreInfo) => $"{scoreInfo.User.Username} playing {scoreInfo.Beatmap.GetDisplayTitle()}";
|
public static string GetDisplayTitle(this IScoreInfo scoreInfo) => $"{scoreInfo.User.Username} playing {scoreInfo.Beatmap?.GetDisplayTitle() ?? "unknown"}";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Orders an array of <see cref="ScoreInfo"/>s by total score.
|
/// Orders an array of <see cref="ScoreInfo"/>s by total score.
|
||||||
|
@ -141,7 +141,7 @@ namespace osu.Game.Scoring
|
|||||||
{
|
{
|
||||||
Realm.Run(r =>
|
Realm.Run(r =>
|
||||||
{
|
{
|
||||||
var beatmapScores = r.Find<BeatmapInfo>(beatmap.ID).Scores.ToList();
|
var beatmapScores = r.Find<BeatmapInfo>(beatmap.ID)!.Scores.ToList();
|
||||||
Delete(beatmapScores, silent);
|
Delete(beatmapScores, silent);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ namespace osu.Game.Scoring
|
|||||||
{
|
{
|
||||||
var score = lookup.ScoreInfo;
|
var score = lookup.ScoreInfo;
|
||||||
|
|
||||||
var attributes = await difficultyCache.GetDifficultyAsync(score.BeatmapInfo, score.Ruleset, score.Mods, token).ConfigureAwait(false);
|
var attributes = await difficultyCache.GetDifficultyAsync(score.BeatmapInfo!, score.Ruleset, score.Mods, token).ConfigureAwait(false);
|
||||||
|
|
||||||
// Performance calculation requires the beatmap and ruleset to be locally available. If not, return a default value.
|
// Performance calculation requires the beatmap and ruleset to be locally available. If not, return a default value.
|
||||||
if (attributes?.Attributes == null)
|
if (attributes?.Attributes == null)
|
||||||
|
@ -53,7 +53,7 @@ namespace osu.Game.Screens.Play
|
|||||||
if (gameplayClock.CurrentTime < firstBreakTime)
|
if (gameplayClock.CurrentTime < firstBreakTime)
|
||||||
firstBreakTime = null;
|
firstBreakTime = null;
|
||||||
|
|
||||||
if (gameplayClock.ElapsedFrameTime < 0)
|
if (gameplayClock.IsRewinding)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (combo.NewValue == 0 && (combo.OldValue > 20 || (alwaysPlayFirst.Value && firstBreakTime == null)))
|
if (combo.NewValue == 0 && (combo.OldValue > 20 || (alwaysPlayFirst.Value && firstBreakTime == null)))
|
||||||
|
@ -3,10 +3,8 @@
|
|||||||
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Input.Events;
|
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osu.Game.Screens.Play.PlayerSettings;
|
using osu.Game.Screens.Play.PlayerSettings;
|
||||||
using osuTK.Input;
|
|
||||||
|
|
||||||
namespace osu.Game.Screens.Play.HUD
|
namespace osu.Game.Screens.Play.HUD
|
||||||
{
|
{
|
||||||
@ -14,16 +12,12 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
{
|
{
|
||||||
private const int fade_duration = 200;
|
private const int fade_duration = 200;
|
||||||
|
|
||||||
public bool ReplayLoaded;
|
|
||||||
|
|
||||||
public readonly PlaybackSettings PlaybackSettings;
|
public readonly PlaybackSettings PlaybackSettings;
|
||||||
|
|
||||||
public readonly VisualSettings VisualSettings;
|
public readonly VisualSettings VisualSettings;
|
||||||
|
|
||||||
public PlayerSettingsOverlay()
|
public PlayerSettingsOverlay()
|
||||||
{
|
{
|
||||||
AlwaysPresent = true;
|
|
||||||
|
|
||||||
Anchor = Anchor.TopRight;
|
Anchor = Anchor.TopRight;
|
||||||
Origin = Anchor.TopRight;
|
Origin = Anchor.TopRight;
|
||||||
AutoSizeAxes = Axes.Both;
|
AutoSizeAxes = Axes.Both;
|
||||||
@ -37,8 +31,6 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
Spacing = new Vector2(0, 20),
|
Spacing = new Vector2(0, 20),
|
||||||
Children = new PlayerSettingsGroup[]
|
Children = new PlayerSettingsGroup[]
|
||||||
{
|
{
|
||||||
//CollectionSettings = new CollectionSettings(),
|
|
||||||
//DiscussionSettings = new DiscussionSettings(),
|
|
||||||
PlaybackSettings = new PlaybackSettings { Expanded = { Value = false } },
|
PlaybackSettings = new PlaybackSettings { Expanded = { Value = false } },
|
||||||
VisualSettings = new VisualSettings { Expanded = { Value = false } },
|
VisualSettings = new VisualSettings { Expanded = { Value = false } },
|
||||||
new AudioSettings { Expanded = { Value = false } }
|
new AudioSettings { Expanded = { Value = false } }
|
||||||
@ -48,24 +40,5 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
|
|
||||||
protected override void PopIn() => this.FadeIn(fade_duration);
|
protected override void PopIn() => this.FadeIn(fade_duration);
|
||||||
protected override void PopOut() => this.FadeOut(fade_duration);
|
protected override void PopOut() => this.FadeOut(fade_duration);
|
||||||
|
|
||||||
// We want to handle keyboard inputs all the time in order to trigger ToggleVisibility() when not visible
|
|
||||||
public override bool PropagateNonPositionalInputSubTree => true;
|
|
||||||
|
|
||||||
protected override bool OnKeyDown(KeyDownEvent e)
|
|
||||||
{
|
|
||||||
if (e.Repeat) return false;
|
|
||||||
|
|
||||||
if (e.ControlPressed)
|
|
||||||
{
|
|
||||||
if (e.Key == Key.H && ReplayLoaded)
|
|
||||||
{
|
|
||||||
ToggleVisibility();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.OnKeyDown(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,6 +78,7 @@ namespace osu.Game.Screens.Play
|
|||||||
public Bindable<bool> ShowHud { get; } = new BindableBool();
|
public Bindable<bool> ShowHud { get; } = new BindableBool();
|
||||||
|
|
||||||
private Bindable<HUDVisibilityMode> configVisibilityMode;
|
private Bindable<HUDVisibilityMode> configVisibilityMode;
|
||||||
|
private Bindable<bool> configSettingsOverlay;
|
||||||
|
|
||||||
private readonly BindableBool replayLoaded = new BindableBool();
|
private readonly BindableBool replayLoaded = new BindableBool();
|
||||||
|
|
||||||
@ -178,6 +179,7 @@ namespace osu.Game.Screens.Play
|
|||||||
ModDisplay.Current.Value = mods;
|
ModDisplay.Current.Value = mods;
|
||||||
|
|
||||||
configVisibilityMode = config.GetBindable<HUDVisibilityMode>(OsuSetting.HUDVisibilityMode);
|
configVisibilityMode = config.GetBindable<HUDVisibilityMode>(OsuSetting.HUDVisibilityMode);
|
||||||
|
configSettingsOverlay = config.GetBindable<bool>(OsuSetting.ReplaySettingsOverlay);
|
||||||
|
|
||||||
if (configVisibilityMode.Value == HUDVisibilityMode.Never && !hasShownNotificationOnce)
|
if (configVisibilityMode.Value == HUDVisibilityMode.Never && !hasShownNotificationOnce)
|
||||||
{
|
{
|
||||||
@ -204,9 +206,24 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
holdingForHUD.BindValueChanged(_ => updateVisibility());
|
holdingForHUD.BindValueChanged(_ => updateVisibility());
|
||||||
IsPlaying.BindValueChanged(_ => updateVisibility());
|
IsPlaying.BindValueChanged(_ => updateVisibility());
|
||||||
configVisibilityMode.BindValueChanged(_ => updateVisibility(), true);
|
configVisibilityMode.BindValueChanged(_ => updateVisibility());
|
||||||
|
configSettingsOverlay.BindValueChanged(_ => updateVisibility());
|
||||||
|
|
||||||
replayLoaded.BindValueChanged(replayLoadedValueChanged, true);
|
replayLoaded.BindValueChanged(e =>
|
||||||
|
{
|
||||||
|
if (e.NewValue)
|
||||||
|
{
|
||||||
|
ModDisplay.FadeIn(200);
|
||||||
|
InputCountController.Margin = new MarginPadding(10) { Bottom = 30 };
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ModDisplay.Delay(2000).FadeOut(200);
|
||||||
|
InputCountController.Margin = new MarginPadding(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateVisibility();
|
||||||
|
}, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
@ -280,6 +297,11 @@ namespace osu.Game.Screens.Play
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (configSettingsOverlay.Value && replayLoaded.Value)
|
||||||
|
PlayerSettingsOverlay.Show();
|
||||||
|
else
|
||||||
|
PlayerSettingsOverlay.Hide();
|
||||||
|
|
||||||
switch (configVisibilityMode.Value)
|
switch (configVisibilityMode.Value)
|
||||||
{
|
{
|
||||||
case HUDVisibilityMode.Never:
|
case HUDVisibilityMode.Never:
|
||||||
@ -297,26 +319,6 @@ namespace osu.Game.Screens.Play
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void replayLoadedValueChanged(ValueChangedEvent<bool> e)
|
|
||||||
{
|
|
||||||
PlayerSettingsOverlay.ReplayLoaded = e.NewValue;
|
|
||||||
|
|
||||||
if (e.NewValue)
|
|
||||||
{
|
|
||||||
PlayerSettingsOverlay.Show();
|
|
||||||
ModDisplay.FadeIn(200);
|
|
||||||
InputCountController.Margin = new MarginPadding(10) { Bottom = 30 };
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PlayerSettingsOverlay.Hide();
|
|
||||||
ModDisplay.Delay(2000).FadeOut(200);
|
|
||||||
InputCountController.Margin = new MarginPadding(10);
|
|
||||||
}
|
|
||||||
|
|
||||||
updateVisibility();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void BindDrawableRuleset(DrawableRuleset drawableRuleset)
|
protected virtual void BindDrawableRuleset(DrawableRuleset drawableRuleset)
|
||||||
{
|
{
|
||||||
if (drawableRuleset is ICanAttachHUDPieces attachTarget)
|
if (drawableRuleset is ICanAttachHUDPieces attachTarget)
|
||||||
@ -354,6 +356,10 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
switch (e.Action)
|
switch (e.Action)
|
||||||
{
|
{
|
||||||
|
case GlobalAction.ToggleReplaySettings:
|
||||||
|
configSettingsOverlay.Value = !configSettingsOverlay.Value;
|
||||||
|
return true;
|
||||||
|
|
||||||
case GlobalAction.HoldForHUD:
|
case GlobalAction.HoldForHUD:
|
||||||
holdingForHUD.Value = true;
|
holdingForHUD.Value = true;
|
||||||
return true;
|
return true;
|
||||||
|
@ -11,8 +11,6 @@ using System.Threading;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Audio;
|
|
||||||
using osu.Framework.Audio.Sample;
|
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -114,8 +112,6 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
private Ruleset ruleset;
|
private Ruleset ruleset;
|
||||||
|
|
||||||
private Sample sampleRestart;
|
|
||||||
|
|
||||||
public BreakOverlay BreakOverlay;
|
public BreakOverlay BreakOverlay;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -195,7 +191,7 @@ namespace osu.Game.Screens.Play
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
private void load(AudioManager audio, OsuConfigManager config, OsuGameBase game, CancellationToken cancellationToken)
|
private void load(OsuConfigManager config, OsuGameBase game, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var gameplayMods = Mods.Value.Select(m => m.DeepClone()).ToArray();
|
var gameplayMods = Mods.Value.Select(m => m.DeepClone()).ToArray();
|
||||||
|
|
||||||
@ -213,8 +209,6 @@ namespace osu.Game.Screens.Play
|
|||||||
if (playableBeatmap == null)
|
if (playableBeatmap == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
sampleRestart = audio.Samples.Get(@"Gameplay/restart");
|
|
||||||
|
|
||||||
mouseWheelDisabled = config.GetBindable<bool>(OsuSetting.MouseDisableWheel);
|
mouseWheelDisabled = config.GetBindable<bool>(OsuSetting.MouseDisableWheel);
|
||||||
|
|
||||||
if (game != null)
|
if (game != null)
|
||||||
@ -295,14 +289,17 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
if (Configuration.AllowRestart)
|
if (Configuration.AllowRestart)
|
||||||
{
|
{
|
||||||
rulesetSkinProvider.Add(new HotkeyRetryOverlay
|
rulesetSkinProvider.AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
Action = () =>
|
new HotkeyRetryOverlay
|
||||||
{
|
{
|
||||||
if (!this.IsCurrentScreen()) return;
|
Action = () =>
|
||||||
|
{
|
||||||
|
if (!this.IsCurrentScreen()) return;
|
||||||
|
|
||||||
fadeOut(true);
|
fadeOut(true);
|
||||||
Restart(true);
|
Restart(true);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -673,7 +670,6 @@ namespace osu.Game.Screens.Play
|
|||||||
// stopping here is to ensure music doesn't become audible after exiting back to PlayerLoader.
|
// stopping here is to ensure music doesn't become audible after exiting back to PlayerLoader.
|
||||||
musicController.Stop();
|
musicController.Stop();
|
||||||
|
|
||||||
sampleRestart?.Play();
|
|
||||||
RestartRequested?.Invoke(quickRestart);
|
RestartRequested?.Invoke(quickRestart);
|
||||||
|
|
||||||
PerformExit(false);
|
PerformExit(false);
|
||||||
|
@ -15,6 +15,7 @@ using osu.Framework.Graphics.Transforms;
|
|||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Framework.Threading;
|
using osu.Framework.Threading;
|
||||||
|
using osu.Game.Audio;
|
||||||
using osu.Game.Audio.Effects;
|
using osu.Game.Audio.Effects;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
@ -25,6 +26,7 @@ using osu.Game.Overlays;
|
|||||||
using osu.Game.Overlays.Notifications;
|
using osu.Game.Overlays.Notifications;
|
||||||
using osu.Game.Screens.Menu;
|
using osu.Game.Screens.Menu;
|
||||||
using osu.Game.Screens.Play.PlayerSettings;
|
using osu.Game.Screens.Play.PlayerSettings;
|
||||||
|
using osu.Game.Skinning;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
using osu.Game.Utils;
|
using osu.Game.Utils;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
@ -76,6 +78,8 @@ namespace osu.Game.Screens.Play
|
|||||||
private AudioFilter lowPassFilter = null!;
|
private AudioFilter lowPassFilter = null!;
|
||||||
private AudioFilter highPassFilter = null!;
|
private AudioFilter highPassFilter = null!;
|
||||||
|
|
||||||
|
private SkinnableSound sampleRestart = null!;
|
||||||
|
|
||||||
[Cached]
|
[Cached]
|
||||||
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple);
|
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple);
|
||||||
|
|
||||||
@ -199,7 +203,8 @@ namespace osu.Game.Screens.Play
|
|||||||
},
|
},
|
||||||
idleTracker = new IdleTracker(750),
|
idleTracker = new IdleTracker(750),
|
||||||
lowPassFilter = new AudioFilter(audio.TrackMixer),
|
lowPassFilter = new AudioFilter(audio.TrackMixer),
|
||||||
highPassFilter = new AudioFilter(audio.TrackMixer, BQFType.HighPass)
|
highPassFilter = new AudioFilter(audio.TrackMixer, BQFType.HighPass),
|
||||||
|
sampleRestart = new SkinnableSound(new SampleInfo(@"Gameplay/restart", @"pause-retry-click"))
|
||||||
};
|
};
|
||||||
|
|
||||||
if (Beatmap.Value.BeatmapInfo.EpilepsyWarning)
|
if (Beatmap.Value.BeatmapInfo.EpilepsyWarning)
|
||||||
@ -265,6 +270,8 @@ namespace osu.Game.Screens.Play
|
|||||||
playerConsumed = false;
|
playerConsumed = false;
|
||||||
cancelLoad();
|
cancelLoad();
|
||||||
|
|
||||||
|
sampleRestart.Play();
|
||||||
|
|
||||||
contentIn();
|
contentIn();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ namespace osu.Game.Screens.Play
|
|||||||
{
|
{
|
||||||
IBeatmapInfo beatmap = score.ScoreInfo.BeatmapInfo;
|
IBeatmapInfo beatmap = score.ScoreInfo.BeatmapInfo;
|
||||||
|
|
||||||
Debug.Assert(beatmap.OnlineID > 0);
|
Debug.Assert(beatmap!.OnlineID > 0);
|
||||||
|
|
||||||
return new SubmitSoloScoreRequest(score.ScoreInfo, token, beatmap.OnlineID);
|
return new SubmitSoloScoreRequest(score.ScoreInfo, token, beatmap.OnlineID);
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,7 @@ namespace osu.Game.Screens.Ranking.Expanded
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(BeatmapDifficultyCache beatmapDifficultyCache)
|
private void load(BeatmapDifficultyCache beatmapDifficultyCache)
|
||||||
{
|
{
|
||||||
var beatmap = score.BeatmapInfo;
|
var beatmap = score.BeatmapInfo!;
|
||||||
var metadata = beatmap.BeatmapSet?.Metadata ?? beatmap.Metadata;
|
var metadata = beatmap.BeatmapSet?.Metadata ?? beatmap.Metadata;
|
||||||
string creator = metadata.Author.Username;
|
string creator = metadata.Author.Username;
|
||||||
|
|
||||||
|
@ -305,7 +305,7 @@ namespace osu.Game.Screens.Ranking
|
|||||||
float origLocation = detachedPanelContainer.ToLocalSpace(screenSpacePos).X;
|
float origLocation = detachedPanelContainer.ToLocalSpace(screenSpacePos).X;
|
||||||
expandedPanel.MoveToX(origLocation)
|
expandedPanel.MoveToX(origLocation)
|
||||||
.Then()
|
.Then()
|
||||||
.MoveToX(StatisticsPanel.SIDE_PADDING, 150, Easing.OutQuint);
|
.MoveToX(StatisticsPanel.SIDE_PADDING, 400, Easing.OutElasticQuarter);
|
||||||
|
|
||||||
// Hide contracted panels.
|
// Hide contracted panels.
|
||||||
foreach (var contracted in ScorePanelList.GetScorePanels().Where(p => p.State == PanelState.Contracted))
|
foreach (var contracted in ScorePanelList.GetScorePanels().Where(p => p.State == PanelState.Contracted))
|
||||||
@ -313,7 +313,7 @@ namespace osu.Game.Screens.Ranking
|
|||||||
ScorePanelList.HandleInput = false;
|
ScorePanelList.HandleInput = false;
|
||||||
|
|
||||||
// Dim background.
|
// Dim background.
|
||||||
ApplyToBackground(b => b.FadeColour(OsuColour.Gray(0.1f), 150));
|
ApplyToBackground(b => b.FadeColour(OsuColour.Gray(0.4f), 400, Easing.OutQuint));
|
||||||
|
|
||||||
detachedPanel = expandedPanel;
|
detachedPanel = expandedPanel;
|
||||||
}
|
}
|
||||||
@ -329,7 +329,7 @@ namespace osu.Game.Screens.Ranking
|
|||||||
float origLocation = detachedPanel.Parent.ToLocalSpace(screenSpacePos).X;
|
float origLocation = detachedPanel.Parent.ToLocalSpace(screenSpacePos).X;
|
||||||
detachedPanel.MoveToX(origLocation)
|
detachedPanel.MoveToX(origLocation)
|
||||||
.Then()
|
.Then()
|
||||||
.MoveToX(0, 150, Easing.OutQuint);
|
.MoveToX(0, 250, Easing.OutElasticQuarter);
|
||||||
|
|
||||||
// Show contracted panels.
|
// Show contracted panels.
|
||||||
foreach (var contracted in ScorePanelList.GetScorePanels().Where(p => p.State == PanelState.Contracted))
|
foreach (var contracted in ScorePanelList.GetScorePanels().Where(p => p.State == PanelState.Contracted))
|
||||||
@ -337,7 +337,7 @@ namespace osu.Game.Screens.Ranking
|
|||||||
ScorePanelList.HandleInput = true;
|
ScorePanelList.HandleInput = true;
|
||||||
|
|
||||||
// Un-dim background.
|
// Un-dim background.
|
||||||
ApplyToBackground(b => b.FadeColour(OsuColour.Gray(0.5f), 150));
|
ApplyToBackground(b => b.FadeColour(OsuColour.Gray(0.5f), 250, Easing.OutQuint));
|
||||||
|
|
||||||
detachedPanel = null;
|
detachedPanel = null;
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ namespace osu.Game.Screens.Ranking
|
|||||||
|
|
||||||
protected override APIRequest? FetchScores(Action<IEnumerable<ScoreInfo>>? scoresCallback)
|
protected override APIRequest? FetchScores(Action<IEnumerable<ScoreInfo>>? scoresCallback)
|
||||||
{
|
{
|
||||||
if (Score.BeatmapInfo.OnlineID <= 0 || Score.BeatmapInfo.Status <= BeatmapOnlineStatus.Pending)
|
if (Score.BeatmapInfo!.OnlineID <= 0 || Score.BeatmapInfo.Status <= BeatmapOnlineStatus.Pending)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
getScoreRequest = new GetScoresRequest(Score.BeatmapInfo, Score.Ruleset);
|
getScoreRequest = new GetScoresRequest(Score.BeatmapInfo, Score.Ruleset);
|
||||||
|
@ -223,7 +223,7 @@ namespace osu.Game.Screens.Ranking.Statistics
|
|||||||
|
|
||||||
protected override void PopIn()
|
protected override void PopIn()
|
||||||
{
|
{
|
||||||
this.FadeIn(150, Easing.OutQuint);
|
this.FadeIn(350, Easing.OutQuint);
|
||||||
|
|
||||||
popInSample?.Play();
|
popInSample?.Play();
|
||||||
wasOpened = true;
|
wasOpened = true;
|
||||||
@ -231,7 +231,7 @@ namespace osu.Game.Screens.Ranking.Statistics
|
|||||||
|
|
||||||
protected override void PopOut()
|
protected override void PopOut()
|
||||||
{
|
{
|
||||||
this.FadeOut(150, Easing.OutQuint);
|
this.FadeOut(250, Easing.OutQuint);
|
||||||
|
|
||||||
if (wasOpened)
|
if (wasOpened)
|
||||||
popOutSample?.Play();
|
popOutSample?.Play();
|
||||||
|
@ -223,7 +223,7 @@ namespace osu.Game.Screens.Select
|
|||||||
subscriptionHiddenBeatmaps = realm.RegisterForNotifications(r => r.All<BeatmapInfo>().Where(b => b.Hidden), beatmapsChanged);
|
subscriptionHiddenBeatmaps = realm.RegisterForNotifications(r => r.All<BeatmapInfo>().Where(b => b.Hidden), beatmapsChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void deletedBeatmapSetsChanged(IRealmCollection<BeatmapSetInfo> sender, ChangeSet? changes, Exception? error)
|
private void deletedBeatmapSetsChanged(IRealmCollection<BeatmapSetInfo> sender, ChangeSet? changes)
|
||||||
{
|
{
|
||||||
// If loading test beatmaps, avoid overwriting with realm subscription callbacks.
|
// If loading test beatmaps, avoid overwriting with realm subscription callbacks.
|
||||||
if (loadedTestBeatmaps)
|
if (loadedTestBeatmaps)
|
||||||
@ -236,7 +236,7 @@ namespace osu.Game.Screens.Select
|
|||||||
removeBeatmapSet(sender[i].ID);
|
removeBeatmapSet(sender[i].ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void beatmapSetsChanged(IRealmCollection<BeatmapSetInfo> sender, ChangeSet? changes, Exception? error)
|
private void beatmapSetsChanged(IRealmCollection<BeatmapSetInfo> sender, ChangeSet? changes)
|
||||||
{
|
{
|
||||||
// If loading test beatmaps, avoid overwriting with realm subscription callbacks.
|
// If loading test beatmaps, avoid overwriting with realm subscription callbacks.
|
||||||
if (loadedTestBeatmaps)
|
if (loadedTestBeatmaps)
|
||||||
@ -255,7 +255,7 @@ namespace osu.Game.Screens.Select
|
|||||||
foreach (var id in realmSets)
|
foreach (var id in realmSets)
|
||||||
{
|
{
|
||||||
if (!root.BeatmapSetsByID.ContainsKey(id))
|
if (!root.BeatmapSetsByID.ContainsKey(id))
|
||||||
UpdateBeatmapSet(realm.Realm.Find<BeatmapSetInfo>(id).Detach());
|
UpdateBeatmapSet(realm.Realm.Find<BeatmapSetInfo>(id)!.Detach());
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var id in root.BeatmapSetsByID.Keys)
|
foreach (var id in root.BeatmapSetsByID.Keys)
|
||||||
@ -315,7 +315,7 @@ namespace osu.Game.Screens.Select
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void beatmapsChanged(IRealmCollection<BeatmapInfo> sender, ChangeSet? changes, Exception? error)
|
private void beatmapsChanged(IRealmCollection<BeatmapInfo> sender, ChangeSet? changes)
|
||||||
{
|
{
|
||||||
// we only care about actual changes in hidden status.
|
// we only care about actual changes in hidden status.
|
||||||
if (changes == null)
|
if (changes == null)
|
||||||
|
@ -76,14 +76,12 @@ namespace osu.Game.Screens.Select
|
|||||||
protected override void PopIn()
|
protected override void PopIn()
|
||||||
{
|
{
|
||||||
this.MoveToX(0, animation_duration, Easing.OutQuint);
|
this.MoveToX(0, animation_duration, Easing.OutQuint);
|
||||||
this.RotateTo(0, animation_duration, Easing.OutQuint);
|
|
||||||
this.FadeIn(transition_duration);
|
this.FadeIn(transition_duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void PopOut()
|
protected override void PopOut()
|
||||||
{
|
{
|
||||||
this.MoveToX(-100, animation_duration, Easing.In);
|
this.MoveToX(-100, animation_duration, Easing.In);
|
||||||
this.RotateTo(10, animation_duration, Easing.In);
|
|
||||||
this.FadeOut(transition_duration * 2, Easing.In);
|
this.FadeOut(transition_duration * 2, Easing.In);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ namespace osu.Game.Screens.Select.Carousel
|
|||||||
localScoresChanged);
|
localScoresChanged);
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
void localScoresChanged(IRealmCollection<ScoreInfo> sender, ChangeSet? changes, Exception _)
|
void localScoresChanged(IRealmCollection<ScoreInfo> sender, ChangeSet? changes)
|
||||||
{
|
{
|
||||||
// This subscription may fire from changes to linked beatmaps, which we don't care about.
|
// This subscription may fire from changes to linked beatmaps, which we don't care about.
|
||||||
// It's currently not possible for a score to be modified after insertion, so we can safely ignore callbacks with only modifications.
|
// It's currently not possible for a score to be modified after insertion, so we can safely ignore callbacks with only modifications.
|
||||||
|
@ -193,7 +193,7 @@ namespace osu.Game.Screens.Select.Leaderboards
|
|||||||
+ $" AND {nameof(ScoreInfo.DeletePending)} == false"
|
+ $" AND {nameof(ScoreInfo.DeletePending)} == false"
|
||||||
, beatmapInfo.ID, ruleset.Value.ShortName), localScoresChanged);
|
, beatmapInfo.ID, ruleset.Value.ShortName), localScoresChanged);
|
||||||
|
|
||||||
void localScoresChanged(IRealmCollection<ScoreInfo> sender, ChangeSet? changes, Exception exception)
|
void localScoresChanged(IRealmCollection<ScoreInfo> sender, ChangeSet? changes)
|
||||||
{
|
{
|
||||||
if (cancellationToken.IsCancellationRequested)
|
if (cancellationToken.IsCancellationRequested)
|
||||||
return;
|
return;
|
||||||
|
@ -4,9 +4,7 @@
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Game.Overlays.Dialog;
|
using osu.Game.Overlays.Dialog;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
using System.Diagnostics;
|
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
|
|
||||||
namespace osu.Game.Screens.Select
|
namespace osu.Game.Screens.Select
|
||||||
{
|
{
|
||||||
@ -20,11 +18,8 @@ namespace osu.Game.Screens.Select
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(BeatmapManager beatmapManager, ScoreManager scoreManager)
|
private void load(ScoreManager scoreManager)
|
||||||
{
|
{
|
||||||
BeatmapInfo? beatmapInfo = beatmapManager.QueryBeatmap(b => b.ID == score.BeatmapInfoID);
|
|
||||||
Debug.Assert(beatmapInfo != null);
|
|
||||||
|
|
||||||
BodyText = $"{score.User} ({score.DisplayAccuracy}, {score.Rank})";
|
BodyText = $"{score.User} ({score.DisplayAccuracy}, {score.Rank})";
|
||||||
|
|
||||||
Icon = FontAwesome.Regular.TrashAlt;
|
Icon = FontAwesome.Regular.TrashAlt;
|
||||||
|
@ -90,7 +90,7 @@ namespace osu.Game.Screens.Spectate
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void beatmapsChanged(IRealmCollection<BeatmapSetInfo> items, ChangeSet changes, Exception ___)
|
private void beatmapsChanged(IRealmCollection<BeatmapSetInfo> items, ChangeSet changes)
|
||||||
{
|
{
|
||||||
if (changes?.InsertedIndices == null) return;
|
if (changes?.InsertedIndices == null) return;
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ namespace osu.Game.Skinning
|
|||||||
realmSubscription?.Dispose();
|
realmSubscription?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void skinChanged(IRealmCollection<T> sender, ChangeSet changes, Exception error) => invalidateCache();
|
private void skinChanged(IRealmCollection<T> sender, ChangeSet? changes) => invalidateCache();
|
||||||
|
|
||||||
protected override IEnumerable<string> GetFilenames(string name)
|
protected override IEnumerable<string> GetFilenames(string name)
|
||||||
{
|
{
|
||||||
|
@ -198,7 +198,7 @@ namespace osu.Game.Skinning
|
|||||||
|
|
||||||
using (var streamContent = new MemoryStream(Encoding.UTF8.GetBytes(skinInfoJson)))
|
using (var streamContent = new MemoryStream(Encoding.UTF8.GetBytes(skinInfoJson)))
|
||||||
{
|
{
|
||||||
modelManager.AddFile(s, streamContent, skin_info_file, s.Realm);
|
modelManager.AddFile(s, streamContent, skin_info_file, s.Realm!);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then serialise each of the drawable component groups into respective files.
|
// Then serialise each of the drawable component groups into respective files.
|
||||||
@ -213,9 +213,9 @@ namespace osu.Game.Skinning
|
|||||||
var oldFile = s.GetFile(filename);
|
var oldFile = s.GetFile(filename);
|
||||||
|
|
||||||
if (oldFile != null)
|
if (oldFile != null)
|
||||||
modelManager.ReplaceFile(oldFile, streamContent, s.Realm);
|
modelManager.ReplaceFile(oldFile, streamContent, s.Realm!);
|
||||||
else
|
else
|
||||||
modelManager.AddFile(s, streamContent, filename, s.Realm);
|
modelManager.AddFile(s, streamContent, filename, s.Realm!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ using osu.Framework.Graphics.Shapes;
|
|||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Framework.Testing.Input;
|
using osu.Framework.Testing.Input;
|
||||||
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Cursor;
|
using osu.Game.Graphics.Cursor;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Graphics.UserInterfaceV2;
|
using osu.Game.Graphics.UserInterfaceV2;
|
||||||
@ -25,8 +26,7 @@ namespace osu.Game.Tests.Visual
|
|||||||
|
|
||||||
protected readonly ManualInputManager InputManager;
|
protected readonly ManualInputManager InputManager;
|
||||||
|
|
||||||
private readonly RoundedButton buttonTest;
|
private readonly Container takeControlOverlay;
|
||||||
private readonly RoundedButton buttonLocal;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether to create a nested container to handle <see cref="GlobalAction"/>s that result from local (manual) test input.
|
/// Whether to create a nested container to handle <see cref="GlobalAction"/>s that result from local (manual) test input.
|
||||||
@ -66,12 +66,12 @@ namespace osu.Game.Tests.Visual
|
|||||||
UseParentInput = true,
|
UseParentInput = true,
|
||||||
Child = mainContent
|
Child = mainContent
|
||||||
},
|
},
|
||||||
new Container
|
takeControlOverlay = new Container
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Anchor = Anchor.TopRight,
|
Anchor = Anchor.BottomCentre,
|
||||||
Origin = Anchor.TopRight,
|
Origin = Anchor.BottomCentre,
|
||||||
Margin = new MarginPadding(5),
|
Margin = new MarginPadding(40),
|
||||||
CornerRadius = 5,
|
CornerRadius = 5,
|
||||||
Masking = true,
|
Masking = true,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
@ -80,44 +80,38 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
Colour = Color4.Black,
|
Colour = Color4.Black,
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Alpha = 0.5f,
|
Alpha = 0.4f,
|
||||||
},
|
},
|
||||||
new FillFlowContainer
|
new FillFlowContainer
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
Margin = new MarginPadding(5),
|
Margin = new MarginPadding(10),
|
||||||
Spacing = new Vector2(5),
|
Spacing = new Vector2(10),
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new OsuSpriteText
|
new OsuSpriteText
|
||||||
{
|
{
|
||||||
Anchor = Anchor.TopCentre,
|
Anchor = Anchor.TopCentre,
|
||||||
Origin = Anchor.TopCentre,
|
Origin = Anchor.TopCentre,
|
||||||
Text = "Input Priority"
|
Font = OsuFont.Default.With(weight: FontWeight.Bold),
|
||||||
|
Text = "The test is currently overriding local input",
|
||||||
},
|
},
|
||||||
new FillFlowContainer
|
new FillFlowContainer
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Anchor = Anchor.TopCentre,
|
Anchor = Anchor.TopCentre,
|
||||||
Origin = Anchor.TopCentre,
|
Origin = Anchor.TopCentre,
|
||||||
Margin = new MarginPadding(5),
|
|
||||||
Spacing = new Vector2(5),
|
Spacing = new Vector2(5),
|
||||||
Direction = FillDirection.Horizontal,
|
Direction = FillDirection.Horizontal,
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
buttonLocal = new RoundedButton
|
new RoundedButton
|
||||||
{
|
{
|
||||||
Text = "local",
|
Text = "Take control back",
|
||||||
Size = new Vector2(50, 30),
|
Size = new Vector2(180, 30),
|
||||||
Action = returnUserInput
|
Action = () => InputManager.UseParentInput = true
|
||||||
},
|
|
||||||
buttonTest = new RoundedButton
|
|
||||||
{
|
|
||||||
Text = "test",
|
|
||||||
Size = new Vector2(50, 30),
|
|
||||||
Action = returnTestInput
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -128,6 +122,13 @@ namespace osu.Game.Tests.Visual
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
|
||||||
|
takeControlOverlay.Alpha = InputManager.UseParentInput ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Wait for a button to become enabled, then click it.
|
/// Wait for a button to become enabled, then click it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -146,19 +147,5 @@ namespace osu.Game.Tests.Visual
|
|||||||
InputManager.Click(MouseButton.Left);
|
InputManager.Click(MouseButton.Left);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
|
||||||
{
|
|
||||||
base.Update();
|
|
||||||
|
|
||||||
buttonTest.Enabled.Value = InputManager.UseParentInput;
|
|
||||||
buttonLocal.Enabled.Value = !InputManager.UseParentInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void returnUserInput() =>
|
|
||||||
InputManager.UseParentInput = true;
|
|
||||||
|
|
||||||
private void returnTestInput() =>
|
|
||||||
InputManager.UseParentInput = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,7 @@ namespace osu.Game.Users
|
|||||||
|
|
||||||
protected string Username => score.User.Username;
|
protected string Username => score.User.Username;
|
||||||
|
|
||||||
public BeatmapInfo BeatmapInfo => score.BeatmapInfo;
|
public BeatmapInfo? BeatmapInfo => score.BeatmapInfo;
|
||||||
|
|
||||||
public WatchingReplay(ScoreInfo score)
|
public WatchingReplay(ScoreInfo score)
|
||||||
{
|
{
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user