1
0
mirror of https://github.com/ppy/osu.git synced 2025-03-17 22:17:25 +08:00

Merge branch 'master' of https://github.com/ppy/osu into no-long-notes-mod

This commit is contained in:
Spooghetti420 2022-01-28 08:53:35 +00:00
commit b13f3df327
22 changed files with 335 additions and 86 deletions

View File

@ -794,5 +794,32 @@ namespace osu.Game.Tests.Beatmaps.Formats
Assert.That(path.Distance, Is.EqualTo(1));
}
}
[Test]
public void TestLegacyDefaultsPreserved()
{
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
using (var memoryStream = new MemoryStream())
using (var stream = new LineBufferedReader(memoryStream))
{
var decoded = decoder.Decode(stream);
Assert.Multiple(() =>
{
Assert.That(decoded.BeatmapInfo.AudioLeadIn, Is.EqualTo(0));
Assert.That(decoded.BeatmapInfo.StackLeniency, Is.EqualTo(0.7f));
Assert.That(decoded.BeatmapInfo.SpecialStyle, Is.False);
Assert.That(decoded.BeatmapInfo.LetterboxInBreaks, Is.False);
Assert.That(decoded.BeatmapInfo.WidescreenStoryboard, Is.False);
Assert.That(decoded.BeatmapInfo.EpilepsyWarning, Is.False);
Assert.That(decoded.BeatmapInfo.SamplesMatchPlaybackRate, Is.False);
Assert.That(decoded.BeatmapInfo.Countdown, Is.EqualTo(CountdownType.Normal));
Assert.That(decoded.BeatmapInfo.CountdownOffset, Is.EqualTo(0));
Assert.That(decoded.BeatmapInfo.Metadata.PreviewTime, Is.EqualTo(-1));
Assert.That(decoded.BeatmapInfo.Ruleset.OnlineID, Is.EqualTo(0));
});
}
}
}
}

View File

@ -3,9 +3,9 @@
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Testing;
using osu.Game.Screens.Play.HUD;
using osuTK;
using osuTK.Input;
@ -19,28 +19,35 @@ namespace osu.Game.Tests.Visual.Gameplay
protected override double TimePerAction => 100; // required for the early exit test, since hold-to-confirm delay is 200ms
[BackgroundDependencyLoader]
private void load()
private HoldForMenuButton holdForMenuButton;
[SetUpSteps]
public void SetUpSteps()
{
HoldForMenuButton holdForMenuButton;
Add(holdForMenuButton = new HoldForMenuButton
AddStep("create button", () =>
{
Origin = Anchor.BottomRight,
Anchor = Anchor.BottomRight,
Action = () => exitAction = true
exitAction = false;
Child = holdForMenuButton = new HoldForMenuButton
{
Scale = new Vector2(2),
Origin = Anchor.CentreRight,
Anchor = Anchor.CentreRight,
Action = () => exitAction = true
};
});
}
var text = holdForMenuButton.Children.OfType<SpriteText>().First();
[Test]
public void TestMovementAndTrigger()
{
AddStep("Trigger text fade in", () => InputManager.MoveMouseTo(holdForMenuButton));
AddUntilStep("Text visible", () => text.IsPresent && !exitAction);
AddUntilStep("Text visible", () => getSpriteText().IsPresent && !exitAction);
AddStep("Trigger text fade out", () => InputManager.MoveMouseTo(Vector2.One));
AddUntilStep("Text is not visible", () => !text.IsPresent && !exitAction);
AddUntilStep("Text is not visible", () => !getSpriteText().IsPresent && !exitAction);
AddStep("Trigger exit action", () =>
{
exitAction = false;
InputManager.MoveMouseTo(holdForMenuButton);
InputManager.PressButton(MouseButton.Left);
});
@ -50,6 +57,17 @@ namespace osu.Game.Tests.Visual.Gameplay
AddStep("Trigger exit action", () => InputManager.PressButton(MouseButton.Left));
AddUntilStep($"{nameof(holdForMenuButton.Action)} was triggered", () => exitAction);
AddStep("Release", () => InputManager.ReleaseButton(MouseButton.Left));
}
[Test]
public void TestFadeOnNoInput()
{
AddStep("move mouse away", () => InputManager.MoveMouseTo(Vector2.One));
AddUntilStep("wait for text fade out", () => !getSpriteText().IsPresent);
AddUntilStep("wait for button fade out", () => holdForMenuButton.Alpha < 0.1f);
}
private SpriteText getSpriteText() => holdForMenuButton.Children.OfType<SpriteText>().First();
}
}

