1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-15 15:12:57 +08:00

Merge branch 'master' into visual-settings-container

This commit is contained in:
David Zhao 2019-03-19 20:17:12 +09:00 committed by GitHub
commit a1000524ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 238 additions and 160 deletions

View File

@ -23,16 +23,9 @@ namespace osu.Game.Rulesets.Catch.Difficulty
protected override int SectionLength => 750; protected override int SectionLength => 750;
private readonly float halfCatchWidth;
public CatchDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap) public CatchDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap)
: base(ruleset, beatmap) : base(ruleset, beatmap)
{ {
var catcher = new CatcherArea.Catcher(beatmap.BeatmapInfo.BaseDifficulty);
halfCatchWidth = catcher.CatchWidth * 0.5f;
// We're only using 80% of the catcher's width to simulate imperfect gameplay.
halfCatchWidth *= 0.8f;
} }
protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
@ -54,6 +47,14 @@ namespace osu.Game.Rulesets.Catch.Difficulty
protected override IEnumerable<DifficultyHitObject> CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) protected override IEnumerable<DifficultyHitObject> CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate)
{ {
float halfCatchWidth;
using (var catcher = new CatcherArea.Catcher(beatmap.BeatmapInfo.BaseDifficulty))
{
halfCatchWidth = catcher.CatchWidth * 0.5f;
halfCatchWidth *= 0.8f; // We're only using 80% of the catcher's width to simulate imperfect gameplay.
}
CatchHitObject lastObject = null; CatchHitObject lastObject = null;
foreach (var hitObject in beatmap.HitObjects.OfType<CatchHitObject>()) foreach (var hitObject in beatmap.HitObjects.OfType<CatchHitObject>())

View File

@ -15,41 +15,66 @@ namespace osu.Game.Rulesets.Catch.Mods
public override double ScoreMultiplier => 1.12; public override double ScoreMultiplier => 1.12;
public override bool Ranked => true; public override bool Ranked => true;
private float lastStartX; private float? lastPosition;
private int lastStartTime; private double lastStartTime;
public void ApplyToHitObject(HitObject hitObject) public void ApplyToHitObject(HitObject hitObject)
{ {
if (!(hitObject is Fruit))
return;
var catchObject = (CatchHitObject)hitObject; var catchObject = (CatchHitObject)hitObject;
float position = catchObject.X; float position = catchObject.X;
int startTime = (int)hitObject.StartTime; double startTime = hitObject.StartTime;
if (lastStartX == 0) if (lastPosition == null)
{ {
lastStartX = position; lastPosition = position;
lastStartTime = startTime; lastStartTime = startTime;
return; return;
} }
float diff = lastStartX - position; float positionDiff = position - lastPosition.Value;
int timeDiff = startTime - lastStartTime; double timeDiff = startTime - lastStartTime;
if (timeDiff > 1000) if (timeDiff > 1000)
{ {
lastStartX = position; lastPosition = position;
lastStartTime = startTime; lastStartTime = startTime;
return; return;
} }
if (diff == 0) if (positionDiff == 0)
{
applyRandomOffset(ref position, timeDiff / 4d);
catchObject.X = position;
return;
}
if (Math.Abs(positionDiff * CatchPlayfield.BASE_WIDTH) < timeDiff / 3d)
applyOffset(ref position, positionDiff);
catchObject.X = position;
lastPosition = position;
lastStartTime = startTime;
}
/// <summary>
/// Applies a random offset in a random direction to a position, ensuring that the final position remains within the boundary of the playfield.
/// </summary>
/// <param name="position">The position which the offset should be applied to.</param>
/// <param name="maxOffset">The maximum offset, cannot exceed 20px.</param>
private void applyRandomOffset(ref float position, double maxOffset)
{ {
bool right = RNG.NextBool(); bool right = RNG.NextBool();
float rand = Math.Min(20, (float)RNG.NextDouble(0, maxOffset)) / CatchPlayfield.BASE_WIDTH;
float rand = Math.Min(20, (float)RNG.NextDouble(0, timeDiff / 4d)) / CatchPlayfield.BASE_WIDTH;
if (right) if (right)
{ {
// Clamp to the right bound
if (position + rand <= 1) if (position + rand <= 1)
position += rand; position += rand;
else else
@ -57,35 +82,33 @@ namespace osu.Game.Rulesets.Catch.Mods
} }
else else
{ {
// Clamp to the left bound
if (position - rand >= 0) if (position - rand >= 0)
position -= rand; position -= rand;
else else
position += rand; position += rand;
} }
catchObject.X = position;
return;
} }
if (Math.Abs(diff) < timeDiff / 3d) /// <summary>
/// Applies an offset to a position, ensuring that the final position remains within the boundary of the playfield.
/// </summary>
/// <param name="position">The position which the offset should be applied to.</param>
/// <param name="amount">The amount to offset by.</param>
private void applyOffset(ref float position, float amount)
{ {
if (diff > 0) if (amount > 0)
{ {
if (position - diff > 0) // Clamp to the right bound
position -= diff; if (position + amount < 1)
position += amount;
} }
else else
{ {
if (position - diff < 1) // Clamp to the left bound
position -= diff; if (position + amount > 0)
} position += amount;
} }
catchObject.X = position;
lastStartX = position;
lastStartTime = startTime;
} }
} }
} }

View File

