mirror of
https://github.com/ppy/osu.git
synced 2025-01-15 09:22:54 +08:00
Merge remote-tracking branch 'upstream/master' into user-status-wiring
This commit is contained in:
commit
5ac6bd8204
@ -26,9 +26,9 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="System.IO.Packaging" Version="4.5.0" />
|
<PackageReference Include="System.IO.Packaging" Version="4.5.0" />
|
||||||
<PackageReference Include="ppy.squirrel.windows" Version="1.9.0.3" />
|
<PackageReference Include="ppy.squirrel.windows" Version="1.9.0.4" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.3" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.4" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.2.3" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.2.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Resources">
|
<ItemGroup Label="Resources">
|
||||||
<EmbeddedResource Include="lazer.ico" />
|
<EmbeddedResource Include="lazer.ico" />
|
||||||
|
19
osu.Game.Rulesets.Osu.Tests/TestCaseOsuFlashlight.cs
Normal file
19
osu.Game.Rulesets.Osu.Tests/TestCaseOsuFlashlight.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
|
using osu.Game.Screens.Play;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Tests
|
||||||
|
{
|
||||||
|
public class TestCaseOsuFlashlight : TestCaseOsuPlayer
|
||||||
|
{
|
||||||
|
protected override Player CreatePlayer(Ruleset ruleset)
|
||||||
|
{
|
||||||
|
Mods.Value = new Mod[] { new OsuModAutoplay(), new OsuModFlashlight(), };
|
||||||
|
|
||||||
|
return base.CreatePlayer(ruleset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -353,6 +353,8 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
{
|
{
|
||||||
public new ScoreProcessor ScoreProcessor => base.ScoreProcessor;
|
public new ScoreProcessor ScoreProcessor => base.ScoreProcessor;
|
||||||
|
|
||||||
|
protected override bool PauseOnFocusLost => false;
|
||||||
|
|
||||||
public ScoreAccessibleReplayPlayer(Score score)
|
public ScoreAccessibleReplayPlayer(Score score)
|
||||||
: base(score, false, false)
|
: base(score, false, false)
|
||||||
{
|
{
|
||||||
|
@ -1,23 +1,37 @@
|
|||||||
// 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.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Mods
|
namespace osu.Game.Rulesets.Osu.Mods
|
||||||
{
|
{
|
||||||
public class OsuModFlashlight : ModFlashlight<OsuHitObject>
|
public class OsuModFlashlight : ModFlashlight<OsuHitObject>, IApplicableToDrawableHitObjects
|
||||||
{
|
{
|
||||||
public override double ScoreMultiplier => 1.12;
|
public override double ScoreMultiplier => 1.12;
|
||||||
|
|
||||||
private const float default_flashlight_size = 180;
|
private const float default_flashlight_size = 180;
|
||||||
|
|
||||||
public override Flashlight CreateFlashlight() => new OsuFlashlight();
|
private OsuFlashlight flashlight;
|
||||||
|
|
||||||
|
public override Flashlight CreateFlashlight() => flashlight = new OsuFlashlight();
|
||||||
|
|
||||||
|
public void ApplyToDrawableHitObjects(IEnumerable<DrawableHitObject> drawables)
|
||||||
|
{
|
||||||
|
foreach (var s in drawables.OfType<DrawableSlider>())
|
||||||
|
{
|
||||||
|
s.Tracking.ValueChanged += flashlight.OnSliderTrackingChange;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class OsuFlashlight : Flashlight, IRequireHighFrequencyMousePosition
|
private class OsuFlashlight : Flashlight, IRequireHighFrequencyMousePosition
|
||||||
{
|
{
|
||||||
@ -26,6 +40,12 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
FlashlightSize = new Vector2(0, getSizeFor(0));
|
FlashlightSize = new Vector2(0, getSizeFor(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void OnSliderTrackingChange(ValueChangedEvent<bool> e)
|
||||||
|
{
|
||||||
|
// If a slider is in a tracking state, a further dim should be applied to the (remaining) visible portion of the playfield over a brief duration.
|
||||||
|
this.TransformTo(nameof(FlashlightDim), e.NewValue ? 0.8f : 0.0f, 50);
|
||||||
|
}
|
||||||
|
|
||||||
protected override bool OnMouseMove(MouseMoveEvent e)
|
protected override bool OnMouseMove(MouseMoveEvent e)
|
||||||
{
|
{
|
||||||
FlashlightPosition = e.MousePosition;
|
FlashlightPosition = e.MousePosition;
|
||||||
|
@ -44,7 +44,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
{
|
{
|
||||||
if (repeatPoint.StartTime <= Time.Current)
|
if (repeatPoint.StartTime <= Time.Current)
|
||||||
ApplyResult(r => r.Type = drawableSlider.Tracking ? HitResult.Great : HitResult.Miss);
|
ApplyResult(r => r.Type = drawableSlider.Tracking.Value ? HitResult.Great : HitResult.Miss);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdatePreemptState()
|
protected override void UpdatePreemptState()
|
||||||
|
@ -130,13 +130,13 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Tracking;
|
public readonly Bindable<bool> Tracking = new Bindable<bool>();
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
Tracking = Ball.Tracking;
|
Tracking.Value = Ball.Tracking;
|
||||||
|
|
||||||
double completionProgress = MathHelper.Clamp((Time.Current - slider.StartTime) / slider.Duration, 0, 1);
|
double completionProgress = MathHelper.Clamp((Time.Current - slider.StartTime) / slider.Duration, 0, 1);
|
||||||
|
|
||||||
|
@ -328,7 +328,7 @@ namespace osu.Game.Tests.Visual.Background
|
|||||||
public bool IsBlurCorrect() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2(BACKGROUND_BLUR);
|
public bool IsBlurCorrect() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2(BACKGROUND_BLUR);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestPlayer : Player
|
private class TestPlayer : Visual.TestPlayer
|
||||||
{
|
{
|
||||||
protected override BackgroundScreen CreateBackground() => new FadeAccessibleBackground(Beatmap.Value);
|
protected override BackgroundScreen CreateBackground() => new FadeAccessibleBackground(Beatmap.Value);
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ using osu.Framework.Graphics.Containers;
|
|||||||
using osu.Framework.Graphics.Primitives;
|
using osu.Framework.Graphics.Primitives;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.MathUtils;
|
using osu.Framework.MathUtils;
|
||||||
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Cursor;
|
using osu.Game.Graphics.Cursor;
|
||||||
using osu.Game.Screens.Edit.Compose.Components.Timeline;
|
using osu.Game.Screens.Edit.Compose.Components.Timeline;
|
||||||
@ -18,38 +19,49 @@ namespace osu.Game.Tests.Visual.Editor
|
|||||||
{
|
{
|
||||||
public class TestCaseZoomableScrollContainer : ManualInputManagerTestCase
|
public class TestCaseZoomableScrollContainer : ManualInputManagerTestCase
|
||||||
{
|
{
|
||||||
private readonly ZoomableScrollContainer scrollContainer;
|
private ZoomableScrollContainer scrollContainer;
|
||||||
private readonly Drawable innerBox;
|
private Drawable innerBox;
|
||||||
|
|
||||||
public TestCaseZoomableScrollContainer()
|
[SetUpSteps]
|
||||||
|
public void SetUpSteps()
|
||||||
{
|
{
|
||||||
Children = new Drawable[]
|
AddStep("Add new scroll container", () =>
|
||||||
{
|
{
|
||||||
new Container
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
new Container
|
||||||
Origin = Anchor.Centre,
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
Height = 250,
|
|
||||||
Width = 0.75f,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
{
|
||||||
new Box
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Height = 250,
|
||||||
|
Width = 0.75f,
|
||||||
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
new Box
|
||||||
Colour = OsuColour.Gray(30)
|
{
|
||||||
},
|
RelativeSizeAxes = Axes.Both,
|
||||||
scrollContainer = new ZoomableScrollContainer { RelativeSizeAxes = Axes.Both }
|
Colour = OsuColour.Gray(30)
|
||||||
}
|
},
|
||||||
},
|
scrollContainer = new ZoomableScrollContainer { RelativeSizeAxes = Axes.Both }
|
||||||
new MenuCursor()
|
}
|
||||||
};
|
},
|
||||||
|
new MenuCursor()
|
||||||
|
};
|
||||||
|
|
||||||
scrollContainer.Add(innerBox = new Box
|
scrollContainer.Add(innerBox = new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = ColourInfo.GradientHorizontal(new Color4(0.8f, 0.6f, 0.4f, 1f), new Color4(0.4f, 0.6f, 0.8f, 1f))
|
Colour = ColourInfo.GradientHorizontal(new Color4(0.8f, 0.6f, 0.4f, 1f), new Color4(0.4f, 0.6f, 0.8f, 1f))
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
AddUntilStep("Scroll container is loaded", () => scrollContainer.LoadState >= LoadState.Loaded);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestWidthInitialization()
|
||||||
|
{
|
||||||
|
AddAssert("Inner container width was initialized", () => innerBox.DrawWidth > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -24,7 +24,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
AddUntilStep("key counter counted keys", () => ((ScoreAccessiblePlayer)Player).HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses > 0));
|
AddUntilStep("key counter counted keys", () => ((ScoreAccessiblePlayer)Player).HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses > 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ScoreAccessiblePlayer : Player
|
private class ScoreAccessiblePlayer : TestPlayer
|
||||||
{
|
{
|
||||||
public new ScoreProcessor ScoreProcessor => base.ScoreProcessor;
|
public new ScoreProcessor ScoreProcessor => base.ScoreProcessor;
|
||||||
public new HUDOverlay HUDOverlay => base.HUDOverlay;
|
public new HUDOverlay HUDOverlay => base.HUDOverlay;
|
||||||
|
@ -73,6 +73,26 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
checkFrameCount(2);
|
checkFrameCount(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestInitialSeekWithGameplayStart()
|
||||||
|
{
|
||||||
|
seekManualTo(1000);
|
||||||
|
createStabilityContainer(30000);
|
||||||
|
|
||||||
|
confirmSeek(1000);
|
||||||
|
checkFrameCount(0);
|
||||||
|
|
||||||
|
seekManualTo(10000);
|
||||||
|
confirmSeek(10000);
|
||||||
|
|
||||||
|
checkFrameCount(1);
|
||||||
|
|
||||||
|
seekManualTo(130000);
|
||||||
|
confirmSeek(130000);
|
||||||
|
|
||||||
|
checkFrameCount(6002);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestInitialSeek()
|
public void TestInitialSeek()
|
||||||
{
|
{
|
||||||
@ -83,7 +103,11 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
checkFrameCount(0);
|
checkFrameCount(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createStabilityContainer() => AddStep("create container", () => mainContainer.Child = new FrameStabilityContainer().WithChild(consumer = new ClockConsumingChild()));
|
private const int max_frames_catchup = 50;
|
||||||
|
|
||||||
|
private void createStabilityContainer(double gameplayStartTime = double.MinValue) => AddStep("create container", () =>
|
||||||
|
mainContainer.Child = new FrameStabilityContainer(gameplayStartTime) { MaxCatchUpFrames = max_frames_catchup }
|
||||||
|
.WithChild(consumer = new ClockConsumingChild()));
|
||||||
|
|
||||||
private void seekManualTo(double time) => AddStep($"seek manual clock to {time}", () => manualClock.CurrentTime = time);
|
private void seekManualTo(double time) => AddStep($"seek manual clock to {time}", () => manualClock.CurrentTime = time);
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ using NUnit.Framework;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.Cursor;
|
using osu.Game.Graphics.Cursor;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
@ -31,6 +32,14 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
base.Content.Add(content = new MenuCursorContainer { RelativeSizeAxes = Axes.Both });
|
base.Content.Add(content = new MenuCursorContainer { RelativeSizeAxes = Axes.Both });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[SetUpSteps]
|
||||||
|
public override void SetUpSteps()
|
||||||
|
{
|
||||||
|
base.SetUpSteps();
|
||||||
|
AddStep("resume player", () => Player.GameplayClockContainer.Start());
|
||||||
|
confirmClockRunning(true);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestPauseResume()
|
public void TestPauseResume()
|
||||||
{
|
{
|
||||||
@ -157,6 +166,8 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
private void confirmPaused()
|
private void confirmPaused()
|
||||||
{
|
{
|
||||||
confirmClockRunning(false);
|
confirmClockRunning(false);
|
||||||
|
AddAssert("player not exited", () => Player.IsCurrentScreen());
|
||||||
|
AddAssert("player not failed", () => !Player.HasFailed);
|
||||||
AddAssert("pause overlay shown", () => Player.PauseOverlayVisible);
|
AddAssert("pause overlay shown", () => Player.PauseOverlayVisible);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,7 +195,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
protected override Player CreatePlayer(Ruleset ruleset) => new PausePlayer();
|
protected override Player CreatePlayer(Ruleset ruleset) => new PausePlayer();
|
||||||
|
|
||||||
protected class PausePlayer : Player
|
protected class PausePlayer : TestPlayer
|
||||||
{
|
{
|
||||||
public new GameplayClockContainer GameplayClockContainer => base.GameplayClockContainer;
|
public new GameplayClockContainer GameplayClockContainer => base.GameplayClockContainer;
|
||||||
|
|
||||||
@ -196,10 +207,10 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
public bool PauseOverlayVisible => PauseOverlay.State == Visibility.Visible;
|
public bool PauseOverlayVisible => PauseOverlay.State == Visibility.Visible;
|
||||||
|
|
||||||
protected override void LoadComplete()
|
public override void OnEntering(IScreen last)
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.OnEntering(last);
|
||||||
HUDOverlay.HoldToQuit.PauseOnFocusLost = false;
|
GameplayClockContainer.Stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@ -34,20 +35,20 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestLoadContinuation()
|
public void TestLoadContinuation()
|
||||||
{
|
{
|
||||||
AddStep("load dummy beatmap", () => stack.Push(loader = new PlayerLoader(() => new Player(false, false))));
|
Player player = null;
|
||||||
|
SlowLoadPlayer slowPlayer = null;
|
||||||
|
|
||||||
|
AddStep("load dummy beatmap", () => stack.Push(loader = new PlayerLoader(() => player = new TestPlayer(false, false))));
|
||||||
AddUntilStep("wait for current", () => loader.IsCurrentScreen());
|
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("wait for no longer current", () => !loader.IsCurrentScreen());
|
AddUntilStep("wait for player to be current", () => player.IsCurrentScreen());
|
||||||
AddStep("load slow dummy beatmap", () =>
|
AddStep("load slow dummy beatmap", () =>
|
||||||
{
|
{
|
||||||
SlowLoadPlayer slow = null;
|
stack.Push(loader = new PlayerLoader(() => slowPlayer = new SlowLoadPlayer(false, false)));
|
||||||
|
Scheduler.AddDelayed(() => slowPlayer.AllowLoad.Set(), 5000);
|
||||||
stack.Push(loader = new PlayerLoader(() => slow = new SlowLoadPlayer(false, false)));
|
|
||||||
|
|
||||||
Scheduler.AddDelayed(() => slow.Ready = true, 5000);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
AddUntilStep("wait for no longer current", () => !loader.IsCurrentScreen());
|
AddUntilStep("wait for player to be current", () => slowPlayer.IsCurrentScreen());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -101,19 +102,19 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank;
|
public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestPlayer : Player
|
private class TestPlayer : Visual.TestPlayer
|
||||||
{
|
{
|
||||||
public new Bindable<IReadOnlyList<Mod>> Mods => base.Mods;
|
public new Bindable<IReadOnlyList<Mod>> Mods => base.Mods;
|
||||||
|
|
||||||
public TestPlayer()
|
public TestPlayer(bool allowPause = true, bool showResults = true)
|
||||||
: base(false, false)
|
: base(allowPause, showResults)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected class SlowLoadPlayer : Player
|
protected class SlowLoadPlayer : Visual.TestPlayer
|
||||||
{
|
{
|
||||||
public bool Ready;
|
public readonly ManualResetEventSlim AllowLoad = new ManualResetEventSlim(false);
|
||||||
|
|
||||||
public SlowLoadPlayer(bool allowPause = true, bool showResults = true)
|
public SlowLoadPlayer(bool allowPause = true, bool showResults = true)
|
||||||
: base(allowPause, showResults)
|
: base(allowPause, showResults)
|
||||||
@ -123,8 +124,8 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
while (!Ready)
|
if (!AllowLoad.Wait(TimeSpan.FromSeconds(10)))
|
||||||
Thread.Sleep(1);
|
throw new TimeoutException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,8 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
public new ScoreProcessor ScoreProcessor => base.ScoreProcessor;
|
public new ScoreProcessor ScoreProcessor => base.ScoreProcessor;
|
||||||
public new HUDOverlay HUDOverlay => base.HUDOverlay;
|
public new HUDOverlay HUDOverlay => base.HUDOverlay;
|
||||||
|
|
||||||
|
protected override bool PauseOnFocusLost => false;
|
||||||
|
|
||||||
public ScoreAccessibleReplayPlayer(Score score)
|
public ScoreAccessibleReplayPlayer(Score score)
|
||||||
: base(score)
|
: base(score)
|
||||||
{
|
{
|
||||||
|
@ -1,22 +1,27 @@
|
|||||||
// 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.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.Drawables;
|
using osu.Game.Beatmaps.Drawables;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Online.API.Requests;
|
using osu.Game.Online.API.Requests;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Tests.Beatmaps.IO;
|
using osu.Game.Tests.Beatmaps.IO;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.UserInterface
|
namespace osu.Game.Tests.Visual.UserInterface
|
||||||
{
|
{
|
||||||
public class TestCaseUpdateableBeatmapBackgroundSprite : OsuTestCase
|
public class TestCaseUpdateableBeatmapBackgroundSprite : OsuTestCase
|
||||||
{
|
{
|
||||||
private TestUpdateableBeatmapBackgroundSprite backgroundSprite;
|
private BeatmapSetInfo testBeatmap;
|
||||||
|
private IAPIProvider api;
|
||||||
|
private RulesetStore rulesets;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private BeatmapManager beatmaps { get; set; }
|
private BeatmapManager beatmaps { get; set; }
|
||||||
@ -24,40 +29,119 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuGameBase osu, IAPIProvider api, RulesetStore rulesets)
|
private void load(OsuGameBase osu, IAPIProvider api, RulesetStore rulesets)
|
||||||
{
|
{
|
||||||
Bindable<BeatmapInfo> beatmapBindable = new Bindable<BeatmapInfo>();
|
this.api = api;
|
||||||
|
this.rulesets = rulesets;
|
||||||
|
|
||||||
var imported = ImportBeatmapTest.LoadOszIntoOsu(osu);
|
testBeatmap = ImportBeatmapTest.LoadOszIntoOsu(osu);
|
||||||
|
}
|
||||||
|
|
||||||
Child = backgroundSprite = new TestUpdateableBeatmapBackgroundSprite { RelativeSizeAxes = Axes.Both };
|
[Test]
|
||||||
|
public void TestNullBeatmap()
|
||||||
|
{
|
||||||
|
TestUpdateableBeatmapBackgroundSprite background = null;
|
||||||
|
|
||||||
backgroundSprite.Beatmap.BindTo(beatmapBindable);
|
AddStep("load null beatmap", () => Child = background = new TestUpdateableBeatmapBackgroundSprite { RelativeSizeAxes = Axes.Both });
|
||||||
|
AddUntilStep("wait for load", () => background.ContentLoaded);
|
||||||
|
}
|
||||||
|
|
||||||
var req = new GetBeatmapSetRequest(1);
|
[Test]
|
||||||
api.Queue(req);
|
public void TestLocalBeatmap()
|
||||||
|
{
|
||||||
|
TestUpdateableBeatmapBackgroundSprite background = null;
|
||||||
|
|
||||||
AddStep("load null beatmap", () => beatmapBindable.Value = null);
|
AddStep("load local beatmap", () =>
|
||||||
AddUntilStep("wait for cleanup...", () => backgroundSprite.ChildCount == 1);
|
{
|
||||||
AddStep("load imported beatmap", () => beatmapBindable.Value = imported.Beatmaps.First());
|
Child = background = new TestUpdateableBeatmapBackgroundSprite
|
||||||
AddUntilStep("wait for cleanup...", () => backgroundSprite.ChildCount == 1);
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Beatmap = { Value = testBeatmap.Beatmaps.First() }
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
AddUntilStep("wait for load", () => background.ContentLoaded);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestOnlineBeatmap()
|
||||||
|
{
|
||||||
if (api.IsLoggedIn)
|
if (api.IsLoggedIn)
|
||||||
{
|
{
|
||||||
|
var req = new GetBeatmapSetRequest(1);
|
||||||
|
api.Queue(req);
|
||||||
|
|
||||||
AddUntilStep("wait for api response", () => req.Result != null);
|
AddUntilStep("wait for api response", () => req.Result != null);
|
||||||
AddStep("load online beatmap", () => beatmapBindable.Value = new BeatmapInfo
|
|
||||||
|
TestUpdateableBeatmapBackgroundSprite background = null;
|
||||||
|
|
||||||
|
AddStep("load online beatmap", () =>
|
||||||
{
|
{
|
||||||
BeatmapSet = req.Result?.ToBeatmapSet(rulesets)
|
Child = background = new TestUpdateableBeatmapBackgroundSprite
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Beatmap = { Value = new BeatmapInfo { BeatmapSet = req.Result?.ToBeatmapSet(rulesets) } }
|
||||||
|
};
|
||||||
});
|
});
|
||||||
AddUntilStep("wait for cleanup...", () => backgroundSprite.ChildCount == 1);
|
|
||||||
|
AddUntilStep("wait for load", () => background.ContentLoaded);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
AddStep("online (login first)", () => { });
|
AddStep("online (login first)", () => { });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestUnloadAndReload()
|
||||||
|
{
|
||||||
|
var backgrounds = new List<TestUpdateableBeatmapBackgroundSprite>();
|
||||||
|
ScrollContainer scrollContainer = null;
|
||||||
|
|
||||||
|
AddStep("create backgrounds hierarchy", () =>
|
||||||
|
{
|
||||||
|
FillFlowContainer backgroundFlow;
|
||||||
|
|
||||||
|
Child = scrollContainer = new ScrollContainer
|
||||||
|
{
|
||||||
|
Size = new Vector2(500),
|
||||||
|
Child = backgroundFlow = new FillFlowContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
Spacing = new Vector2(10),
|
||||||
|
Padding = new MarginPadding { Bottom = 550 }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i < 25; i++)
|
||||||
|
{
|
||||||
|
var background = new TestUpdateableBeatmapBackgroundSprite { RelativeSizeAxes = Axes.Both };
|
||||||
|
|
||||||
|
if (i % 2 == 0)
|
||||||
|
background.Beatmap.Value = testBeatmap.Beatmaps.First();
|
||||||
|
|
||||||
|
backgroundFlow.Add(new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Height = 100,
|
||||||
|
Masking = true,
|
||||||
|
Child = background
|
||||||
|
});
|
||||||
|
|
||||||
|
backgrounds.Add(background);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var loadedBackgrounds = backgrounds.Where(b => b.ContentLoaded);
|
||||||
|
|
||||||
|
AddUntilStep("some loaded", () => loadedBackgrounds.Any());
|
||||||
|
AddStep("scroll to bottom", () => scrollContainer.ScrollToEnd());
|
||||||
|
AddUntilStep("all unloaded", () => !loadedBackgrounds.Any());
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestUpdateableBeatmapBackgroundSprite : UpdateableBeatmapBackgroundSprite
|
private class TestUpdateableBeatmapBackgroundSprite : UpdateableBeatmapBackgroundSprite
|
||||||
{
|
{
|
||||||
public int ChildCount => InternalChildren.Count;
|
protected override double UnloadDelay => 2000;
|
||||||
|
|
||||||
|
public bool ContentLoaded => ((DelayedLoadUnloadWrapper)InternalChildren.LastOrDefault())?.Content?.IsLoaded ?? false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,6 @@ namespace osu.Game.Beatmaps
|
|||||||
protected override IQueryable<BeatmapSetInfo> AddIncludesForDeletion(IQueryable<BeatmapSetInfo> query) =>
|
protected override IQueryable<BeatmapSetInfo> AddIncludesForDeletion(IQueryable<BeatmapSetInfo> query) =>
|
||||||
base.AddIncludesForDeletion(query)
|
base.AddIncludesForDeletion(query)
|
||||||
.Include(s => s.Metadata)
|
.Include(s => s.Metadata)
|
||||||
.Include(s => s.Beatmaps).ThenInclude(b => b.Scores)
|
|
||||||
.Include(s => s.Beatmaps).ThenInclude(b => b.BaseDifficulty)
|
.Include(s => s.Beatmaps).ThenInclude(b => b.BaseDifficulty)
|
||||||
.Include(s => s.Beatmaps).ThenInclude(b => b.Metadata);
|
.Include(s => s.Beatmaps).ThenInclude(b => b.Metadata);
|
||||||
|
|
||||||
|
@ -26,6 +26,11 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
this.beatmapSetCoverType = beatmapSetCoverType;
|
this.beatmapSetCoverType = beatmapSetCoverType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Delay before the background is unloaded while off-screen.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual double UnloadDelay => 10000;
|
||||||
|
|
||||||
private BeatmapInfo lastModel;
|
private BeatmapInfo lastModel;
|
||||||
|
|
||||||
protected override DelayedLoadWrapper CreateDelayedLoadWrapper(Drawable content, double timeBeforeLoad)
|
protected override DelayedLoadWrapper CreateDelayedLoadWrapper(Drawable content, double timeBeforeLoad)
|
||||||
@ -34,13 +39,13 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
{
|
{
|
||||||
// If DelayedLoadUnloadWrapper is attempting to RELOAD the same content (Beatmap), that means that it was
|
// If DelayedLoadUnloadWrapper is attempting to RELOAD the same content (Beatmap), that means that it was
|
||||||
// previously UNLOADED and thus its children have been disposed of, so we need to recreate them here.
|
// previously UNLOADED and thus its children have been disposed of, so we need to recreate them here.
|
||||||
if (lastModel == Beatmap.Value && Beatmap.Value != null)
|
if (lastModel == Beatmap.Value)
|
||||||
return CreateDrawable(Beatmap.Value);
|
return CreateDrawable(Beatmap.Value);
|
||||||
|
|
||||||
// If the model has changed since the previous unload (or if there was no load), then we can safely use the given content
|
// If the model has changed since the previous unload (or if there was no load), then we can safely use the given content
|
||||||
lastModel = Beatmap.Value;
|
lastModel = Beatmap.Value;
|
||||||
return content;
|
return content;
|
||||||
}, timeBeforeLoad, 10000);
|
}, timeBeforeLoad, UnloadDelay);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Drawable CreateDrawable(BeatmapInfo model)
|
protected override Drawable CreateDrawable(BeatmapInfo model)
|
||||||
|
@ -29,5 +29,12 @@ namespace osu.Game.Beatmaps.Timing
|
|||||||
/// Whether the break has any effect. Breaks that are too short are culled before they are added to the beatmap.
|
/// Whether the break has any effect. Breaks that are too short are culled before they are added to the beatmap.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool HasEffect => Duration >= MIN_BREAK_DURATION;
|
public bool HasEffect => Duration >= MIN_BREAK_DURATION;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether this break contains a specified time.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="time">The time to check in milliseconds.</param>
|
||||||
|
/// <returns>Whether the time falls within this <see cref="BreakPeriod"/>.</returns>
|
||||||
|
public bool Contains(double time) => time >= StartTime && time <= EndTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -385,7 +385,7 @@ namespace osu.Game.Database
|
|||||||
/// Delete multiple items.
|
/// Delete multiple items.
|
||||||
/// This will post notifications tracking progress.
|
/// This will post notifications tracking progress.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Delete(List<TModel> items)
|
public void Delete(List<TModel> items, bool silent = false)
|
||||||
{
|
{
|
||||||
if (items.Count == 0) return;
|
if (items.Count == 0) return;
|
||||||
|
|
||||||
@ -396,7 +396,8 @@ namespace osu.Game.Database
|
|||||||
State = ProgressNotificationState.Active,
|
State = ProgressNotificationState.Active,
|
||||||
};
|
};
|
||||||
|
|
||||||
PostNotification?.Invoke(notification);
|
if (!silent)
|
||||||
|
PostNotification?.Invoke(notification);
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
@ -423,7 +424,7 @@ namespace osu.Game.Database
|
|||||||
/// Restore multiple items that were previously deleted.
|
/// Restore multiple items that were previously deleted.
|
||||||
/// This will post notifications tracking progress.
|
/// This will post notifications tracking progress.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Undelete(List<TModel> items)
|
public void Undelete(List<TModel> items, bool silent = false)
|
||||||
{
|
{
|
||||||
if (!items.Any()) return;
|
if (!items.Any()) return;
|
||||||
|
|
||||||
@ -434,7 +435,8 @@ namespace osu.Game.Database
|
|||||||
State = ProgressNotificationState.Active,
|
State = ProgressNotificationState.Active,
|
||||||
};
|
};
|
||||||
|
|
||||||
PostNotification?.Invoke(notification);
|
if (!silent)
|
||||||
|
PostNotification?.Invoke(notification);
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
|
@ -77,13 +77,13 @@ namespace osu.Game.Online.API
|
|||||||
/// <param name="component"></param>
|
/// <param name="component"></param>
|
||||||
public void Register(IOnlineComponent component)
|
public void Register(IOnlineComponent component)
|
||||||
{
|
{
|
||||||
Scheduler.Add(delegate { components.Add(component); });
|
Schedule(() => components.Add(component));
|
||||||
component.APIStateChanged(this, state);
|
component.APIStateChanged(this, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Unregister(IOnlineComponent component)
|
public void Unregister(IOnlineComponent component)
|
||||||
{
|
{
|
||||||
Scheduler.Add(delegate { components.Remove(component); });
|
Schedule(() => components.Remove(component));
|
||||||
}
|
}
|
||||||
|
|
||||||
public string AccessToken => authentication.RequestAccessToken();
|
public string AccessToken => authentication.RequestAccessToken();
|
||||||
@ -274,7 +274,7 @@ namespace osu.Game.Online.API
|
|||||||
state = value;
|
state = value;
|
||||||
|
|
||||||
log.Add($@"We just went {state}!");
|
log.Add($@"We just went {state}!");
|
||||||
Scheduler.Add(delegate
|
Schedule(() =>
|
||||||
{
|
{
|
||||||
components.ForEach(c => c.APIStateChanged(this, state));
|
components.ForEach(c => c.APIStateChanged(this, state));
|
||||||
OnStateChange?.Invoke(oldState, state);
|
OnStateChange?.Invoke(oldState, state);
|
||||||
@ -352,9 +352,13 @@ namespace osu.Game.Online.API
|
|||||||
public void Logout()
|
public void Logout()
|
||||||
{
|
{
|
||||||
flushQueue();
|
flushQueue();
|
||||||
|
|
||||||
password = null;
|
password = null;
|
||||||
authentication.Clear();
|
authentication.Clear();
|
||||||
LocalUser.Value = createGuestUser();
|
|
||||||
|
// Scheduled prior to state change such that the state changed event is invoked with the correct user present
|
||||||
|
Schedule(() => LocalUser.Value = createGuestUser());
|
||||||
|
|
||||||
State = APIState.Offline;
|
State = APIState.Offline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,8 +155,23 @@ namespace osu.Game
|
|||||||
|
|
||||||
dependencies.Cache(RulesetStore = new RulesetStore(contextFactory));
|
dependencies.Cache(RulesetStore = new RulesetStore(contextFactory));
|
||||||
dependencies.Cache(FileStore = new FileStore(contextFactory, Host.Storage));
|
dependencies.Cache(FileStore = new FileStore(contextFactory, Host.Storage));
|
||||||
|
|
||||||
|
// ordering is important here to ensure foreign keys rules are not broken in ModelStore.Cleanup()
|
||||||
|
dependencies.Cache(ScoreManager = new ScoreManager(RulesetStore, () => BeatmapManager, Host.Storage, contextFactory, Host));
|
||||||
dependencies.Cache(BeatmapManager = new BeatmapManager(Host.Storage, contextFactory, RulesetStore, API, Audio, Host, defaultBeatmap));
|
dependencies.Cache(BeatmapManager = new BeatmapManager(Host.Storage, contextFactory, RulesetStore, API, Audio, Host, defaultBeatmap));
|
||||||
dependencies.Cache(ScoreManager = new ScoreManager(RulesetStore, BeatmapManager, Host.Storage, contextFactory, Host));
|
|
||||||
|
// this should likely be moved to ArchiveModelManager when another case appers where it is necessary
|
||||||
|
// to have inter-dependent model managers. this could be obtained with an IHasForeign<T> interface to
|
||||||
|
// allow lookups to be done on the child (ScoreManager in this case) to perform the cascading delete.
|
||||||
|
List<ScoreInfo> getBeatmapScores(BeatmapSetInfo set)
|
||||||
|
{
|
||||||
|
var beatmapIds = BeatmapManager.QueryBeatmaps(b => b.BeatmapSetInfoID == set.ID).Select(b => b.ID).ToList();
|
||||||
|
return ScoreManager.QueryScores(s => beatmapIds.Contains(s.Beatmap.ID)).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
BeatmapManager.ItemRemoved += i => ScoreManager.Delete(getBeatmapScores(i), true);
|
||||||
|
BeatmapManager.ItemAdded += (i, existing) => ScoreManager.Undelete(getBeatmapScores(i), true);
|
||||||
|
|
||||||
dependencies.Cache(KeyBindingStore = new KeyBindingStore(contextFactory, RulesetStore));
|
dependencies.Cache(KeyBindingStore = new KeyBindingStore(contextFactory, RulesetStore));
|
||||||
dependencies.Cache(SettingsStore = new SettingsStore(contextFactory));
|
dependencies.Cache(SettingsStore = new SettingsStore(contextFactory));
|
||||||
dependencies.Cache(RulesetConfigCache = new RulesetConfigCache(SettingsStore));
|
dependencies.Cache(RulesetConfigCache = new RulesetConfigCache(SettingsStore));
|
||||||
|
@ -4,14 +4,12 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Extensions;
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Sprites;
|
|
||||||
using osu.Framework.Graphics.Textures;
|
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Online.Leaderboards;
|
||||||
using osu.Game.Overlays.Profile.Header.Components;
|
using osu.Game.Overlays.Profile.Header.Components;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
@ -185,8 +183,6 @@ namespace osu.Game.Overlays.Profile.Header
|
|||||||
|
|
||||||
private class ScoreRankInfo : CompositeDrawable
|
private class ScoreRankInfo : CompositeDrawable
|
||||||
{
|
{
|
||||||
private readonly ScoreRank rank;
|
|
||||||
private readonly Sprite rankSprite;
|
|
||||||
private readonly OsuSpriteText rankCount;
|
private readonly OsuSpriteText rankCount;
|
||||||
|
|
||||||
public int RankCount
|
public int RankCount
|
||||||
@ -196,8 +192,6 @@ namespace osu.Game.Overlays.Profile.Header
|
|||||||
|
|
||||||
public ScoreRankInfo(ScoreRank rank)
|
public ScoreRankInfo(ScoreRank rank)
|
||||||
{
|
{
|
||||||
this.rank = rank;
|
|
||||||
|
|
||||||
AutoSizeAxes = Axes.Both;
|
AutoSizeAxes = Axes.Both;
|
||||||
InternalChild = new FillFlowContainer
|
InternalChild = new FillFlowContainer
|
||||||
{
|
{
|
||||||
@ -206,10 +200,10 @@ namespace osu.Game.Overlays.Profile.Header
|
|||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
rankSprite = new Sprite
|
new DrawableRank(rank)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.X,
|
||||||
FillMode = FillMode.Fit
|
Height = 30,
|
||||||
},
|
},
|
||||||
rankCount = new OsuSpriteText
|
rankCount = new OsuSpriteText
|
||||||
{
|
{
|
||||||
@ -220,12 +214,6 @@ namespace osu.Game.Overlays.Profile.Header
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(TextureStore textures)
|
|
||||||
{
|
|
||||||
rankSprite.Texture = textures.Get($"Grades/{rank.GetDescription()}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,14 +85,15 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
|
|
||||||
Combo.ValueChanged += OnComboChange;
|
Combo.ValueChanged += OnComboChange;
|
||||||
|
|
||||||
this.FadeInFromZero(FLASHLIGHT_FADE_DURATION);
|
using (BeginAbsoluteSequence(0))
|
||||||
|
|
||||||
foreach (var breakPeriod in Breaks)
|
|
||||||
{
|
{
|
||||||
if (breakPeriod.Duration < FLASHLIGHT_FADE_DURATION * 2) continue;
|
foreach (var breakPeriod in Breaks)
|
||||||
|
{
|
||||||
|
if (breakPeriod.Duration < FLASHLIGHT_FADE_DURATION * 2) continue;
|
||||||
|
|
||||||
this.Delay(breakPeriod.StartTime + FLASHLIGHT_FADE_DURATION).FadeOutFromOne(FLASHLIGHT_FADE_DURATION);
|
this.Delay(breakPeriod.StartTime + FLASHLIGHT_FADE_DURATION).FadeOutFromOne(FLASHLIGHT_FADE_DURATION);
|
||||||
this.Delay(breakPeriod.EndTime - FLASHLIGHT_FADE_DURATION).FadeInFromZero(FLASHLIGHT_FADE_DURATION);
|
this.Delay(breakPeriod.EndTime - FLASHLIGHT_FADE_DURATION).FadeInFromZero(FLASHLIGHT_FADE_DURATION);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,6 +129,20 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private float flashlightDim;
|
||||||
|
|
||||||
|
public float FlashlightDim
|
||||||
|
{
|
||||||
|
get => flashlightDim;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (flashlightDim == value) return;
|
||||||
|
|
||||||
|
flashlightDim = value;
|
||||||
|
Invalidate(Invalidation.DrawNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class FlashlightDrawNode : DrawNode
|
private class FlashlightDrawNode : DrawNode
|
||||||
{
|
{
|
||||||
protected new Flashlight Source => (Flashlight)base.Source;
|
protected new Flashlight Source => (Flashlight)base.Source;
|
||||||
@ -136,6 +151,7 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
private Quad screenSpaceDrawQuad;
|
private Quad screenSpaceDrawQuad;
|
||||||
private Vector2 flashlightPosition;
|
private Vector2 flashlightPosition;
|
||||||
private Vector2 flashlightSize;
|
private Vector2 flashlightSize;
|
||||||
|
private float flashlightDim;
|
||||||
|
|
||||||
public FlashlightDrawNode(Flashlight source)
|
public FlashlightDrawNode(Flashlight source)
|
||||||
: base(source)
|
: base(source)
|
||||||
@ -149,7 +165,8 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
shader = Source.shader;
|
shader = Source.shader;
|
||||||
screenSpaceDrawQuad = Source.ScreenSpaceDrawQuad;
|
screenSpaceDrawQuad = Source.ScreenSpaceDrawQuad;
|
||||||
flashlightPosition = Vector2Extensions.Transform(Source.FlashlightPosition, DrawInfo.Matrix);
|
flashlightPosition = Vector2Extensions.Transform(Source.FlashlightPosition, DrawInfo.Matrix);
|
||||||
flashlightSize = Vector2Extensions.Transform(Source.FlashlightSize, DrawInfo.Matrix);
|
flashlightSize = Source.FlashlightSize * DrawInfo.Matrix.ExtractScale().Xy;
|
||||||
|
flashlightDim = Source.FlashlightDim;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Draw(Action<TexturedVertex2D> vertexAction)
|
public override void Draw(Action<TexturedVertex2D> vertexAction)
|
||||||
@ -160,6 +177,7 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
|
|
||||||
shader.GetUniform<Vector2>("flashlightPos").UpdateValue(ref flashlightPosition);
|
shader.GetUniform<Vector2>("flashlightPos").UpdateValue(ref flashlightPosition);
|
||||||
shader.GetUniform<Vector2>("flashlightSize").UpdateValue(ref flashlightSize);
|
shader.GetUniform<Vector2>("flashlightSize").UpdateValue(ref flashlightSize);
|
||||||
|
shader.GetUniform<float>("flashlightDim").UpdateValue(ref flashlightDim);
|
||||||
|
|
||||||
Texture.WhitePixel.DrawQuad(screenSpaceDrawQuad, DrawColourInfo.Colour, vertexAction: vertexAction);
|
Texture.WhitePixel.DrawQuad(screenSpaceDrawQuad, DrawColourInfo.Colour, vertexAction: vertexAction);
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// 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.Collections.Concurrent;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Rulesets.Configuration;
|
using osu.Game.Rulesets.Configuration;
|
||||||
@ -15,7 +15,7 @@ namespace osu.Game.Rulesets
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class RulesetConfigCache : Component
|
public class RulesetConfigCache : Component
|
||||||
{
|
{
|
||||||
private readonly Dictionary<int, IRulesetConfigManager> configCache = new Dictionary<int, IRulesetConfigManager>();
|
private readonly ConcurrentDictionary<int, IRulesetConfigManager> configCache = new ConcurrentDictionary<int, IRulesetConfigManager>();
|
||||||
private readonly SettingsStore settingsStore;
|
private readonly SettingsStore settingsStore;
|
||||||
|
|
||||||
public RulesetConfigCache(SettingsStore settingsStore)
|
public RulesetConfigCache(SettingsStore settingsStore)
|
||||||
@ -34,10 +34,7 @@ namespace osu.Game.Rulesets
|
|||||||
if (ruleset.RulesetInfo.ID == null)
|
if (ruleset.RulesetInfo.ID == null)
|
||||||
throw new InvalidOperationException("The provided ruleset doesn't have a valid id.");
|
throw new InvalidOperationException("The provided ruleset doesn't have a valid id.");
|
||||||
|
|
||||||
if (configCache.TryGetValue(ruleset.RulesetInfo.ID.Value, out var existing))
|
return configCache.GetOrAdd(ruleset.RulesetInfo.ID.Value, _ => ruleset.CreateConfig(settingsStore));
|
||||||
return existing;
|
|
||||||
|
|
||||||
return configCache[ruleset.RulesetInfo.ID.Value] = ruleset.CreateConfig(settingsStore);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -360,6 +360,9 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
|
|
||||||
JudgedHits--;
|
JudgedHits--;
|
||||||
|
|
||||||
|
if (result.Type != HitResult.None)
|
||||||
|
scoreResultCounts[result.Type] = scoreResultCounts.GetOrDefault(result.Type) - 1;
|
||||||
|
|
||||||
if (result.Judgement.IsBonus)
|
if (result.Judgement.IsBonus)
|
||||||
{
|
{
|
||||||
if (result.IsHit)
|
if (result.IsHit)
|
||||||
|
@ -12,6 +12,7 @@ using osu.Game.Rulesets.Objects.Drawables;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics.Cursor;
|
using osu.Framework.Graphics.Cursor;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
@ -59,6 +60,8 @@ namespace osu.Game.Rulesets.UI
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Container Overlays { get; private set; }
|
public Container Overlays { get; private set; }
|
||||||
|
|
||||||
|
public override GameplayClock FrameStableClock => frameStabilityContainer.GameplayClock;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invoked when a <see cref="JudgementResult"/> has been applied by a <see cref="DrawableHitObject"/>.
|
/// Invoked when a <see cref="JudgementResult"/> has been applied by a <see cref="DrawableHitObject"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -140,11 +143,11 @@ namespace osu.Game.Rulesets.UI
|
|||||||
public virtual PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => new PlayfieldAdjustmentContainer();
|
public virtual PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => new PlayfieldAdjustmentContainer();
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuConfigManager config)
|
private void load(OsuConfigManager config, CancellationToken? cancellationToken)
|
||||||
{
|
{
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
frameStabilityContainer = new FrameStabilityContainer
|
frameStabilityContainer = new FrameStabilityContainer(GameplayStartTime)
|
||||||
{
|
{
|
||||||
Child = KeyBindingInputManager
|
Child = KeyBindingInputManager
|
||||||
.WithChild(CreatePlayfieldAdjustmentContainer()
|
.WithChild(CreatePlayfieldAdjustmentContainer()
|
||||||
@ -163,16 +166,21 @@ namespace osu.Game.Rulesets.UI
|
|||||||
|
|
||||||
applyRulesetMods(mods, config);
|
applyRulesetMods(mods, config);
|
||||||
|
|
||||||
loadObjects();
|
loadObjects(cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates and adds drawable representations of hit objects to the play field.
|
/// Creates and adds drawable representations of hit objects to the play field.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void loadObjects()
|
private void loadObjects(CancellationToken? cancellationToken)
|
||||||
{
|
{
|
||||||
foreach (TObject h in Beatmap.HitObjects)
|
foreach (TObject h in Beatmap.HitObjects)
|
||||||
|
{
|
||||||
|
cancellationToken?.ThrowIfCancellationRequested();
|
||||||
addHitObject(h);
|
addHitObject(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
cancellationToken?.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
Playfield.PostProcess();
|
Playfield.PostProcess();
|
||||||
|
|
||||||
@ -334,6 +342,11 @@ namespace osu.Game.Rulesets.UI
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly BindableBool IsPaused = new BindableBool();
|
public readonly BindableBool IsPaused = new BindableBool();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The frame-stable clock which is being used for playfield display.
|
||||||
|
/// </summary>
|
||||||
|
public abstract GameplayClock FrameStableClock { get; }
|
||||||
|
|
||||||
/// <summary>~
|
/// <summary>~
|
||||||
/// The associated ruleset.
|
/// The associated ruleset.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -17,19 +17,29 @@ namespace osu.Game.Rulesets.UI
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class FrameStabilityContainer : Container, IHasReplayHandler
|
public class FrameStabilityContainer : Container, IHasReplayHandler
|
||||||
{
|
{
|
||||||
public FrameStabilityContainer()
|
private readonly double gameplayStartTime;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The number of frames (per parent frame) which can be run in an attempt to catch-up to real-time.
|
||||||
|
/// </summary>
|
||||||
|
public int MaxCatchUpFrames { get; set; } = 5;
|
||||||
|
|
||||||
|
[Cached]
|
||||||
|
public GameplayClock GameplayClock { get; }
|
||||||
|
|
||||||
|
public FrameStabilityContainer(double gameplayStartTime = double.MinValue)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
gameplayClock = new GameplayClock(framedClock = new FramedClock(manualClock = new ManualClock()));
|
|
||||||
|
GameplayClock = new GameplayClock(framedClock = new FramedClock(manualClock = new ManualClock()));
|
||||||
|
|
||||||
|
this.gameplayStartTime = gameplayStartTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly ManualClock manualClock;
|
private readonly ManualClock manualClock;
|
||||||
|
|
||||||
private readonly FramedClock framedClock;
|
private readonly FramedClock framedClock;
|
||||||
|
|
||||||
[Cached]
|
|
||||||
private GameplayClock gameplayClock;
|
|
||||||
|
|
||||||
private IFrameBasedClock parentGameplayClock;
|
private IFrameBasedClock parentGameplayClock;
|
||||||
|
|
||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
@ -38,7 +48,7 @@ namespace osu.Game.Rulesets.UI
|
|||||||
if (clock != null)
|
if (clock != null)
|
||||||
{
|
{
|
||||||
parentGameplayClock = clock;
|
parentGameplayClock = clock;
|
||||||
gameplayClock.IsPaused.BindTo(clock.IsPaused);
|
GameplayClock.IsPaused.BindTo(clock.IsPaused);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,8 +74,6 @@ namespace osu.Game.Rulesets.UI
|
|||||||
|
|
||||||
private bool isAttached => ReplayInputHandler != null;
|
private bool isAttached => ReplayInputHandler != null;
|
||||||
|
|
||||||
private const int max_catch_up_updates_per_frame = 50;
|
|
||||||
|
|
||||||
private const double sixty_frame_time = 1000.0 / 60;
|
private const double sixty_frame_time = 1000.0 / 60;
|
||||||
|
|
||||||
private bool firstConsumption = true;
|
private bool firstConsumption = true;
|
||||||
@ -73,11 +81,11 @@ namespace osu.Game.Rulesets.UI
|
|||||||
public override bool UpdateSubTree()
|
public override bool UpdateSubTree()
|
||||||
{
|
{
|
||||||
requireMoreUpdateLoops = true;
|
requireMoreUpdateLoops = true;
|
||||||
validState = !gameplayClock.IsPaused.Value;
|
validState = !GameplayClock.IsPaused.Value;
|
||||||
|
|
||||||
int loops = 0;
|
int loops = 0;
|
||||||
|
|
||||||
while (validState && requireMoreUpdateLoops && loops++ < max_catch_up_updates_per_frame)
|
while (validState && requireMoreUpdateLoops && loops++ < MaxCatchUpFrames)
|
||||||
{
|
{
|
||||||
updateClock();
|
updateClock();
|
||||||
|
|
||||||
@ -116,6 +124,8 @@ namespace osu.Game.Rulesets.UI
|
|||||||
|
|
||||||
firstConsumption = false;
|
firstConsumption = false;
|
||||||
}
|
}
|
||||||
|
else if (manualClock.CurrentTime < gameplayStartTime)
|
||||||
|
manualClock.CurrentTime = newProposedTime = Math.Min(gameplayStartTime, newProposedTime);
|
||||||
else if (Math.Abs(manualClock.CurrentTime - newProposedTime) > sixty_frame_time * 1.2f)
|
else if (Math.Abs(manualClock.CurrentTime - newProposedTime) > sixty_frame_time * 1.2f)
|
||||||
{
|
{
|
||||||
newProposedTime = newProposedTime > manualClock.CurrentTime
|
newProposedTime = newProposedTime > manualClock.CurrentTime
|
||||||
@ -160,7 +170,7 @@ namespace osu.Game.Rulesets.UI
|
|||||||
if (parentGameplayClock == null)
|
if (parentGameplayClock == null)
|
||||||
parentGameplayClock = Clock;
|
parentGameplayClock = Clock;
|
||||||
|
|
||||||
Clock = gameplayClock;
|
Clock = GameplayClock;
|
||||||
ProcessCustomClock = false;
|
ProcessCustomClock = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,9 +25,9 @@ namespace osu.Game.Scoring
|
|||||||
protected override string ImportFromStablePath => "Replays";
|
protected override string ImportFromStablePath => "Replays";
|
||||||
|
|
||||||
private readonly RulesetStore rulesets;
|
private readonly RulesetStore rulesets;
|
||||||
private readonly BeatmapManager beatmaps;
|
private readonly Func<BeatmapManager> beatmaps;
|
||||||
|
|
||||||
public ScoreManager(RulesetStore rulesets, BeatmapManager beatmaps, Storage storage, IDatabaseContextFactory contextFactory, IIpcHost importHost = null)
|
public ScoreManager(RulesetStore rulesets, Func<BeatmapManager> beatmaps, Storage storage, IDatabaseContextFactory contextFactory, IIpcHost importHost = null)
|
||||||
: base(storage, contextFactory, new ScoreStore(contextFactory, storage), importHost)
|
: base(storage, contextFactory, new ScoreStore(contextFactory, storage), importHost)
|
||||||
{
|
{
|
||||||
this.rulesets = rulesets;
|
this.rulesets = rulesets;
|
||||||
@ -43,7 +43,7 @@ namespace osu.Game.Scoring
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return new DatabasedLegacyScoreParser(rulesets, beatmaps).Parse(stream).ScoreInfo;
|
return new DatabasedLegacyScoreParser(rulesets, beatmaps()).Parse(stream).ScoreInfo;
|
||||||
}
|
}
|
||||||
catch (LegacyScoreParser.BeatmapNotFoundException e)
|
catch (LegacyScoreParser.BeatmapNotFoundException e)
|
||||||
{
|
{
|
||||||
@ -53,7 +53,7 @@ namespace osu.Game.Scoring
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Score GetScore(ScoreInfo score) => new LegacyDatabasedScore(score, rulesets, beatmaps, Files.Store);
|
public Score GetScore(ScoreInfo score) => new LegacyDatabasedScore(score, rulesets, beatmaps(), Files.Store);
|
||||||
|
|
||||||
public List<ScoreInfo> GetAllUsableScores() => ModelStore.ConsumableItems.Where(s => !s.DeletePending).ToList();
|
public List<ScoreInfo> GetAllUsableScores() => ModelStore.ConsumableItems.Where(s => !s.DeletePending).ToList();
|
||||||
|
|
||||||
|
@ -92,6 +92,14 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
// This width only gets updated on the application of a transform, so this needs to be initialized here.
|
||||||
|
updateZoomedContentWidth();
|
||||||
|
}
|
||||||
|
|
||||||
protected override bool OnScroll(ScrollEvent e)
|
protected override bool OnScroll(ScrollEvent e)
|
||||||
{
|
{
|
||||||
if (e.IsPrecise)
|
if (e.IsPrecise)
|
||||||
@ -102,6 +110,8 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateZoomedContentWidth() => zoomedContent.Width = DrawWidth * currentZoom;
|
||||||
|
|
||||||
private float zoomTarget = 1;
|
private float zoomTarget = 1;
|
||||||
|
|
||||||
private void setZoomTarget(float newZoom, float focusPoint)
|
private void setZoomTarget(float newZoom, float focusPoint)
|
||||||
@ -163,7 +173,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
|
|
||||||
d.currentZoom = newZoom;
|
d.currentZoom = newZoom;
|
||||||
|
|
||||||
d.zoomedContent.Width = d.DrawWidth * d.currentZoom;
|
d.updateZoomedContentWidth();
|
||||||
// Temporarily here to make sure ScrollTo gets the correct DrawSize for scrollable area.
|
// Temporarily here to make sure ScrollTo gets the correct DrawSize for scrollable area.
|
||||||
// TODO: Make sure draw size gets invalidated properly on the framework side, and remove this once it is.
|
// TODO: Make sure draw size gets invalidated properly on the framework side, and remove this once it is.
|
||||||
d.Invalidate(Invalidation.DrawSize);
|
d.Invalidate(Invalidation.DrawSize);
|
||||||
|
@ -25,6 +25,8 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
{
|
{
|
||||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true;
|
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true;
|
||||||
|
|
||||||
|
public readonly Bindable<bool> IsPaused = new Bindable<bool>();
|
||||||
|
|
||||||
private readonly Button button;
|
private readonly Button button;
|
||||||
|
|
||||||
public Action Action
|
public Action Action
|
||||||
@ -51,7 +53,8 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
button = new Button
|
button = new Button
|
||||||
{
|
{
|
||||||
HoverGained = () => text.FadeIn(500, Easing.OutQuint),
|
HoverGained = () => text.FadeIn(500, Easing.OutQuint),
|
||||||
HoverLost = () => text.FadeOut(500, Easing.OutQuint)
|
HoverLost = () => text.FadeOut(500, Easing.OutQuint),
|
||||||
|
IsPaused = { BindTarget = IsPaused }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
AutoSizeAxes = Axes.Both;
|
AutoSizeAxes = Axes.Both;
|
||||||
@ -94,6 +97,8 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
private CircularProgress circularProgress;
|
private CircularProgress circularProgress;
|
||||||
private Circle overlayCircle;
|
private Circle overlayCircle;
|
||||||
|
|
||||||
|
public readonly Bindable<bool> IsPaused = new Bindable<bool>();
|
||||||
|
|
||||||
protected override bool AllowMultipleFires => true;
|
protected override bool AllowMultipleFires => true;
|
||||||
|
|
||||||
public Action HoverGained;
|
public Action HoverGained;
|
||||||
@ -217,7 +222,7 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
|
|
||||||
private void updateActive()
|
private void updateActive()
|
||||||
{
|
{
|
||||||
if (!pauseOnFocusLost) return;
|
if (!pauseOnFocusLost || IsPaused.Value) return;
|
||||||
|
|
||||||
if (gameActive.Value)
|
if (gameActive.Value)
|
||||||
AbortConfirm();
|
AbortConfirm();
|
||||||
|
@ -24,6 +24,8 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
|
|
||||||
public bool DisplayUnrankedText = true;
|
public bool DisplayUnrankedText = true;
|
||||||
|
|
||||||
|
public bool AllowExpand = true;
|
||||||
|
|
||||||
private readonly Bindable<IReadOnlyList<Mod>> current = new Bindable<IReadOnlyList<Mod>>();
|
private readonly Bindable<IReadOnlyList<Mod>> current = new Bindable<IReadOnlyList<Mod>>();
|
||||||
|
|
||||||
public Bindable<IReadOnlyList<Mod>> Current
|
public Bindable<IReadOnlyList<Mod>> Current
|
||||||
@ -88,7 +90,9 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
appearTransform();
|
appearTransform();
|
||||||
|
iconsContainer.FadeInFromZero(fade_duration, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void appearTransform()
|
private void appearTransform()
|
||||||
@ -98,14 +102,17 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
else
|
else
|
||||||
unrankedText.Hide();
|
unrankedText.Hide();
|
||||||
|
|
||||||
iconsContainer.FinishTransforms();
|
|
||||||
iconsContainer.FadeInFromZero(fade_duration, Easing.OutQuint);
|
|
||||||
expand();
|
expand();
|
||||||
|
|
||||||
using (iconsContainer.BeginDelayedSequence(1200))
|
using (iconsContainer.BeginDelayedSequence(1200))
|
||||||
contract();
|
contract();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void expand() => iconsContainer.TransformSpacingTo(new Vector2(5, 0), 500, Easing.OutQuint);
|
private void expand()
|
||||||
|
{
|
||||||
|
if (AllowExpand)
|
||||||
|
iconsContainer.TransformSpacingTo(new Vector2(5, 0), 500, Easing.OutQuint);
|
||||||
|
}
|
||||||
|
|
||||||
private void contract() => iconsContainer.TransformSpacingTo(new Vector2(-25, 0), 500, Easing.OutQuint);
|
private void contract() => iconsContainer.TransformSpacingTo(new Vector2(-25, 0), 500, Easing.OutQuint);
|
||||||
|
|
||||||
|
@ -35,6 +35,10 @@ namespace osu.Game.Screens.Play
|
|||||||
public readonly HoldForMenuButton HoldToQuit;
|
public readonly HoldForMenuButton HoldToQuit;
|
||||||
public readonly PlayerSettingsOverlay PlayerSettingsOverlay;
|
public readonly PlayerSettingsOverlay PlayerSettingsOverlay;
|
||||||
|
|
||||||
|
private readonly ScoreProcessor scoreProcessor;
|
||||||
|
private readonly DrawableRuleset drawableRuleset;
|
||||||
|
private readonly IReadOnlyList<Mod> mods;
|
||||||
|
|
||||||
private Bindable<bool> showHud;
|
private Bindable<bool> showHud;
|
||||||
private readonly Container visibilityContainer;
|
private readonly Container visibilityContainer;
|
||||||
private readonly BindableBool replayLoaded = new BindableBool();
|
private readonly BindableBool replayLoaded = new BindableBool();
|
||||||
@ -45,6 +49,10 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
public HUDOverlay(ScoreProcessor scoreProcessor, DrawableRuleset drawableRuleset, IReadOnlyList<Mod> mods)
|
public HUDOverlay(ScoreProcessor scoreProcessor, DrawableRuleset drawableRuleset, IReadOnlyList<Mod> mods)
|
||||||
{
|
{
|
||||||
|
this.scoreProcessor = scoreProcessor;
|
||||||
|
this.drawableRuleset = drawableRuleset;
|
||||||
|
this.mods = mods;
|
||||||
|
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
@ -89,20 +97,21 @@ namespace osu.Game.Screens.Play
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader(true)]
|
||||||
|
private void load(OsuConfigManager config, NotificationOverlay notificationOverlay)
|
||||||
|
{
|
||||||
BindProcessor(scoreProcessor);
|
BindProcessor(scoreProcessor);
|
||||||
BindDrawableRuleset(drawableRuleset);
|
BindDrawableRuleset(drawableRuleset);
|
||||||
|
|
||||||
Progress.Objects = drawableRuleset.Objects;
|
Progress.Objects = drawableRuleset.Objects;
|
||||||
Progress.AllowSeeking = drawableRuleset.HasReplayLoaded.Value;
|
Progress.AllowSeeking = drawableRuleset.HasReplayLoaded.Value;
|
||||||
Progress.RequestSeek = time => RequestSeek(time);
|
Progress.RequestSeek = time => RequestSeek(time);
|
||||||
|
Progress.ReferenceClock = drawableRuleset.FrameStableClock;
|
||||||
|
|
||||||
ModDisplay.Current.Value = mods;
|
ModDisplay.Current.Value = mods;
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader(true)]
|
|
||||||
private void load(OsuConfigManager config, NotificationOverlay notificationOverlay)
|
|
||||||
{
|
|
||||||
showHud = config.GetBindable<bool>(OsuSetting.ShowInterface);
|
showHud = config.GetBindable<bool>(OsuSetting.ShowInterface);
|
||||||
showHud.ValueChanged += visible => visibilityContainer.FadeTo(visible.NewValue ? 1 : 0, duration);
|
showHud.ValueChanged += visible => visibilityContainer.FadeTo(visible.NewValue ? 1 : 0, duration);
|
||||||
showHud.TriggerChange();
|
showHud.TriggerChange();
|
||||||
@ -122,8 +131,7 @@ namespace osu.Game.Screens.Play
|
|||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
replayLoaded.ValueChanged += replayLoadedValueChanged;
|
replayLoaded.BindValueChanged(replayLoadedValueChanged, true);
|
||||||
replayLoaded.TriggerChange();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void replayLoadedValueChanged(ValueChangedEvent<bool> e)
|
private void replayLoadedValueChanged(ValueChangedEvent<bool> e)
|
||||||
|
@ -43,6 +43,11 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
public override OverlayActivation InitialOverlayActivationMode => OverlayActivation.UserTriggered;
|
public override OverlayActivation InitialOverlayActivationMode => OverlayActivation.UserTriggered;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether gameplay should pause when the game window focus is lost.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual bool PauseOnFocusLost => true;
|
||||||
|
|
||||||
public Action RestartRequested;
|
public Action RestartRequested;
|
||||||
|
|
||||||
public bool HasFailed { get; private set; }
|
public bool HasFailed { get; private set; }
|
||||||
@ -135,7 +140,11 @@ namespace osu.Game.Screens.Play
|
|||||||
DrawableRuleset.Cursor?.CreateProxy() ?? new Container(),
|
DrawableRuleset.Cursor?.CreateProxy() ?? new Container(),
|
||||||
HUDOverlay = new HUDOverlay(ScoreProcessor, DrawableRuleset, Mods.Value)
|
HUDOverlay = new HUDOverlay(ScoreProcessor, DrawableRuleset, Mods.Value)
|
||||||
{
|
{
|
||||||
HoldToQuit = { Action = performUserRequestedExit },
|
HoldToQuit =
|
||||||
|
{
|
||||||
|
Action = performUserRequestedExit,
|
||||||
|
IsPaused = { BindTarget = GameplayClockContainer.IsPaused }
|
||||||
|
},
|
||||||
PlayerSettingsOverlay = { PlaybackSettings = { UserPlaybackRate = { BindTarget = GameplayClockContainer.UserPlaybackRate } } },
|
PlayerSettingsOverlay = { PlaybackSettings = { UserPlaybackRate = { BindTarget = GameplayClockContainer.UserPlaybackRate } } },
|
||||||
KeyCounter = { Visible = { BindTarget = DrawableRuleset.HasReplayLoaded } },
|
KeyCounter = { Visible = { BindTarget = DrawableRuleset.HasReplayLoaded } },
|
||||||
RequestSeek = GameplayClockContainer.Seek,
|
RequestSeek = GameplayClockContainer.Seek,
|
||||||
@ -170,6 +179,8 @@ namespace osu.Game.Screens.Play
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
DrawableRuleset.HasReplayLoaded.BindValueChanged(e => HUDOverlay.HoldToQuit.PauseOnFocusLost = !e.NewValue && PauseOnFocusLost, true);
|
||||||
|
|
||||||
// bind clock into components that require it
|
// bind clock into components that require it
|
||||||
DrawableRuleset.IsPaused.BindTo(GameplayClockContainer.IsPaused);
|
DrawableRuleset.IsPaused.BindTo(GameplayClockContainer.IsPaused);
|
||||||
|
|
||||||
@ -406,8 +417,9 @@ namespace osu.Game.Screens.Play
|
|||||||
IsResuming = true;
|
IsResuming = true;
|
||||||
PauseOverlay.Hide();
|
PauseOverlay.Hide();
|
||||||
|
|
||||||
// time-based conditions may allow instant resume.
|
// breaks and time-based conditions may allow instant resume.
|
||||||
if (GameplayClockContainer.GameplayClock.CurrentTime < Beatmap.Value.Beatmap.HitObjects.First().StartTime)
|
double time = GameplayClockContainer.GameplayClock.CurrentTime;
|
||||||
|
if (Beatmap.Value.Beatmap.Breaks.Any(b => b.Contains(time)) || time < Beatmap.Value.Beatmap.HitObjects.First().StartTime)
|
||||||
completeResume();
|
completeResume();
|
||||||
else
|
else
|
||||||
DrawableRuleset.RequestResume(completeResume);
|
DrawableRuleset.RequestResume(completeResume);
|
||||||
|
@ -10,6 +10,7 @@ using osu.Game.Graphics;
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Timing;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
@ -55,7 +56,9 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
private readonly BindableBool replayLoaded = new BindableBool();
|
private readonly BindableBool replayLoaded = new BindableBool();
|
||||||
|
|
||||||
private GameplayClock gameplayClock;
|
public IClock ReferenceClock;
|
||||||
|
|
||||||
|
private IClock gameplayClock;
|
||||||
|
|
||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
private void load(OsuColour colours, GameplayClock clock)
|
private void load(OsuColour colours, GameplayClock clock)
|
||||||
@ -154,10 +157,12 @@ namespace osu.Game.Screens.Play
|
|||||||
if (objects == null)
|
if (objects == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
double position = gameplayClock?.CurrentTime ?? Time.Current;
|
double gameplayTime = gameplayClock?.CurrentTime ?? Time.Current;
|
||||||
double progress = Math.Min(1, (position - firstHitTime) / (lastHitTime - firstHitTime));
|
double frameStableTime = ReferenceClock?.CurrentTime ?? gameplayTime;
|
||||||
|
|
||||||
bar.CurrentTime = position;
|
double progress = Math.Min(1, (frameStableTime - firstHitTime) / (lastHitTime - firstHitTime));
|
||||||
|
|
||||||
|
bar.CurrentTime = gameplayTime;
|
||||||
graph.Progress = (int)(graph.ColumnCount * progress);
|
graph.Progress = (int)(graph.ColumnCount * progress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ using osu.Framework.Graphics.Containers;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
|
using osu.Framework.MathUtils;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Play
|
namespace osu.Game.Screens.Play
|
||||||
{
|
{
|
||||||
@ -107,9 +108,17 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
protected override void UpdateValue(float value)
|
protected override void UpdateValue(float value)
|
||||||
{
|
{
|
||||||
var xFill = value * UsableWidth;
|
// handled in update
|
||||||
fill.Width = xFill;
|
}
|
||||||
handleBase.X = xFill;
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
|
||||||
|
float newX = (float)Interpolation.Lerp(handleBase.X, NormalizedValue * UsableWidth, MathHelper.Clamp(Time.Elapsed / 40, 0, 1));
|
||||||
|
|
||||||
|
fill.Width = newX;
|
||||||
|
handleBase.X = newX;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnUserChange(double value) => OnSeek?.Invoke(value);
|
protected override void OnUserChange(double value) => OnSeek?.Invoke(value);
|
||||||
|
@ -6,7 +6,6 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
using osuTK.Input;
|
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
@ -20,9 +19,6 @@ namespace osu.Game.Screens.Select
|
|||||||
{
|
{
|
||||||
private readonly Box modeLight;
|
private readonly Box modeLight;
|
||||||
|
|
||||||
private const float play_song_select_button_width = 100;
|
|
||||||
private const float play_song_select_button_height = 50;
|
|
||||||
|
|
||||||
public const float HEIGHT = 50;
|
public const float HEIGHT = 50;
|
||||||
|
|
||||||
public const int TRANSITION_LENGTH = 300;
|
public const int TRANSITION_LENGTH = 300;
|
||||||
@ -33,57 +29,36 @@ namespace osu.Game.Screens.Select
|
|||||||
|
|
||||||
private readonly FillFlowContainer<FooterButton> buttons;
|
private readonly FillFlowContainer<FooterButton> buttons;
|
||||||
|
|
||||||
/// <param name="text">Text on the button.</param>
|
|
||||||
/// <param name="colour">Colour of the button.</param>
|
|
||||||
/// <param name="hotkey">Hotkey of the button.</param>
|
|
||||||
/// <param name="action">Action the button does.</param>
|
|
||||||
/// <param name="depth">
|
|
||||||
/// <para>Higher depth to be put on the left, and lower to be put on the right.</para>
|
|
||||||
/// <para>Notice this is different to <see cref="Options.BeatmapOptionsOverlay"/>!</para>
|
|
||||||
/// </param>
|
|
||||||
public void AddButton(string text, Color4 colour, Action action, Key? hotkey = null, float depth = 0)
|
|
||||||
{
|
|
||||||
var button = new FooterButton
|
|
||||||
{
|
|
||||||
Text = text,
|
|
||||||
Height = play_song_select_button_height,
|
|
||||||
Width = play_song_select_button_width,
|
|
||||||
Depth = depth,
|
|
||||||
SelectedColour = colour,
|
|
||||||
DeselectedColour = colour.Opacity(0.5f),
|
|
||||||
Hotkey = hotkey,
|
|
||||||
Hovered = updateModeLight,
|
|
||||||
HoverLost = updateModeLight,
|
|
||||||
Action = action,
|
|
||||||
};
|
|
||||||
|
|
||||||
buttons.Add(button);
|
|
||||||
buttons.SetLayoutPosition(button, -depth);
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly List<OverlayContainer> overlays = new List<OverlayContainer>();
|
private readonly List<OverlayContainer> overlays = new List<OverlayContainer>();
|
||||||
|
|
||||||
/// <param name="text">Text on the button.</param>
|
/// <param name="button">THe button to be added.</param>
|
||||||
/// <param name="colour">Colour of the button.</param>
|
|
||||||
/// <param name="hotkey">Hotkey of the button.</param>
|
|
||||||
/// <param name="overlay">The <see cref="OverlayContainer"/> to be toggled by this button.</param>
|
/// <param name="overlay">The <see cref="OverlayContainer"/> to be toggled by this button.</param>
|
||||||
/// <param name="depth">
|
public void AddButton(FooterButton button, OverlayContainer overlay)
|
||||||
/// <para>Higher depth to be put on the left, and lower to be put on the right.</para>
|
|
||||||
/// <para>Notice this is different to <see cref="Options.BeatmapOptionsOverlay"/>!</para>
|
|
||||||
/// </param>
|
|
||||||
public void AddButton(string text, Color4 colour, OverlayContainer overlay, Key? hotkey = null, float depth = 0)
|
|
||||||
{
|
{
|
||||||
overlays.Add(overlay);
|
overlays.Add(overlay);
|
||||||
AddButton(text, colour, () =>
|
button.Action = () => showOverlay(overlay);
|
||||||
|
|
||||||
|
AddButton(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <param name="button">Button to be added.</param>
|
||||||
|
public void AddButton(FooterButton button)
|
||||||
|
{
|
||||||
|
button.Hovered = updateModeLight;
|
||||||
|
button.HoverLost = updateModeLight;
|
||||||
|
|
||||||
|
buttons.Add(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showOverlay(OverlayContainer overlay)
|
||||||
|
{
|
||||||
|
foreach (var o in overlays)
|
||||||
{
|
{
|
||||||
foreach (var o in overlays)
|
if (o == overlay)
|
||||||
{
|
o.ToggleVisibility();
|
||||||
if (o == overlay)
|
else
|
||||||
o.ToggleVisibility();
|
o.Hide();
|
||||||
else
|
}
|
||||||
o.Hide();
|
|
||||||
}
|
|
||||||
}, hotkey, depth);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateModeLight() => modeLight.FadeColour(buttons.FirstOrDefault(b => b.IsHovered)?.SelectedColour ?? Color4.Transparent, TRANSITION_LENGTH, Easing.OutQuint);
|
private void updateModeLight() => modeLight.FadeColour(buttons.FirstOrDefault(b => b.IsHovered)?.SelectedColour ?? Color4.Transparent, TRANSITION_LENGTH, Easing.OutQuint);
|
||||||
|
@ -6,6 +6,7 @@ using osuTK;
|
|||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
using osuTK.Input;
|
using osuTK.Input;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
@ -20,11 +21,11 @@ namespace osu.Game.Screens.Select
|
|||||||
|
|
||||||
public string Text
|
public string Text
|
||||||
{
|
{
|
||||||
get => spriteText?.Text;
|
get => SpriteText?.Text;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (spriteText != null)
|
if (SpriteText != null)
|
||||||
spriteText.Text = value;
|
SpriteText.Text = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,7 +54,8 @@ namespace osu.Game.Screens.Select
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly SpriteText spriteText;
|
protected readonly Container TextContainer;
|
||||||
|
protected readonly SpriteText SpriteText;
|
||||||
private readonly Box box;
|
private readonly Box box;
|
||||||
private readonly Box light;
|
private readonly Box light;
|
||||||
|
|
||||||
@ -61,8 +63,18 @@ namespace osu.Game.Screens.Select
|
|||||||
|
|
||||||
public FooterButton()
|
public FooterButton()
|
||||||
{
|
{
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
|
TextContainer = new Container
|
||||||
|
{
|
||||||
|
Size = new Vector2(100, 50),
|
||||||
|
Child = SpriteText = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
}
|
||||||
|
},
|
||||||
box = new Box
|
box = new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
@ -78,11 +90,6 @@ namespace osu.Game.Screens.Select
|
|||||||
EdgeSmoothness = new Vector2(2, 0),
|
EdgeSmoothness = new Vector2(2, 0),
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
},
|
},
|
||||||
spriteText = new OsuSpriteText
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
60
osu.Game/Screens/Select/FooterButtonMods.cs
Normal file
60
osu.Game/Screens/Select/FooterButtonMods.cs
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Screens.Play.HUD;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Input;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Select
|
||||||
|
{
|
||||||
|
public class FooterButtonMods : FooterButton
|
||||||
|
{
|
||||||
|
public FooterButtonMods(Bindable<IReadOnlyList<Mod>> mods)
|
||||||
|
{
|
||||||
|
FooterModDisplay modDisplay;
|
||||||
|
|
||||||
|
Add(new Container
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
Child = modDisplay = new FooterModDisplay
|
||||||
|
{
|
||||||
|
DisplayUnrankedText = false,
|
||||||
|
Scale = new Vector2(0.8f)
|
||||||
|
},
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Margin = new MarginPadding { Left = 70 }
|
||||||
|
});
|
||||||
|
|
||||||
|
if (mods != null)
|
||||||
|
modDisplay.Current = mods;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
SelectedColour = colours.Yellow;
|
||||||
|
DeselectedColour = SelectedColour.Opacity(0.5f);
|
||||||
|
Text = @"mods";
|
||||||
|
Hotkey = Key.F1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class FooterModDisplay : ModDisplay
|
||||||
|
{
|
||||||
|
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Parent?.Parent?.ReceivePositionalInputAt(screenSpacePos) ?? false;
|
||||||
|
|
||||||
|
public FooterModDisplay()
|
||||||
|
{
|
||||||
|
AllowExpand = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
22
osu.Game/Screens/Select/FooterButtonOptions.cs
Normal file
22
osu.Game/Screens/Select/FooterButtonOptions.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osuTK.Input;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Select
|
||||||
|
{
|
||||||
|
public class FooterButtonOptions : FooterButton
|
||||||
|
{
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
SelectedColour = colours.Blue;
|
||||||
|
DeselectedColour = SelectedColour.Opacity(0.5f);
|
||||||
|
Text = @"options";
|
||||||
|
Hotkey = Key.F3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
68
osu.Game/Screens/Select/FooterButtonRandom.cs
Normal file
68
osu.Game/Screens/Select/FooterButtonRandom.cs
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osuTK.Input;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Select
|
||||||
|
{
|
||||||
|
public class FooterButtonRandom : FooterButton
|
||||||
|
{
|
||||||
|
private readonly SpriteText secondaryText;
|
||||||
|
private bool secondaryActive;
|
||||||
|
|
||||||
|
public FooterButtonRandom()
|
||||||
|
{
|
||||||
|
TextContainer.Add(secondaryText = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Text = @"rewind",
|
||||||
|
Alpha = 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
SelectedColour = colours.Green;
|
||||||
|
DeselectedColour = SelectedColour.Opacity(0.5f);
|
||||||
|
Text = @"random";
|
||||||
|
Hotkey = Key.F2;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnKeyDown(KeyDownEvent e)
|
||||||
|
{
|
||||||
|
secondaryActive = e.ShiftPressed;
|
||||||
|
updateText();
|
||||||
|
return base.OnKeyDown(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnKeyUp(KeyUpEvent e)
|
||||||
|
{
|
||||||
|
secondaryActive = e.ShiftPressed;
|
||||||
|
updateText();
|
||||||
|
return base.OnKeyUp(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateText()
|
||||||
|
{
|
||||||
|
if (secondaryActive)
|
||||||
|
{
|
||||||
|
SpriteText.FadeOut(120, Easing.InQuad);
|
||||||
|
secondaryText.FadeIn(120, Easing.InQuad);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SpriteText.FadeIn(120, Easing.InQuad);
|
||||||
|
secondaryText.FadeOut(120, Easing.InQuad);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -39,6 +39,7 @@ namespace osu.Game.Screens.Select
|
|||||||
public abstract class SongSelect : OsuScreen
|
public abstract class SongSelect : OsuScreen
|
||||||
{
|
{
|
||||||
private static readonly Vector2 wedged_container_size = new Vector2(0.5f, 245);
|
private static readonly Vector2 wedged_container_size = new Vector2(0.5f, 245);
|
||||||
|
|
||||||
protected const float BACKGROUND_BLUR = 20;
|
protected const float BACKGROUND_BLUR = 20;
|
||||||
private const float left_area_padding = 20;
|
private const float left_area_padding = 20;
|
||||||
|
|
||||||
@ -89,8 +90,6 @@ namespace osu.Game.Screens.Select
|
|||||||
|
|
||||||
protected SongSelect()
|
protected SongSelect()
|
||||||
{
|
{
|
||||||
const float carousel_width = 640;
|
|
||||||
|
|
||||||
AddRangeInternal(new Drawable[]
|
AddRangeInternal(new Drawable[]
|
||||||
{
|
{
|
||||||
new ParallaxContainer
|
new ParallaxContainer
|
||||||
@ -103,7 +102,8 @@ namespace osu.Game.Screens.Select
|
|||||||
new WedgeBackground
|
new WedgeBackground
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Padding = new MarginPadding { Right = carousel_width * 0.76f },
|
Padding = new MarginPadding { Right = -150 },
|
||||||
|
Size = new Vector2(wedged_container_size.X, 1),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -144,8 +144,8 @@ namespace osu.Game.Screens.Select
|
|||||||
Carousel = new BeatmapCarousel
|
Carousel = new BeatmapCarousel
|
||||||
{
|
{
|
||||||
Masking = false,
|
Masking = false,
|
||||||
RelativeSizeAxes = Axes.Y,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Size = new Vector2(carousel_width, 1),
|
Size = new Vector2(1 - wedged_container_size.X, 1),
|
||||||
Anchor = Anchor.CentreRight,
|
Anchor = Anchor.CentreRight,
|
||||||
Origin = Anchor.CentreRight,
|
Origin = Anchor.CentreRight,
|
||||||
SelectionChanged = updateSelectedBeatmap,
|
SelectionChanged = updateSelectedBeatmap,
|
||||||
@ -223,9 +223,9 @@ namespace osu.Game.Screens.Select
|
|||||||
|
|
||||||
if (Footer != null)
|
if (Footer != null)
|
||||||
{
|
{
|
||||||
Footer.AddButton(@"mods", colours.Yellow, ModSelect, Key.F1);
|
Footer.AddButton(new FooterButtonMods(mods), ModSelect);
|
||||||
Footer.AddButton(@"random", colours.Green, triggerRandom, Key.F2);
|
Footer.AddButton(new FooterButtonRandom { Action = triggerRandom });
|
||||||
Footer.AddButton(@"options", colours.Blue, BeatmapOptions, Key.F3);
|
Footer.AddButton(new FooterButtonOptions(), BeatmapOptions);
|
||||||
|
|
||||||
BeatmapOptions.AddButton(@"Delete", @"all difficulties", FontAwesome.Solid.Trash, colours.Pink, () => delete(Beatmap.Value.BeatmapSetInfo), Key.Number4, float.MaxValue);
|
BeatmapOptions.AddButton(@"Delete", @"all difficulties", FontAwesome.Solid.Trash, colours.Pink, () => delete(Beatmap.Value.BeatmapSetInfo), Key.Number4, float.MaxValue);
|
||||||
BeatmapOptions.AddButton(@"Remove", @"from unplayed", FontAwesome.Regular.TimesCircle, colours.Purple, null, Key.Number1);
|
BeatmapOptions.AddButton(@"Remove", @"from unplayed", FontAwesome.Regular.TimesCircle, colours.Purple, null, Key.Number1);
|
||||||
@ -505,6 +505,8 @@ namespace osu.Game.Screens.Select
|
|||||||
{
|
{
|
||||||
ModSelect.Hide();
|
ModSelect.Hide();
|
||||||
|
|
||||||
|
BeatmapOptions.Hide();
|
||||||
|
|
||||||
this.ScaleTo(1.1f, 250, Easing.InSine);
|
this.ScaleTo(1.1f, 250, Easing.InSine);
|
||||||
|
|
||||||
this.FadeOut(250);
|
this.FadeOut(250);
|
||||||
|
@ -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.Threading;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -57,7 +58,7 @@ namespace osu.Game.Storyboards.Drawables
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
private void load(FileStore fileStore, GameplayClock clock)
|
private void load(FileStore fileStore, GameplayClock clock, CancellationToken? cancellationToken)
|
||||||
{
|
{
|
||||||
if (clock != null)
|
if (clock != null)
|
||||||
Clock = clock;
|
Clock = clock;
|
||||||
@ -65,7 +66,11 @@ namespace osu.Game.Storyboards.Drawables
|
|||||||
dependencies.Cache(new TextureStore(new TextureLoaderStore(fileStore.Store), false, scaleAdjust: 1));
|
dependencies.Cache(new TextureStore(new TextureLoaderStore(fileStore.Store), false, scaleAdjust: 1));
|
||||||
|
|
||||||
foreach (var layer in Storyboard.Layers)
|
foreach (var layer in Storyboard.Layers)
|
||||||
|
{
|
||||||
|
cancellationToken?.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
Add(layer.CreateDrawable());
|
Add(layer.CreateDrawable());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateLayerVisibility()
|
private void updateLayerVisibility()
|
||||||
|
@ -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.Threading;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
@ -24,10 +25,12 @@ namespace osu.Game.Storyboards.Drawables
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load(CancellationToken? cancellationToken)
|
||||||
{
|
{
|
||||||
foreach (var element in Layer.Elements)
|
foreach (var element in Layer.Elements)
|
||||||
{
|
{
|
||||||
|
cancellationToken?.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
if (element.IsDrawable)
|
if (element.IsDrawable)
|
||||||
AddInternal(element.CreateDrawable());
|
AddInternal(element.CreateDrawable());
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,10 @@ using osu.Game.Beatmaps;
|
|||||||
using osu.Game.Storyboards.Drawables;
|
using osu.Game.Storyboards.Drawables;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace osu.Game.Storyboards
|
namespace osu.Game.Storyboards
|
||||||
{
|
{
|
||||||
public class Storyboard : IDisposable
|
public class Storyboard
|
||||||
{
|
{
|
||||||
private readonly Dictionary<string, StoryboardLayer> layers = new Dictionary<string, StoryboardLayer>();
|
private readonly Dictionary<string, StoryboardLayer> layers = new Dictionary<string, StoryboardLayer>();
|
||||||
public IEnumerable<StoryboardLayer> Layers => layers.Values;
|
public IEnumerable<StoryboardLayer> Layers => layers.Values;
|
||||||
@ -56,30 +55,5 @@ namespace osu.Game.Storyboards
|
|||||||
drawable.Width = drawable.Height * (BeatmapInfo.WidescreenStoryboard ? 16 / 9f : 4 / 3f);
|
drawable.Width = drawable.Height * (BeatmapInfo.WidescreenStoryboard ? 16 / 9f : 4 / 3f);
|
||||||
return drawable;
|
return drawable;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Disposal
|
|
||||||
|
|
||||||
~Storyboard()
|
|
||||||
{
|
|
||||||
Dispose(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
Dispose(true);
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool isDisposed;
|
|
||||||
|
|
||||||
protected virtual void Dispose(bool isDisposing)
|
|
||||||
{
|
|
||||||
if (isDisposed)
|
|
||||||
return;
|
|
||||||
|
|
||||||
isDisposed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Framework.Timing;
|
using osu.Framework.Timing;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
@ -41,6 +42,10 @@ namespace osu.Game.Tests.Visual
|
|||||||
|
|
||||||
AddCheckSteps();
|
AddCheckSteps();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OsuConfigManager manager;
|
||||||
|
Dependencies.Cache(manager = new OsuConfigManager(LocalStorage));
|
||||||
|
manager.GetBindable<double>(OsuSetting.DimLevel).Value = 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void AddCheckSteps();
|
protected abstract void AddCheckSteps();
|
||||||
@ -71,6 +76,6 @@ namespace osu.Game.Tests.Visual
|
|||||||
return Player;
|
return Player;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual Player CreatePlayer(Ruleset ruleset) => new Player(false, false);
|
protected virtual Player CreatePlayer(Ruleset ruleset) => new TestPlayer(false, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
// 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.Linq;
|
using System.Linq;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
@ -22,8 +24,16 @@ namespace osu.Game.Tests.Visual
|
|||||||
this.ruleset = ruleset;
|
this.ruleset = ruleset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
OsuConfigManager manager;
|
||||||
|
Dependencies.Cache(manager = new OsuConfigManager(LocalStorage));
|
||||||
|
manager.GetBindable<double>(OsuSetting.DimLevel).Value = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
[SetUpSteps]
|
[SetUpSteps]
|
||||||
public void SetUpSteps()
|
public virtual void SetUpSteps()
|
||||||
{
|
{
|
||||||
AddStep(ruleset.RulesetInfo.Name, loadPlayer);
|
AddStep(ruleset.RulesetInfo.Name, loadPlayer);
|
||||||
AddUntilStep("player loaded", () => Player.IsLoaded && Player.Alpha == 1);
|
AddUntilStep("player loaded", () => Player.IsLoaded && Player.Alpha == 1);
|
||||||
@ -46,6 +56,6 @@ namespace osu.Game.Tests.Visual
|
|||||||
LoadScreen(Player);
|
LoadScreen(Player);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual Player CreatePlayer(Ruleset ruleset) => new Player(false, false);
|
protected virtual Player CreatePlayer(Ruleset ruleset) => new TestPlayer(false, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
17
osu.Game/Tests/Visual/TestPlayer.cs
Normal file
17
osu.Game/Tests/Visual/TestPlayer.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Game.Screens.Play;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual
|
||||||
|
{
|
||||||
|
public class TestPlayer : Player
|
||||||
|
{
|
||||||
|
protected override bool PauseOnFocusLost => false;
|
||||||
|
|
||||||
|
public TestPlayer(bool allowPause = true, bool showResults = true)
|
||||||
|
: base(allowPause, showResults)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -11,11 +11,11 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="Humanizer" Version="2.6.2" />
|
<PackageReference Include="Humanizer" Version="2.6.2" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.3" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.4" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.3" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.4" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.128.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.502.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework" Version="2019.502.0" />
|
<PackageReference Include="ppy.osu.Framework" Version="2019.508.0" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.23.0" />
|
<PackageReference Include="SharpCompress" Version="0.23.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" />
|
||||||
|
Loading…
Reference in New Issue
Block a user