View File

@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
@ -10,16 +11,19 @@ using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.Leaderboards;
using osu.Game.Overlays;
using osu.Game.Overlays.Mods;
using osu.Game.Overlays.Toolbar;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Scoring;
using osu.Game.Screens.Menu;
using osu.Game.Screens.OnlinePlay.Lounge;
using osu.Game.Screens.Play;
using osu.Game.Screens.Ranking;
using osu.Game.Screens.Select;
using osu.Game.Screens.Select.Leaderboards;
using osu.Game.Screens.Select.Options;
using osu.Game.Tests.Beatmaps.IO;
using osuTK;
@ -96,35 +100,81 @@ namespace osu.Game.Tests.Visual.Navigation
[Test]
public void TestRetryFromResults()
{
Player player = null;
ResultsScreen results = null;
var getOriginalPlayer = playToResults();
IWorkingBeatmap beatmap() => Game.Beatmap.Value;
AddStep("attempt to retry", () => ((ResultsScreen)Game.ScreenStack.CurrentScreen).ChildrenOfType<HotkeyRetryOverlay>().First().Action());
AddUntilStep("wait for player", () => Game.ScreenStack.CurrentScreen != getOriginalPlayer() && Game.ScreenStack.CurrentScreen is Player);
}
Screens.Select.SongSelect songSelect = null;
PushAndConfirm(() => songSelect = new TestPlaySongSelect());
AddUntilStep("wait for song select", () => songSelect.BeatmapSetsLoaded);
[Test]
public void TestDeleteAllScoresAfterPlaying()
{
playToResults();
AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).WaitSafely());
ScoreInfo score = null;
LeaderboardScore scorePanel = null;
AddUntilStep("wait for selected", () => !Game.Beatmap.IsDefault);
AddStep("get score", () => score = ((ResultsScreen)Game.ScreenStack.CurrentScreen).Score);
AddStep("set mods", () => Game.SelectedMods.Value = new Mod[] { new OsuModNoFail(), new OsuModDoubleTime { SpeedChange = { Value = 2 } } });
AddAssert("ensure score is databased", () => Game.Realm.Run(r => r.Find<ScoreInfo>(score.ID)?.DeletePending == false));
AddStep("press enter", () => InputManager.Key(Key.Enter));
AddStep("press back button", () => Game.ChildrenOfType<BackButton>().First().Action());
AddUntilStep("wait for player", () =>
AddStep("show local scores", () => Game.ChildrenOfType<BeatmapDetailAreaTabControl>().First().Current.Value = new BeatmapDetailAreaLeaderboardTabItem<BeatmapLeaderboardScope>(BeatmapLeaderboardScope.Local));
AddUntilStep("wait for score displayed", () => (scorePanel = Game.ChildrenOfType<LeaderboardScore>().FirstOrDefault(s => s.Score.Equals(score))) != null);
AddStep("open options", () => InputManager.Key(Key.F3));
AddStep("choose clear all scores", () => InputManager.Key(Key.Number4));
AddStep("confirm deletion", () => InputManager.Key(Key.Number1));
AddAssert("ensure score is pending deletion", () => Game.Realm.Run(r => r.Find<ScoreInfo>(score.ID)?.DeletePending == true));
AddUntilStep("wait for score panel removal", () => scorePanel.Parent == null);
}
[Test]
public void TestDeleteScoreAfterPlaying()
{
playToResults();
ScoreInfo score = null;
LeaderboardScore scorePanel = null;
AddStep("get score", () => score = ((ResultsScreen)Game.ScreenStack.CurrentScreen).Score);
AddAssert("ensure score is databased", () => Game.Realm.Run(r => r.Find<ScoreInfo>(score.ID)?.DeletePending == false));
AddStep("press back button", () => Game.ChildrenOfType<BackButton>().First().Action());
AddStep("show local scores", () => Game.ChildrenOfType<BeatmapDetailAreaTabControl>().First().Current.Value = new BeatmapDetailAreaLeaderboardTabItem<BeatmapLeaderboardScope>(BeatmapLeaderboardScope.Local));
AddUntilStep("wait for score displayed", () => (scorePanel = Game.ChildrenOfType<LeaderboardScore>().FirstOrDefault(s => s.Score.Equals(score))) != null);
AddStep("right click panel", () =>
{
// dismiss any notifications that may appear (ie. muted notification).
clickMouseInCentre();
return (player = Game.ScreenStack.CurrentScreen as Player) != null;
InputManager.MoveMouseTo(scorePanel);
InputManager.Click(MouseButton.Right);
});
AddUntilStep("wait for track playing", () => beatmap().Track.IsRunning);
AddStep("seek to near end", () => player.ChildrenOfType<GameplayClockContainer>().First().Seek(beatmap().Beatmap.HitObjects[^1].StartTime - 1000));
AddUntilStep("wait for pass", () => (results = Game.ScreenStack.CurrentScreen as ResultsScreen) != null && results.IsLoaded);
AddStep("attempt to retry", () => results.ChildrenOfType<HotkeyRetryOverlay>().First().Action());
AddUntilStep("wait for player", () => Game.ScreenStack.CurrentScreen != player && Game.ScreenStack.CurrentScreen is Player);
AddStep("click delete", () =>
{
var dropdownItem = Game
.ChildrenOfType<PlayBeatmapDetailArea>().First()
.ChildrenOfType<OsuContextMenu>().First()
.ChildrenOfType<DrawableOsuMenuItem>().First(i => i.Item.Text.ToString() == "Delete");
InputManager.MoveMouseTo(dropdownItem);
InputManager.Click(MouseButton.Left);
});
AddStep("confirm deletion", () => InputManager.Key(Key.Number1));
AddAssert("ensure score is pending deletion", () => Game.Realm.Run(r => r.Find<ScoreInfo>(score.ID)?.DeletePending == true));
AddUntilStep("wait for score panel removal", () => scorePanel.Parent == null);
}
[TestCase(true)]
@ -432,6 +482,37 @@ namespace osu.Game.Tests.Visual.Navigation
AddStep("test dispose doesn't crash", () => Game.Dispose());
}
private Func<Player> playToResults()
{
Player player = null;
IWorkingBeatmap beatmap() => Game.Beatmap.Value;
Screens.Select.SongSelect songSelect = null;
PushAndConfirm(() => songSelect = new TestPlaySongSelect());
AddUntilStep("wait for song select", () => songSelect.BeatmapSetsLoaded);
AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).WaitSafely());
AddUntilStep("wait for selected", () => !Game.Beatmap.IsDefault);
AddStep("set mods", () => Game.SelectedMods.Value = new Mod[] { new OsuModNoFail(), new OsuModDoubleTime { SpeedChange = { Value = 2 } } });
AddStep("press enter", () => InputManager.Key(Key.Enter));
AddUntilStep("wait for player", () =>
{
// dismiss any notifications that may appear (ie. muted notification).
clickMouseInCentre();
return (player = Game.ScreenStack.CurrentScreen as Player) != null;
});
AddUntilStep("wait for track playing", () => beatmap().Track.IsRunning);
AddStep("seek to near end", () => player.ChildrenOfType<GameplayClockContainer>().First().Seek(beatmap().Beatmap.HitObjects[^1].StartTime - 1000));
AddUntilStep("wait for pass", () => (Game.ScreenStack.CurrentScreen as ResultsScreen)?.IsLoaded == true);
return () => player;
}
private void clickMouseInCentre()
{
InputManager.MoveMouseTo(Game.ScreenSpaceDrawQuad.Centre);

View File

@ -9,6 +9,7 @@ using osu.Framework.Allocation;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Rulesets;
@ -40,6 +41,36 @@ namespace osu.Game.Tests.Visual.SongSelect
this.rulesets = rulesets;
}
[Test]
public void TestScrollPositionMaintainedOnAdd()
{
loadBeatmaps(count: 1, randomDifficulties: false);
for (int i = 0; i < 10; i++)
{
AddRepeatStep("Add some sets", () => carousel.UpdateBeatmapSet(TestResources.CreateTestBeatmapSetInfo()), 4);
checkSelectionIsCentered();
}
}
[Test]
public void TestScrollPositionMaintainedOnDelete()
{
loadBeatmaps(count: 50, randomDifficulties: false);
for (int i = 0; i < 10; i++)
{
AddRepeatStep("Remove some sets", () =>
carousel.RemoveBeatmapSet(carousel.Items.Select(item => item.Item)
.OfType<CarouselBeatmapSet>()
.OrderBy(item => item.GetHashCode())
.First(item => item.State.Value != CarouselItemState.Selected && item.Visible).BeatmapSet), 4);
checkSelectionIsCentered();
}
}
[Test]
public void TestManyPanels()
{
@ -813,6 +844,18 @@ namespace osu.Game.Tests.Visual.SongSelect
carousel.Items.Count(s => (diff ? s.Item is CarouselBeatmap : s.Item is CarouselBeatmapSet) && s.Item.Visible) == count);
}
private void checkSelectionIsCentered()
{
AddAssert("Selected panel is centered", () =>
{
return Precision.AlmostEquals(
carousel.ScreenSpaceDrawQuad.Centre,
carousel.Items
.First(i => i.Item.State.Value == CarouselItemState.Selected)
.ScreenSpaceDrawQuad.Centre, 100);
});
}
private void checkNoSelection() => AddAssert("Selection is null", () => currentSelection == null);
private void nextRandom() =>