@ -354,9 +354,9 @@ namespace osu.Game.Rulesets.Osu.Tests
judgementResults = new List<JudgementResult>(); judgementResults = new List<JudgementResult>();
}); });
AddUntilStep(() => Beatmap.Value.Track.CurrentTime == 0, "Beatmap at 0"); AddUntilStep("Beatmap at 0", () => Beatmap.Value.Track.CurrentTime == 0);
AddUntilStep(() => currentPlayer.IsCurrentScreen(), "Wait until player is loaded"); AddUntilStep("Wait until player is loaded", () => currentPlayer.IsCurrentScreen());
AddUntilStep(() => allJudgedFired, "Wait for all judged"); AddUntilStep("Wait for all judged", () => allJudgedFired);
} }
private class ScoreAccessibleReplayPlayer : ReplayPlayer private class ScoreAccessibleReplayPlayer : ReplayPlayer

View File

@ -27,8 +27,8 @@ namespace osu.Game.Tests.Visual
protected override void AddCheckSteps(Func<Player> player) protected override void AddCheckSteps(Func<Player> player)
{ {
base.AddCheckSteps(player); base.AddCheckSteps(player);
AddUntilStep(() => ((ScoreAccessiblePlayer)player()).ScoreProcessor.TotalScore.Value > 0, "score above zero"); AddUntilStep("score above zero", () => ((ScoreAccessiblePlayer)player()).ScoreProcessor.TotalScore.Value > 0);
AddUntilStep(() => ((ScoreAccessiblePlayer)player()).HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses > 0), "key counter counted keys"); AddUntilStep("key counter counted keys", () => ((ScoreAccessiblePlayer)player()).HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses > 0));
} }
private class ScoreAccessiblePlayer : Player private class ScoreAccessiblePlayer : Player

View File

@ -97,8 +97,8 @@ namespace osu.Game.Tests.Visual
public void PlayerLoaderSettingsHoverTest() public void PlayerLoaderSettingsHoverTest()
{ {
setupUserSettings(); setupUserSettings();
AddStep("Start player loader", () => songSelect.Push(playerLoader = new TestPlayerLoader(player = new TestPlayer()))); AddStep("Start player loader", () => songSelect.Push(playerLoader = new DimAccessiblePlayerLoader(player = new DimAccessiblePlayer())));
AddUntilStep(() => playerLoader?.IsLoaded ?? false, "Wait for Player Loader to load"); AddUntilStep("Wait for Player Loader to load", () => playerLoader?.IsLoaded ?? false);
AddAssert("Background retained from song select", () => songSelect.IsBackgroundCurrent()); AddAssert("Background retained from song select", () => songSelect.IsBackgroundCurrent());
AddStep("Trigger background preview", () => AddStep("Trigger background preview", () =>
{ {
@ -223,7 +223,7 @@ namespace osu.Game.Tests.Visual
AddAssert("Screen is undimmed and user blur removed", () => songSelect.IsBackgroundUndimmed() && songSelect.IsBlurCorrect()); AddAssert("Screen is undimmed and user blur removed", () => songSelect.IsBackgroundUndimmed() && songSelect.IsBlurCorrect());
} }
private void waitForDim() => AddWaitStep(5, "Wait for dim"); private void waitForDim() => AddWaitStep("Wait for dim", 5);
private void createFakeStoryboard() => AddStep("Create storyboard", () => private void createFakeStoryboard() => AddStep("Create storyboard", () =>
{ {
@ -252,14 +252,14 @@ namespace osu.Game.Tests.Visual
Ready = true, Ready = true,
})); }));
}); });
AddUntilStep(() => playerLoader.IsLoaded, "Wait for Player Loader to load"); AddUntilStep("Wait for Player Loader to load", () => playerLoader.IsLoaded);
AddStep("Move mouse to center of screen", () => InputManager.MoveMouseTo(playerLoader.ScreenPos)); AddStep("Move mouse to center of screen", () => InputManager.MoveMouseTo(playerLoader.ScreenPos));
AddUntilStep(() => player.IsLoaded, "Wait for player to load"); AddUntilStep("Wait for player to load", () => player.IsLoaded);
} }
private void setupUserSettings() private void setupUserSettings()
{ {
AddUntilStep(() => songSelect.Carousel.SelectedBeatmap != null, "Song select has selection"); AddUntilStep("Song select has selection", () => songSelect.Carousel.SelectedBeatmap != null);
AddStep("Set default user settings", () => AddStep("Set default user settings", () =>
{ {
Beatmap.Value.Mods.Value = Beatmap.Value.Mods.Value.Concat(new[] { new OsuModNoFail() }); Beatmap.Value.Mods.Value = Beatmap.Value.Mods.Value.Concat(new[] { new OsuModNoFail() });

View File

@ -87,7 +87,7 @@ namespace osu.Game.Tests.Visual
carousel.BeatmapSetsChanged = () => changed = true; carousel.BeatmapSetsChanged = () => changed = true;
carousel.BeatmapSets = beatmapSets; carousel.BeatmapSets = beatmapSets;
}); });
AddUntilStep(() => changed, "Wait for load"); AddUntilStep("Wait for load", () => changed);
} }
private void ensureRandomFetchSuccess() => private void ensureRandomFetchSuccess() =>
@ -214,7 +214,7 @@ namespace osu.Game.Tests.Visual
checkSelected(3, 2); checkSelected(3, 2);
AddStep("Un-filter (debounce)", () => carousel.Filter(new FilterCriteria())); AddStep("Un-filter (debounce)", () => carousel.Filter(new FilterCriteria()));
AddUntilStep(() => !carousel.PendingFilterTask, "Wait for debounce"); AddUntilStep("Wait for debounce", () => !carousel.PendingFilterTask);
checkVisibleItemCount(diff: false, count: set_count); checkVisibleItemCount(diff: false, count: set_count);
checkVisibleItemCount(diff: true, count: 3); checkVisibleItemCount(diff: true, count: 3);
@ -327,13 +327,13 @@ namespace osu.Game.Tests.Visual
AddStep("Remove first", () => carousel.RemoveBeatmapSet(carousel.BeatmapSets.First())); AddStep("Remove first", () => carousel.RemoveBeatmapSet(carousel.BeatmapSets.First()));
checkSelected(1); checkSelected(1);
AddUntilStep(() => AddUntilStep("Remove all", () =>
{ {
if (!carousel.BeatmapSets.Any()) return true; if (!carousel.BeatmapSets.Any()) return true;
carousel.RemoveBeatmapSet(carousel.BeatmapSets.Last()); carousel.RemoveBeatmapSet(carousel.BeatmapSets.Last());
return false; return false;
}, "Remove all"); });
checkNoSelection(); checkNoSelection();
} }

View File

@ -56,11 +56,11 @@ namespace osu.Game.Tests.Visual
// select part is redundant, but wait for load isn't // select part is redundant, but wait for load isn't
selectBeatmap(Beatmap.Value.Beatmap); selectBeatmap(Beatmap.Value.Beatmap);
AddWaitStep(3); AddWaitStep("wait for select", 3);
AddStep("hide", () => { infoWedge.State = Visibility.Hidden; }); AddStep("hide", () => { infoWedge.State = Visibility.Hidden; });
AddWaitStep(3); AddWaitStep("wait for hide", 3);
AddStep("show", () => { infoWedge.State = Visibility.Visible; }); AddStep("show", () => { infoWedge.State = Visibility.Visible; });
@ -135,7 +135,7 @@ namespace osu.Game.Tests.Visual
infoWedge.Beatmap = Beatmap.Value = b == null ? Beatmap.Default : new TestWorkingBeatmap(b); infoWedge.Beatmap = Beatmap.Value = b == null ? Beatmap.Default : new TestWorkingBeatmap(b);
}); });
AddUntilStep(() => infoWedge.Info != infoBefore, "wait for async load"); AddUntilStep("wait for async load", () => infoWedge.Info != infoBefore);
} }
private IBeatmap createTestBeatmap(RulesetInfo ruleset) private IBeatmap createTestBeatmap(RulesetInfo ruleset)

View File

@ -90,7 +90,7 @@ namespace osu.Game.Tests.Visual
AddStep("set second channel", () => channelTabControl.Current.Value = channelTabControl.Items.Skip(1).First()); AddStep("set second channel", () => channelTabControl.Current.Value = channelTabControl.Items.Skip(1).First());
AddAssert("selector tab is inactive", () => !channelTabControl.ChannelSelectorActive.Value); AddAssert("selector tab is inactive", () => !channelTabControl.ChannelSelectorActive.Value);
AddUntilStep(() => AddUntilStep("remove all channels", () =>
{ {
var first = channelTabControl.Items.First(); var first = channelTabControl.Items.First();
if (first.Name == "+") if (first.Name == "+")
@ -98,7 +98,7 @@ namespace osu.Game.Tests.Visual
channelTabControl.RemoveChannel(first); channelTabControl.RemoveChannel(first);
return false; return false;
}, "remove all channels"); });
AddAssert("selector tab is active", () => channelTabControl.ChannelSelectorActive.Value); AddAssert("selector tab is active", () => channelTabControl.ChannelSelectorActive.Value);
} }

View File

@ -159,7 +159,7 @@ namespace osu.Game.Tests.Visual
Scheduler.AddDelayed(() => newLine.Message = new DummyMessage(completeText ?? text), delay); Scheduler.AddDelayed(() => newLine.Message = new DummyMessage(completeText ?? text), delay);
}); });
AddUntilStep(() => textContainer.All(line => line.Message is DummyMessage), $"wait for msg #{echoCounter}"); AddUntilStep($"wait for msg #{echoCounter}", () => textContainer.All(line => line.Message is DummyMessage));
} }
} }

View File

@ -2,16 +2,31 @@
// 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 osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Game.Online.API;
using osu.Game.Screens.Menu; using osu.Game.Screens.Menu;
using osu.Game.Users;
namespace osu.Game.Tests.Visual namespace osu.Game.Tests.Visual
{ {
public class TestCaseDisclaimer : ScreenTestCase public class TestCaseDisclaimer : ScreenTestCase
{ {
[Cached(typeof(IAPIProvider))]
private readonly DummyAPIAccess api = new DummyAPIAccess();
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
LoadScreen(new Disclaimer()); AddStep("load disclaimer", () => LoadScreen(new Disclaimer()));
AddStep("toggle support", () =>
{
api.LocalUser.Value = new User
{
Username = api.LocalUser.Value.Username,
Id = api.LocalUser.Value.Id,
IsSupporter = !api.LocalUser.Value.IsSupporter,
};
});
} }
} }
} }

View File

@ -32,9 +32,9 @@ namespace osu.Game.Tests.Visual
var text = holdForMenuButton.Children.OfType<SpriteText>().First(); var text = holdForMenuButton.Children.OfType<SpriteText>().First();
AddStep("Trigger text fade in", () => InputManager.MoveMouseTo(holdForMenuButton)); AddStep("Trigger text fade in", () => InputManager.MoveMouseTo(holdForMenuButton));
AddUntilStep(() => text.IsPresent && !exitAction, "Text visible"); AddUntilStep("Text visible", () => text.IsPresent && !exitAction);
AddStep("Trigger text fade out", () => InputManager.MoveMouseTo(Vector2.One)); AddStep("Trigger text fade out", () => InputManager.MoveMouseTo(Vector2.One));
AddUntilStep(() => !text.IsPresent && !exitAction, "Text is not visible"); AddUntilStep("Text is not visible", () => !text.IsPresent && !exitAction);
AddStep("Trigger exit action", () => AddStep("Trigger exit action", () =>
{ {
@ -47,7 +47,7 @@ namespace osu.Game.Tests.Visual
AddAssert("action not triggered", () => !exitAction); AddAssert("action not triggered", () => !exitAction);
AddStep("Trigger exit action", () => InputManager.PressButton(MouseButton.Left)); AddStep("Trigger exit action", () => InputManager.PressButton(MouseButton.Left));
AddUntilStep(() => exitAction, $"{nameof(holdForMenuButton.Action)} was triggered"); AddUntilStep($"{nameof(holdForMenuButton.Action)} was triggered", () => exitAction);
} }
} }
} }