View File

@ -61,18 +61,15 @@ namespace osu.Game.Tournament
loadingSpinner.Show();
BracketLoadTask.ContinueWith(t =>
BracketLoadTask.ContinueWith(t => Schedule(() =>
{
if (t.IsFaulted)
{
Schedule(() =>
{
loadingSpinner.Hide();
loadingSpinner.Expire();
loadingSpinner.Hide();
loadingSpinner.Expire();
Logger.Error(t.Exception, "Couldn't load bracket with error");
Add(new WarningBox($"Your {BRACKET_FILENAME} file could not be parsed. Please check runtime.log for more details."));
});
Logger.Error(t.Exception, "Couldn't load bracket with error");
Add(new WarningBox($"Your {BRACKET_FILENAME} file could not be parsed. Please check runtime.log for more details."));
return;
}
@ -143,7 +140,7 @@ namespace osu.Game.Tournament
windowMode.Value = WindowMode.Windowed;
}), true);
});
});
}));
}
}
}

View File

@ -99,11 +99,11 @@ namespace osu.Game.Beatmaps
public bool LetterboxInBreaks { get; set; }
public bool WidescreenStoryboard { get; set; }
public bool WidescreenStoryboard { get; set; } = true;
public bool EpilepsyWarning { get; set; }
public bool SamplesMatchPlaybackRate { get; set; }
public bool SamplesMatchPlaybackRate { get; set; } = true;
public double DistanceSpacing { get; set; }