View File

@ -49,7 +49,7 @@ namespace osu.Game.Tests.Visual
AddStep("start confirming", () => overlay.Begin()); AddStep("start confirming", () => overlay.Begin());
AddUntilStep(() => fired, "wait until confirmed"); AddUntilStep("wait until confirmed", () => fired);
} }
private class TestHoldToConfirmOverlay : ExitConfirmOverlay private class TestHoldToConfirmOverlay : ExitConfirmOverlay

View File

@ -59,7 +59,7 @@ namespace osu.Game.Tests.Visual
{ {
AddStep("move mouse to top left", () => InputManager.MoveMouseTo(box1.ScreenSpaceDrawQuad.Centre)); AddStep("move mouse to top left", () => InputManager.MoveMouseTo(box1.ScreenSpaceDrawQuad.Centre));
AddUntilStep(() => box1.IsIdle && box2.IsIdle && box3.IsIdle && box4.IsIdle, "Wait for all idle"); AddUntilStep("Wait for all idle", () => box1.IsIdle && box2.IsIdle && box3.IsIdle && box4.IsIdle);
AddStep("nudge mouse", () => InputManager.MoveMouseTo(box1.ScreenSpaceDrawQuad.Centre + new Vector2(1))); AddStep("nudge mouse", () => InputManager.MoveMouseTo(box1.ScreenSpaceDrawQuad.Centre + new Vector2(1)));
@ -87,7 +87,7 @@ namespace osu.Game.Tests.Visual
AddAssert("check idle", () => !box3.IsIdle); AddAssert("check idle", () => !box3.IsIdle);
AddAssert("check idle", () => !box4.IsIdle); AddAssert("check idle", () => !box4.IsIdle);
AddUntilStep(() => box1.IsIdle && box2.IsIdle && box3.IsIdle && box4.IsIdle, "Wait for all idle"); AddUntilStep("Wait for all idle", () => box1.IsIdle && box2.IsIdle && box3.IsIdle && box4.IsIdle);
} }
[Test] [Test]
@ -96,13 +96,13 @@ namespace osu.Game.Tests.Visual
AddStep("move mouse", () => InputManager.MoveMouseTo(ScreenSpaceDrawQuad.Centre)); AddStep("move mouse", () => InputManager.MoveMouseTo(ScreenSpaceDrawQuad.Centre));
AddAssert("check not idle", () => !box1.IsIdle && !box2.IsIdle && !box3.IsIdle && !box4.IsIdle); AddAssert("check not idle", () => !box1.IsIdle && !box2.IsIdle && !box3.IsIdle && !box4.IsIdle);
AddUntilStep(() => box1.IsIdle, "Wait for idle"); AddUntilStep("Wait for idle", () => box1.IsIdle);
AddAssert("check not idle", () => !box2.IsIdle && !box3.IsIdle && !box4.IsIdle); AddAssert("check not idle", () => !box2.IsIdle && !box3.IsIdle && !box4.IsIdle);
AddUntilStep(() => box2.IsIdle, "Wait for idle"); AddUntilStep("Wait for idle", () => box2.IsIdle);
AddAssert("check not idle", () => !box3.IsIdle && !box4.IsIdle); AddAssert("check not idle", () => !box3.IsIdle && !box4.IsIdle);
AddUntilStep(() => box3.IsIdle, "Wait for idle"); AddUntilStep("Wait for idle", () => box3.IsIdle);
AddUntilStep(() => box1.IsIdle && box2.IsIdle && box3.IsIdle && box4.IsIdle, "Wait for all idle"); AddUntilStep("Wait for all idle", () => box1.IsIdle && box2.IsIdle && box3.IsIdle && box4.IsIdle);
} }
private class IdleTrackingBox : CompositeDrawable private class IdleTrackingBox : CompositeDrawable

View File

@ -25,30 +25,30 @@ namespace osu.Game.Tests.Visual
bool logoVisible = false; bool logoVisible = false;
AddStep("almost instant display", () => Child = loader = new TestLoader(250)); AddStep("almost instant display", () => Child = loader = new TestLoader(250));
AddUntilStep(() => AddUntilStep("loaded", () =>
{ {
logoVisible = loader.Logo?.Alpha > 0; logoVisible = loader.Logo?.Alpha > 0;
return loader.Logo != null && loader.ScreenLoaded; return loader.Logo != null && loader.ScreenLoaded;
}, "loaded"); });
AddAssert("logo not visible", () => !logoVisible); AddAssert("logo not visible", () => !logoVisible);
AddStep("short load", () => Child = loader = new TestLoader(800)); AddStep("short load", () => Child = loader = new TestLoader(800));
AddUntilStep(() => AddUntilStep("loaded", () =>
{ {
logoVisible = loader.Logo?.Alpha > 0; logoVisible = loader.Logo?.Alpha > 0;
return loader.Logo != null && loader.ScreenLoaded; return loader.Logo != null && loader.ScreenLoaded;
}, "loaded"); });
AddAssert("logo visible", () => logoVisible); AddAssert("logo visible", () => logoVisible);
AddUntilStep(() => loader.Logo?.Alpha == 0, "logo gone"); AddUntilStep("logo gone", () => loader.Logo?.Alpha == 0);
AddStep("longer load", () => Child = loader = new TestLoader(1400)); AddStep("longer load", () => Child = loader = new TestLoader(1400));
AddUntilStep(() => AddUntilStep("loaded", () =>
{ {
logoVisible = loader.Logo?.Alpha > 0; logoVisible = loader.Logo?.Alpha > 0;
return loader.Logo != null && loader.ScreenLoaded; return loader.Logo != null && loader.ScreenLoaded;
}, "loaded"); });
AddAssert("logo visible", () => logoVisible); AddAssert("logo visible", () => logoVisible);
AddUntilStep(() => loader.Logo?.Alpha == 0, "logo gone"); AddUntilStep("logo gone", () => loader.Logo?.Alpha == 0);
} }
private class TestLoader : Loader private class TestLoader : Loader

View File

@ -111,7 +111,7 @@ namespace osu.Game.Tests.Visual
settings.ApplyButton.Action.Invoke(); settings.ApplyButton.Action.Invoke();
}); });
AddUntilStep(() => !settings.ErrorText.IsPresent, "error not displayed"); AddUntilStep("error not displayed", () => !settings.ErrorText.IsPresent);
} }
private class TestRoomSettings : MatchSettingsOverlay private class TestRoomSettings : MatchSettingsOverlay

View File

@ -208,22 +208,22 @@ namespace osu.Game.Tests.Visual
{ {
checkLabelColor(Color4.White); checkLabelColor(Color4.White);
selectNext(mod); selectNext(mod);
AddWaitStep(1, "wait for changing colour"); AddWaitStep("wait for changing colour", 1);
checkLabelColor(colour); checkLabelColor(colour);
selectPrevious(mod); selectPrevious(mod);
AddWaitStep(1, "wait for changing colour"); AddWaitStep("wait for changing colour", 1);
checkLabelColor(Color4.White); checkLabelColor(Color4.White);
} }
private void testRankedText(Mod mod) private void testRankedText(Mod mod)
{ {
AddWaitStep(1, "wait for fade"); AddWaitStep("wait for fade", 1);
AddAssert("check for ranked", () => modSelect.UnrankedLabel.Alpha == 0); AddAssert("check for ranked", () => modSelect.UnrankedLabel.Alpha == 0);
selectNext(mod); selectNext(mod);
AddWaitStep(1, "wait for fade"); AddWaitStep("wait for fade", 1);
AddAssert("check for unranked", () => modSelect.UnrankedLabel.Alpha != 0); AddAssert("check for unranked", () => modSelect.UnrankedLabel.Alpha != 0);
selectPrevious(mod); selectPrevious(mod);
AddWaitStep(1, "wait for fade"); AddWaitStep("wait for fade", 1);
AddAssert("check for ranked", () => modSelect.UnrankedLabel.Alpha == 0); AddAssert("check for ranked", () => modSelect.UnrankedLabel.Alpha == 0);
} }

View File

@ -60,7 +60,7 @@ namespace osu.Game.Tests.Visual
setState(Visibility.Hidden); setState(Visibility.Hidden);
AddRepeatStep(@"add many simple", sendManyNotifications, 3); AddRepeatStep(@"add many simple", sendManyNotifications, 3);
AddWaitStep(5); AddWaitStep("wait some", 5);
checkProgressingCount(0); checkProgressingCount(0);
@ -70,7 +70,7 @@ namespace osu.Game.Tests.Visual
AddAssert("Displayed count is 33", () => manager.UnreadCount.Value == 33); AddAssert("Displayed count is 33", () => manager.UnreadCount.Value == 33);
AddWaitStep(10); AddWaitStep("wait some", 10);
checkProgressingCount(0); checkProgressingCount(0);

View File