View File

@ -90,14 +90,7 @@ namespace osu.Game.Beatmaps
{
Beatmaps =
{
new BeatmapInfo
{
Difficulty = new BeatmapDifficulty(),
Ruleset = ruleset,
Metadata = metadata,
WidescreenStoryboard = true,
SamplesMatchPlaybackRate = true,
}
new BeatmapInfo(ruleset, new BeatmapDifficulty(), metadata)
}
};

View File

@ -39,7 +39,7 @@ namespace osu.Game.Beatmaps
/// The time in milliseconds to begin playing the track for preview purposes.
/// If -1, the track should begin playing at 40% of its length.
/// </summary>
public int PreviewTime { get; set; }
public int PreviewTime { get; set; } = -1;
public string AudioFile { get; set; } = string.Empty;
public string BackgroundFile { get; set; } = string.Empty;

View File

@ -56,6 +56,8 @@ namespace osu.Game.Beatmaps.Formats
this.beatmap = beatmap;
this.beatmap.BeatmapInfo.BeatmapVersion = FormatVersion;
applyLegacyDefaults(this.beatmap.BeatmapInfo);
base.ParseStreamInto(stream, beatmap);
flushPendingPoints();
@ -70,6 +72,19 @@ namespace osu.Game.Beatmaps.Formats
hitObject.ApplyDefaults(this.beatmap.ControlPointInfo, this.beatmap.Difficulty);
}
/// <summary>
/// Some `BeatmapInfo` members have default values that differ from the default values used by stable.
/// In addition, legacy beatmaps will sometimes not contain some configuration keys, in which case
/// the legacy default values should be used.
/// This method's intention is to restore those legacy defaults.
/// See also: https://osu.ppy.sh/wiki/en/Client/File_formats/Osu_%28file_format%29
/// </summary>
private void applyLegacyDefaults(BeatmapInfo beatmapInfo)
{
beatmapInfo.WidescreenStoryboard = false;
beatmapInfo.SamplesMatchPlaybackRate = false;
}
protected override bool ShouldSkipLine(string line) => base.ShouldSkipLine(line) || line.StartsWith(' ') || line.StartsWith('_');
protected override void ParseLine(Beatmap beatmap, Section section, string line)