@ -112,10 +112,10 @@ namespace osu.Game.Tests.Visual
createSongSelect(); createSongSelect();
AddAssert("dummy selected", () => songSelect.CurrentBeatmap == defaultBeatmap); AddAssert("dummy selected", () => songSelect.CurrentBeatmap == defaultBeatmap);
AddUntilStep(() => songSelect.CurrentBeatmapDetailsBeatmap == defaultBeatmap, "dummy shown on wedge"); AddUntilStep("dummy shown on wedge", () => songSelect.CurrentBeatmapDetailsBeatmap == defaultBeatmap);
addManyTestMaps(); addManyTestMaps();
AddWaitStep(3); AddWaitStep("wait for select", 3);
AddAssert("random map selected", () => songSelect.CurrentBeatmap != defaultBeatmap); AddAssert("random map selected", () => songSelect.CurrentBeatmap != defaultBeatmap);
} }
@ -125,7 +125,7 @@ namespace osu.Game.Tests.Visual
{ {
createSongSelect(); createSongSelect();
addManyTestMaps(); addManyTestMaps();
AddWaitStep(3); AddWaitStep("wait for add", 3);
AddAssert("random map selected", () => songSelect.CurrentBeatmap != defaultBeatmap); AddAssert("random map selected", () => songSelect.CurrentBeatmap != defaultBeatmap);
@ -142,7 +142,7 @@ namespace osu.Game.Tests.Visual
createSongSelect(); createSongSelect();
changeRuleset(2); changeRuleset(2);
importForRuleset(0); importForRuleset(0);
AddUntilStep(() => songSelect.Carousel.SelectedBeatmap == null, "no selection"); AddUntilStep("no selection", () => songSelect.Carousel.SelectedBeatmap == null);
} }
[Test] [Test]
@ -152,13 +152,13 @@ namespace osu.Game.Tests.Visual
changeRuleset(2); changeRuleset(2);
importForRuleset(2); importForRuleset(2);
importForRuleset(1); importForRuleset(1);
AddUntilStep(() => songSelect.Carousel.SelectedBeatmap.RulesetID == 2, "has selection"); AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmap.RulesetID == 2);
changeRuleset(1); changeRuleset(1);
AddUntilStep(() => songSelect.Carousel.SelectedBeatmap.RulesetID == 1, "has selection"); AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmap.RulesetID == 1);
changeRuleset(0); changeRuleset(0);
AddUntilStep(() => songSelect.Carousel.SelectedBeatmap == null, "no selection"); AddUntilStep("no selection", () => songSelect.Carousel.SelectedBeatmap == null);
} }
[Test] [Test]
@ -196,7 +196,7 @@ namespace osu.Game.Tests.Visual
{ {
createSongSelect(); createSongSelect();
addManyTestMaps(); addManyTestMaps();
AddUntilStep(() => songSelect.Carousel.SelectedBeatmap != null, "has selection"); AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmap != null);
bool startRequested = false; bool startRequested = false;
@ -225,7 +225,7 @@ namespace osu.Game.Tests.Visual
private void createSongSelect() private void createSongSelect()
{ {
AddStep("create song select", () => LoadScreen(songSelect = new TestSongSelect())); AddStep("create song select", () => LoadScreen(songSelect = new TestSongSelect()));
AddUntilStep(() => songSelect.IsCurrentScreen(), "wait for present"); AddUntilStep("wait for present", () => songSelect.IsCurrentScreen());
} }
private void addManyTestMaps() private void addManyTestMaps()

View File

@ -37,15 +37,15 @@ namespace osu.Game.Tests.Visual
AllowResults = false, AllowResults = false,
}))); })));
AddUntilStep(() => loader.IsCurrentScreen(), "wait for current"); AddUntilStep("wait for current", () => loader.IsCurrentScreen());
AddStep("mouse in centre", () => InputManager.MoveMouseTo(loader.ScreenSpaceDrawQuad.Centre)); AddStep("mouse in centre", () => InputManager.MoveMouseTo(loader.ScreenSpaceDrawQuad.Centre));
AddUntilStep(() => !loader.IsCurrentScreen(), "wait for no longer current"); AddUntilStep("wait for no longer current", () => !loader.IsCurrentScreen());
AddStep("exit loader", () => loader.Exit()); AddStep("exit loader", () => loader.Exit());
AddUntilStep(() => !loader.IsAlive, "wait for no longer alive"); AddUntilStep("wait for no longer alive", () => !loader.IsAlive);
AddStep("load slow dummy beatmap", () => AddStep("load slow dummy beatmap", () =>
{ {
@ -61,7 +61,7 @@ namespace osu.Game.Tests.Visual
Scheduler.AddDelayed(() => slow.Ready = true, 5000); Scheduler.AddDelayed(() => slow.Ready = true, 5000);
}); });
AddUntilStep(() => !loader.IsCurrentScreen(), "wait for no longer current"); AddUntilStep("wait for no longer current", () => !loader.IsCurrentScreen());
} }
protected class SlowLoadPlayer : Player protected class SlowLoadPlayer : Player

View File

@ -24,8 +24,8 @@ namespace osu.Game.Tests.Visual
protected override void AddCheckSteps(Func<Player> player) protected override void AddCheckSteps(Func<Player> player)
{ {
base.AddCheckSteps(player); base.AddCheckSteps(player);
AddUntilStep(() => ((ScoreAccessibleReplayPlayer)player()).ScoreProcessor.TotalScore.Value > 0, "score above zero"); AddUntilStep("score above zero", () => ((ScoreAccessibleReplayPlayer)player()).ScoreProcessor.TotalScore.Value > 0);
AddUntilStep(() => ((ScoreAccessibleReplayPlayer)player()).HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses > 0), "key counter counted keys"); AddUntilStep("key counter counted keys", () => ((ScoreAccessibleReplayPlayer)player()).HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses > 0));
} }
private class ScoreAccessibleReplayPlayer : ReplayPlayer private class ScoreAccessibleReplayPlayer : ReplayPlayer

View File

@ -74,7 +74,7 @@ namespace osu.Game.Tests.Visual
} }
private void pushNext() => AddStep(@"push next screen", () => ((TestScreen)screenStack.CurrentScreen).PushNext()); private void pushNext() => AddStep(@"push next screen", () => ((TestScreen)screenStack.CurrentScreen).PushNext());
private void waitForCurrent() => AddUntilStep(() => screenStack.CurrentScreen.IsCurrentScreen(), "current screen"); private void waitForCurrent() => AddUntilStep("current screen", () => screenStack.CurrentScreen.IsCurrentScreen());
private abstract class TestScreen : OsuScreen private abstract class TestScreen : OsuScreen
{ {

View File

@ -46,23 +46,23 @@ namespace osu.Game.Tests.Visual
Origin = Anchor.TopLeft, Origin = Anchor.TopLeft,
}); });
AddWaitStep(5); AddWaitStep("wait some", 5);
AddAssert("ensure not created", () => graph.CreationCount == 0); AddAssert("ensure not created", () => graph.CreationCount == 0);
AddStep("display values", displayNewValues); AddStep("display values", displayNewValues);
AddWaitStep(5); AddWaitStep("wait some", 5);
AddUntilStep(() => graph.CreationCount == 1, "wait for creation count"); AddUntilStep("wait for creation count", () => graph.CreationCount == 1);
AddStep("Toggle Bar", () => progress.AllowSeeking = !progress.AllowSeeking); AddStep("Toggle Bar", () => progress.AllowSeeking = !progress.AllowSeeking);
AddWaitStep(5); AddWaitStep("wait some", 5);
AddUntilStep(() => graph.CreationCount == 1, "wait for creation count"); AddUntilStep("wait for creation count", () => graph.CreationCount == 1);
AddStep("Toggle Bar", () => progress.AllowSeeking = !progress.AllowSeeking); AddStep("Toggle Bar", () => progress.AllowSeeking = !progress.AllowSeeking);
AddWaitStep(5); AddWaitStep("wait some", 5);
AddUntilStep(() => graph.CreationCount == 1, "wait for creation count"); AddUntilStep("wait for creation count", () => graph.CreationCount == 1);
AddRepeatStep("New Values", displayNewValues, 5); AddRepeatStep("New Values", displayNewValues, 5);
AddWaitStep(5); AddWaitStep("wait some", 5);
AddAssert("ensure debounced", () => graph.CreationCount == 2); AddAssert("ensure debounced", () => graph.CreationCount == 2);
} }

View File

@ -36,18 +36,18 @@ namespace osu.Game.Tests.Visual
api.Queue(req); api.Queue(req);
AddStep("load null beatmap", () => beatmapBindable.Value = null); AddStep("load null beatmap", () => beatmapBindable.Value = null);
AddUntilStep(() => backgroundSprite.ChildCount == 1, "wait for cleanup..."); AddUntilStep("wait for cleanup...", () => backgroundSprite.ChildCount == 1);
AddStep("load imported beatmap", () => beatmapBindable.Value = imported.Beatmaps.First()); AddStep("load imported beatmap", () => beatmapBindable.Value = imported.Beatmaps.First());
AddUntilStep(() => backgroundSprite.ChildCount == 1, "wait for cleanup..."); AddUntilStep("wait for cleanup...", () => backgroundSprite.ChildCount == 1);
if (api.IsLoggedIn) if (api.IsLoggedIn)
{ {
AddUntilStep(() => req.Result != null, "wait for api response"); AddUntilStep("wait for api response", () => req.Result != null);
AddStep("load online beatmap", () => beatmapBindable.Value = new BeatmapInfo AddStep("load online beatmap", () => beatmapBindable.Value = new BeatmapInfo
{ {
BeatmapSet = req.Result?.ToBeatmapSet(rulesets) BeatmapSet = req.Result?.ToBeatmapSet(rulesets)
}); });
AddUntilStep(() => backgroundSprite.ChildCount == 1, "wait for cleanup..."); AddUntilStep("wait for cleanup...", () => backgroundSprite.ChildCount == 1);
} }
else else
{ {

View File

@ -108,7 +108,7 @@ namespace osu.Game.Tests.Visual
private void checkSupporterTag(bool isSupporter) private void checkSupporterTag(bool isSupporter)
{ {
AddUntilStep(() => profile.Header.User != null, "wait for load"); AddUntilStep("wait for load", () => profile.Header.User != null);
if (isSupporter) if (isSupporter)
AddAssert("is supporter", () => profile.Header.SupporterTag.Alpha == 1); AddAssert("is supporter", () => profile.Header.SupporterTag.Alpha == 1);
else else

View File

@ -1,12 +1,13 @@
// 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;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Screens; using osu.Framework.Screens;
using osu.Game.Graphics; using osu.Game.Graphics;
@ -25,16 +26,17 @@ namespace osu.Game.Screens.Menu
private SpriteIcon icon; private SpriteIcon icon;
private Color4 iconColour; private Color4 iconColour;
private LinkFlowContainer textFlow; private LinkFlowContainer textFlow;
private LinkFlowContainer supportFlow;
public override bool HideOverlaysOnEnter => true; public override bool HideOverlaysOnEnter => true;
public override OverlayActivation InitialOverlayActivationMode => OverlayActivation.Disabled; public override OverlayActivation InitialOverlayActivationMode => OverlayActivation.Disabled;
public override bool CursorVisible => false; public override bool CursorVisible => false;
private readonly List<Drawable> supporterDrawables = new List<Drawable>();
private Drawable heart; private Drawable heart;
private const float icon_y = -85; private const float icon_y = -85;
private const float icon_size = 30;
private readonly Bindable<User> currentUser = new Bindable<User>(); private readonly Bindable<User> currentUser = new Bindable<User>();
@ -53,19 +55,39 @@ namespace osu.Game.Screens.Menu
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
Icon = FontAwesome.fa_warning, Icon = FontAwesome.fa_warning,
Size = new Vector2(30), Size = new Vector2(icon_size),
Y = icon_y, Y = icon_y,
}, },
new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Y = icon_y + icon_size,
Anchor = Anchor.Centre,
Origin = Anchor.TopCentre,
Children = new Drawable[]
{
textFlow = new LinkFlowContainer textFlow = new LinkFlowContainer
{ {
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y, AutoSizeAxes = Axes.Y,
Padding = new MarginPadding(50),
TextAnchor = Anchor.TopCentre, TextAnchor = Anchor.TopCentre,
Y = -110, Anchor = Anchor.TopCentre,
Anchor = Anchor.Centre,
Origin = Anchor.TopCentre, Origin = Anchor.TopCentre,
Spacing = new Vector2(0, 2), Spacing = new Vector2(0, 2),
},
supportFlow = new LinkFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
TextAnchor = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Alpha = 0,
Spacing = new Vector2(0, 2),
},
}
} }
}; };
@ -88,28 +110,45 @@ namespace osu.Game.Screens.Menu
textFlow.NewParagraph(); textFlow.NewParagraph();
textFlow.NewParagraph(); textFlow.NewParagraph();
supporterDrawables.AddRange(textFlow.AddText("Consider becoming an ", format));
supporterDrawables.AddRange(textFlow.AddLink("osu!supporter", "https://osu.ppy.sh/home/support", creationParameters: format));
supporterDrawables.AddRange(textFlow.AddText(" to help support the game", format));
supporterDrawables.Add(heart = textFlow.AddIcon(FontAwesome.fa_heart, t =>
{
t.Padding = new MarginPadding { Left = 5 };
t.Font = t.Font.With(size: 12);
t.Colour = colours.Pink;
t.Origin = Anchor.Centre;
}).First());
iconColour = colours.Yellow; iconColour = colours.Yellow;
currentUser.BindTo(api.LocalUser); currentUser.BindTo(api.LocalUser);
currentUser.BindValueChanged(e => currentUser.BindValueChanged(e =>
{ {
supportFlow.Children.ForEach(d => d.FadeOut().Expire());
if (e.NewValue.IsSupporter) if (e.NewValue.IsSupporter)
supporterDrawables.ForEach(d => d.FadeOut(500, Easing.OutQuint).Expire()); {
supportFlow.AddText("Thank you for supporting osu!", format);
}
else
{
supportFlow.AddText("Consider becoming an ", format);
supportFlow.AddLink("osu!supporter", "https://osu.ppy.sh/home/support", creationParameters: format);
supportFlow.AddText(" to help support the game", format);
}
heart = supportFlow.AddIcon(FontAwesome.fa_heart, t =>
{
t.Padding = new MarginPadding { Left = 5 };
t.Font = t.Font.With(size: 12);
t.Origin = Anchor.Centre;
t.Colour = colours.Pink;
}).First();
if (IsLoaded)
animateHeart();
if (supportFlow.IsPresent)
supportFlow.FadeInFromZero(500);
}, true); }, true);
} }
private void animateHeart()
{
heart.FlashColour(Color4.White, 750, Easing.OutQuint).Loop();
}
protected override void LoadComplete() protected override void LoadComplete()
{ {
base.LoadComplete(); base.LoadComplete();
@ -128,7 +167,9 @@ namespace osu.Game.Screens.Menu
.MoveToY(icon_y, 160, Easing.InCirc) .MoveToY(icon_y, 160, Easing.InCirc)
.RotateTo(0, 160, Easing.InCirc); .RotateTo(0, 160, Easing.InCirc);
supporterDrawables.ForEach(d => d.FadeOut().Delay(2000).FadeIn(500)); supportFlow.FadeOut().Delay(2000).FadeIn(500);
animateHeart();
this this
.FadeInFromZero(500) .FadeInFromZero(500)
@ -136,8 +177,6 @@ namespace osu.Game.Screens.Menu
.FadeOut(250) .FadeOut(250)
.ScaleTo(0.9f, 250, Easing.InQuint) .ScaleTo(0.9f, 250, Easing.InQuint)
.Finally(d => this.Push(intro)); .Finally(d => this.Push(intro));
heart.FlashColour(Color4.White, 750, Easing.OutQuint).Loop();
} }
} }
} }