View File

@ -374,12 +374,12 @@ namespace osu.Game.Database
log($"Migrated {written}/{count} scores...");
}
var beatmap = r.All<BeatmapInfo>().First(b => b.Hash == score.BeatmapInfo.Hash);
var beatmap = r.All<BeatmapInfo>().FirstOrDefault(b => b.Hash == score.BeatmapInfo.Hash);
var ruleset = r.Find<RulesetInfo>(score.Ruleset.ShortName);
if (ruleset == null)
if (beatmap == null || ruleset == null)
{
log($"Skipping {++missing} scores with missing ruleset");
log($"Skipping {++missing} scores with missing ruleset or beatmap");
continue;
}

View File

@ -2,8 +2,10 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using osu.Framework.Bindables;
using osu.Framework.Development;
using osu.Framework.Graphics.Containers;
using osu.Framework.Threading;
@ -66,6 +68,8 @@ namespace osu.Game.Online
private void doPoll()
{
Debug.Assert(ThreadSafety.IsUpdateThread);
scheduledPoll = null;
pollingActive = true;
Poll().ContinueWith(_ => pollComplete());
@ -96,13 +100,13 @@ namespace osu.Game.Online
if (!lastTimePolled.HasValue)
{
doPoll();
Scheduler.AddOnce(doPoll);
return;
}
if (Time.Current - lastTimePolled.Value > TimeBetweenPolls.Value)
{
doPoll();
Scheduler.AddOnce(doPoll);
return;
}

View File

@ -107,6 +107,9 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
{
set
{
if (score == null && value == null)
return;
if (score?.Equals(value) == true)
return;

View File

@ -266,6 +266,15 @@ namespace osu.Game.Scoring
});
}
public void Delete(BeatmapInfo beatmap, bool silent = false)
{
realm.Run(r =>
{
var beatmapScores = r.Find<BeatmapInfo>(beatmap.ID).Scores.ToList();
scoreModelManager.Delete(beatmapScores, silent);
});
}
public void Delete(List<ScoreInfo> items, bool silent = false)
{
scoreModelManager.Delete(items, silent);

View File

@ -82,6 +82,11 @@ namespace osu.Game.Screens.Edit.Compose
protected override void LoadComplete()
{
base.LoadComplete();
// May be null in the case of a ruleset that doesn't have editor support, see CreateMainContent().
if (composer == null)
return;
EditorBeatmap.SelectedHitObjects.BindCollectionChanged((_, __) => updateClipboardActionAvailability());
clipboard.BindValueChanged(_ => updateClipboardActionAvailability());
composer.OnLoadComplete += _ => updateClipboardActionAvailability();

View File

@ -28,6 +28,8 @@ using osu.Game.Graphics.UserInterface;
using osu.Game.Input.Bindings;
using osu.Game.Online.API;
using osu.Game.Overlays;
using osu.Game.Overlays.Notifications;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Edit;
using osu.Game.Screens.Edit.Components;
using osu.Game.Screens.Edit.Components.Menus;
@ -61,7 +63,16 @@ namespace osu.Game.Screens.Edit
public override bool? AllowTrackAdjustments => false;
protected bool HasUnsavedChanges => lastSavedHash != changeHandler.CurrentStateHash;
protected bool HasUnsavedChanges
{
get
{
if (!canSave)
return false;
return lastSavedHash != changeHandler?.CurrentStateHash;
}
}
[Resolved]
private BeatmapManager beatmapManager { get; set; }
@ -72,10 +83,15 @@ namespace osu.Game.Screens.Edit
[Resolved(canBeNull: true)]
private DialogOverlay dialogOverlay { get; set; }
[Resolved(canBeNull: true)]
private NotificationOverlay notifications { get; set; }
public IBindable<bool> SamplePlaybackDisabled => samplePlaybackDisabled;
private readonly Bindable<bool> samplePlaybackDisabled = new Bindable<bool>();
private bool canSave;
private bool exitConfirmed;
private string lastSavedHash;
@ -92,6 +108,8 @@ namespace osu.Game.Screens.Edit
private IBeatmap playableBeatmap;
private EditorBeatmap editorBeatmap;
[CanBeNull] // Should be non-null once it can support custom rulesets.
private EditorChangeHandler changeHandler;
private EditorMenuBar menuBar;
@ -172,8 +190,14 @@ namespace osu.Game.Screens.Edit
AddInternal(editorBeatmap = new EditorBeatmap(playableBeatmap, loadableBeatmap.GetSkin(), loadableBeatmap.BeatmapInfo));
dependencies.CacheAs(editorBeatmap);
changeHandler = new EditorChangeHandler(editorBeatmap);
dependencies.CacheAs<IEditorChangeHandler>(changeHandler);
canSave = editorBeatmap.BeatmapInfo.Ruleset.CreateInstance() is ILegacyRuleset;
if (canSave)
{
changeHandler = new EditorChangeHandler(editorBeatmap);
dependencies.CacheAs<IEditorChangeHandler>(changeHandler);
}
beatDivisor.Value = editorBeatmap.BeatmapInfo.BeatDivisor;
beatDivisor.BindValueChanged(divisor => editorBeatmap.BeatmapInfo.BeatDivisor = divisor.NewValue);
@ -311,8 +335,8 @@ namespace osu.Game.Screens.Edit
}
});
changeHandler.CanUndo.BindValueChanged(v => undoMenuItem.Action.Disabled = !v.NewValue, true);
changeHandler.CanRedo.BindValueChanged(v => redoMenuItem.Action.Disabled = !v.NewValue, true);
changeHandler?.CanUndo.BindValueChanged(v => undoMenuItem.Action.Disabled = !v.NewValue, true);
changeHandler?.CanRedo.BindValueChanged(v => redoMenuItem.Action.Disabled = !v.NewValue, true);
menuBar.Mode.ValueChanged += onModeChanged;
}
@ -353,6 +377,12 @@ namespace osu.Game.Screens.Edit
protected void Save()
{
if (!canSave)
{
notifications?.Post(new SimpleErrorNotification { Text = "Saving is not supported for this ruleset yet, sorry!" });
return;
}
// no longer new after first user-triggered save.
isNewBeatmap = false;
@ -648,9 +678,9 @@ namespace osu.Game.Screens.Edit
#endregion
protected void Undo() => changeHandler.RestoreState(-1);
protected void Undo() => changeHandler?.RestoreState(-1);
protected void Redo() => changeHandler.RestoreState(1);
protected void Redo() => changeHandler?.RestoreState(1);
private void resetTrack(bool seekToStart = false)
{
@ -761,7 +791,7 @@ namespace osu.Game.Screens.Edit
private void updateLastSavedHash()
{
lastSavedHash = changeHandler.CurrentStateHash;
lastSavedHash = changeHandler?.CurrentStateHash;
}
private List<MenuItem> createFileMenuItems()

View File

@ -33,7 +33,7 @@ namespace osu.Game.Screens.OnlinePlay.Components
});
}
private GetRoomsRequest pollReq;
private GetRoomsRequest lastPollRequest;
protected override Task Poll()
{
@ -45,10 +45,11 @@ namespace osu.Game.Screens.OnlinePlay.Components
var tcs = new TaskCompletionSource<bool>();
pollReq?.Cancel();
pollReq = new GetRoomsRequest(Filter.Value.Status, Filter.Value.Category);
lastPollRequest?.Cancel();
pollReq.Success += result =>
var req = new GetRoomsRequest(Filter.Value.Status, Filter.Value.Category);
req.Success += result =>
{
foreach (var existing in RoomManager.Rooms.ToArray())
{
@ -66,10 +67,11 @@ namespace osu.Game.Screens.OnlinePlay.Components
tcs.SetResult(true);
};
pollReq.Failure += _ => tcs.SetResult(false);
req.Failure += _ => tcs.SetResult(false);
API.Queue(pollReq);
API.Queue(req);
lastPollRequest = req;
return tcs.Task;
}
}