View File

@ -55,7 +55,7 @@ namespace osu.Game.Tests.Visual
AddStep(r.Name, () => p = loadPlayerFor(r)); AddStep(r.Name, () => p = loadPlayerFor(r));
AddCheckSteps(() => p); AddCheckSteps(() => p);
AddUntilStep(() => AddUntilStep("no leaked beatmaps", () =>
{ {
p = null; p = null;
@ -65,9 +65,9 @@ namespace osu.Game.Tests.Visual
workingWeakReferences.ForEachAlive(_ => count++); workingWeakReferences.ForEachAlive(_ => count++);
return count == 1; return count == 1;
}, "no leaked beatmaps"); });
AddUntilStep(() => AddUntilStep("no leaked players", () =>
{ {
GC.Collect(); GC.Collect();
GC.WaitForPendingFinalizers(); GC.WaitForPendingFinalizers();
@ -75,14 +75,14 @@ namespace osu.Game.Tests.Visual
playerWeakReferences.ForEachAlive(_ => count++); playerWeakReferences.ForEachAlive(_ => count++);
return count == 1; return count == 1;
}, "no leaked players"); });
} }
} }
} }
protected virtual void AddCheckSteps(Func<Player> player) protected virtual void AddCheckSteps(Func<Player> player)
{ {
AddUntilStep(() => player().IsLoaded, "player loaded"); AddUntilStep("player loaded", () => player().IsLoaded);
} }
protected virtual IBeatmap CreateBeatmap(Ruleset ruleset) => new TestBeatmap(ruleset.RulesetInfo); protected virtual IBeatmap CreateBeatmap(Ruleset ruleset) => new TestBeatmap(ruleset.RulesetInfo);

View File

@ -16,7 +16,7 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.1" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.1" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.128.0" /> <PackageReference Include="ppy.osu.Game.Resources" Version="2019.128.0" />
<PackageReference Include="ppy.osu.Framework" Version="2019.315.0" /> <PackageReference Include="ppy.osu.Framework" Version="2019.319.0" />
<PackageReference Include="SharpCompress" Version="0.22.0" /> <PackageReference Include="SharpCompress" Version="0.22.0" />
<PackageReference Include="NUnit" Version="3.11.0" /> <PackageReference Include="NUnit" Version="3.11.0" />
<PackageReference Include="SharpRaven" Version="2.4.0" /> <PackageReference Include="SharpRaven" Version="2.4.0" />

View File

@ -105,8 +105,8 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.1" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.1" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.128.0" /> <PackageReference Include="ppy.osu.Game.Resources" Version="2019.128.0" />
<PackageReference Include="ppy.osu.Framework" Version="2019.315.0" /> <PackageReference Include="ppy.osu.Framework" Version="2019.319.0" />
<PackageReference Include="ppy.osu.Framework.iOS" Version="2019.315.0" /> <PackageReference Include="ppy.osu.Framework.iOS" Version="2019.319.0" />
<PackageReference Include="SharpCompress" Version="0.22.0" /> <PackageReference Include="SharpCompress" Version="0.22.0" />
<PackageReference Include="NUnit" Version="3.11.0" /> <PackageReference Include="NUnit" Version="3.11.0" />
<PackageReference Include="SharpRaven" Version="2.4.0" /> <PackageReference Include="SharpRaven" Version="2.4.0" />