View File

@ -18,7 +18,7 @@ namespace osu.Game.Screens.OnlinePlay.Components
this.room = room;
}
private GetRoomRequest pollReq;
private GetRoomRequest lastPollRequest;
protected override Task Poll()
{
@ -30,19 +30,22 @@ namespace osu.Game.Screens.OnlinePlay.Components
var tcs = new TaskCompletionSource<bool>();
pollReq?.Cancel();
pollReq = new GetRoomRequest(room.RoomID.Value.Value);
lastPollRequest?.Cancel();
pollReq.Success += result =>
var req = new GetRoomRequest(room.RoomID.Value.Value);
req.Success += result =>
{
result.RemoveExpiredPlaylistItems();
RoomManager.AddOrUpdateRoom(result);
tcs.SetResult(true);
};
pollReq.Failure += _ => tcs.SetResult(false);
req.Failure += _ => tcs.SetResult(false);
API.Queue(pollReq);
API.Queue(req);
lastPollRequest = req;
return tcs.Task;
}

View File

@ -80,7 +80,7 @@ namespace osu.Game.Screens.Play.HUD
base.LoadComplete();
}
private float positionalAdjust;
private float positionalAdjust = 1; // Start at 1 to handle the case where a user never send positional input.
protected override bool OnMouseMove(MouseMoveEvent e)
{

View File

@ -286,6 +286,9 @@ namespace osu.Game.Screens.Select
root.RemoveChild(existingSet);
itemsCache.Invalidate();
if (!Scroll.UserScrolling)
ScrollToSelected(true);
});
public void UpdateBeatmapSet(BeatmapSetInfo beatmapSet) => Schedule(() =>
@ -311,13 +314,10 @@ namespace osu.Game.Screens.Select
itemsCache.Invalidate();
Schedule(() =>
{
if (!Scroll.UserScrolling)
ScrollToSelected(true);
if (!Scroll.UserScrolling)
ScrollToSelected(true);
BeatmapSetsChanged?.Invoke();
});
BeatmapSetsChanged?.Invoke();
});
/// <summary>

View File

@ -28,7 +28,7 @@ namespace osu.Game.Screens.Select
Text = @"Yes. Please.",
Action = () =>
{
Task.Run(() => scoreManager.Delete(s => !s.DeletePending && s.BeatmapInfo.ID == beatmapInfo.ID))
Task.Run(() => scoreManager.Delete(beatmapInfo))
.ContinueWith(_ => onCompletion);
}
},

View File

@ -38,6 +38,14 @@ namespace osu.Game.Screens.Select.Leaderboards
get => beatmapInfo;
set
{
if (beatmapInfo == null && value == null)
{
// always null scores to ensure a correct initial display.
// see weird `scoresLoadedOnce` logic in base implementation.
Scores = null;
return;
}
if (beatmapInfo?.Equals(value) == true)
return;

View File

@ -14,6 +14,7 @@ using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Database;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API;
using osu.Game.Overlays;
@ -111,6 +112,8 @@ namespace osu.Game.Tests.Visual
public new ScreenStack ScreenStack => base.ScreenStack;
public RealmAccess Realm => Dependencies.Get<RealmAccess>();
public new BackButton BackButton => base.BackButton;
public new BeatmapManager BeatmapManager => base.BeatmapManager;
@ -158,6 +161,14 @@ namespace osu.Game.Tests.Visual
Dependencies.Get<SessionStatics>().SetValue(Static.MutedAudioNotificationShownOnce, true);
}
protected override void Update()
{
base.Update();
// when running in visual tests and the window loses focus, we generally don't want the game to pause.
((Bindable<bool>)IsActive).Value = true;
}
}
public class TestLoader : Loader