mirror of
https://github.com/ppy/osu.git
synced 2024-12-14 14:32:55 +08:00
Merge remote-tracking branch 'refs/remotes/ppy/master' into user_profile_modes
This commit is contained in:
commit
ea492772cf
@ -54,7 +54,9 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
||||
|
||||
for (int i = 0; i < max_sprites; i++)
|
||||
{
|
||||
parts[i].InvalidationID = 0;
|
||||
// InvalidationID 1 forces an update of each part of the cursor trail the first time ApplyState is run on the draw node
|
||||
// This is to prevent garbage data from being sent to the vertex shader, resulting in visual issues on some platforms
|
||||
parts[i].InvalidationID = 1;
|
||||
parts[i].WasUpdated = true;
|
||||
}
|
||||
}
|
||||
|
50
osu.Game.Tests/Visual/Gameplay/TestSceneFailAnimation.cs
Normal file
50
osu.Game.Tests/Visual/Gameplay/TestSceneFailAnimation.cs
Normal file
@ -0,0 +1,50 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Screens.Play;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
public class TestSceneFailAnimation : AllPlayersTestScene
|
||||
{
|
||||
protected override Player CreatePlayer(Ruleset ruleset)
|
||||
{
|
||||
Mods.Value = Array.Empty<Mod>();
|
||||
return new FailPlayer();
|
||||
}
|
||||
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(AllPlayersTestScene),
|
||||
typeof(TestPlayer),
|
||||
typeof(Player),
|
||||
};
|
||||
|
||||
protected override void AddCheckSteps()
|
||||
{
|
||||
AddUntilStep("wait for fail", () => Player.HasFailed);
|
||||
AddUntilStep("wait for fail overlay", () => ((FailPlayer)Player).FailOverlay.State == Visibility.Visible);
|
||||
}
|
||||
|
||||
private class FailPlayer : TestPlayer
|
||||
{
|
||||
public new FailOverlay FailOverlay => base.FailOverlay;
|
||||
|
||||
public FailPlayer()
|
||||
: base(false, false)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
ScoreProcessor.FailConditions += _ => true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -113,7 +113,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
public void TestPauseAfterFail()
|
||||
{
|
||||
AddUntilStep("wait for fail", () => Player.HasFailed);
|
||||
AddAssert("fail overlay shown", () => Player.FailOverlayVisible);
|
||||
AddUntilStep("fail overlay shown", () => Player.FailOverlayVisible);
|
||||
|
||||
confirmClockRunning(false);
|
||||
|
||||
|
@ -84,7 +84,6 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
testLocalCursor();
|
||||
testUserCursorOverride();
|
||||
testMultipleLocalCursors();
|
||||
ReturnUserInput();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -0,0 +1,194 @@
|
||||
// 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 NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Colour;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneOsuHoverContainer : ManualInputManagerTestScene
|
||||
{
|
||||
private OsuHoverTestContainer hoverContainer;
|
||||
private Box colourContainer;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp() => Schedule(() =>
|
||||
{
|
||||
Child = hoverContainer = new OsuHoverTestContainer
|
||||
{
|
||||
Enabled = { Value = true },
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(100),
|
||||
Child = colourContainer = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
};
|
||||
|
||||
doMoveOut();
|
||||
});
|
||||
|
||||
[Description("Checks IsHovered property value on a container when it is hovered/unhovered.")]
|
||||
[TestCase(true, TestName = "Enabled_Check_IsHovered")]
|
||||
[TestCase(false, TestName = "Disabled_Check_IsHovered")]
|
||||
public void TestIsHoveredHasProperValue(bool isEnabled)
|
||||
{
|
||||
setContainerEnabledTo(isEnabled);
|
||||
|
||||
checkNotHovered();
|
||||
|
||||
moveToText();
|
||||
checkHovered();
|
||||
|
||||
moveOut();
|
||||
checkNotHovered();
|
||||
|
||||
moveToText();
|
||||
checkHovered();
|
||||
|
||||
moveOut();
|
||||
checkNotHovered();
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Description("Checks colour fading on an enabled container when it is hovered/unhovered.")]
|
||||
public void TestTransitionWhileEnabled()
|
||||
{
|
||||
enableContainer();
|
||||
|
||||
checkColour(OsuHoverTestContainer.IDLE_COLOUR);
|
||||
|
||||
moveToText();
|
||||
waitUntilColourIs(OsuHoverTestContainer.HOVER_COLOUR);
|
||||
|
||||
moveOut();
|
||||
waitUntilColourIs(OsuHoverTestContainer.IDLE_COLOUR);
|
||||
|
||||
moveToText();
|
||||
waitUntilColourIs(OsuHoverTestContainer.HOVER_COLOUR);
|
||||
|
||||
moveOut();
|
||||
waitUntilColourIs(OsuHoverTestContainer.IDLE_COLOUR);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Description("Checks colour fading on a disabled container when it is hovered/unhovered.")]
|
||||
public void TestNoTransitionWhileDisabled()
|
||||
{
|
||||
disableContainer();
|
||||
|
||||
checkColour(OsuHoverTestContainer.IDLE_COLOUR);
|
||||
|
||||
moveToText();
|
||||
checkColour(OsuHoverTestContainer.IDLE_COLOUR);
|
||||
|
||||
moveOut();
|
||||
checkColour(OsuHoverTestContainer.IDLE_COLOUR);
|
||||
|
||||
moveToText();
|
||||
checkColour(OsuHoverTestContainer.IDLE_COLOUR);
|
||||
|
||||
moveOut();
|
||||
checkColour(OsuHoverTestContainer.IDLE_COLOUR);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Description("Checks that when a disabled & hovered container gets enabled, colour fading happens")]
|
||||
public void TestBecomesEnabledTransition()
|
||||
{
|
||||
disableContainer();
|
||||
checkColour(OsuHoverTestContainer.IDLE_COLOUR);
|
||||
|
||||
moveToText();
|
||||
checkColour(OsuHoverTestContainer.IDLE_COLOUR);
|
||||
|
||||
enableContainer();
|
||||
waitUntilColourIs(OsuHoverTestContainer.HOVER_COLOUR);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Description("Checks that when an enabled & hovered container gets disabled, colour fading happens")]
|
||||
public void TestBecomesDisabledTransition()
|
||||
{
|
||||
enableContainer();
|
||||
checkColour(OsuHoverTestContainer.IDLE_COLOUR);
|
||||
|
||||
moveToText();
|
||||
waitUntilColourIs(OsuHoverTestContainer.HOVER_COLOUR);
|
||||
|
||||
disableContainer();
|
||||
waitUntilColourIs(OsuHoverTestContainer.IDLE_COLOUR);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Description("Checks that when a hovered container gets enabled and disabled multiple times, colour fading happens")]
|
||||
public void TestDisabledChangesMultipleTimes()
|
||||
{
|
||||
enableContainer();
|
||||
checkColour(OsuHoverTestContainer.IDLE_COLOUR);
|
||||
|
||||
moveToText();
|
||||
waitUntilColourIs(OsuHoverTestContainer.HOVER_COLOUR);
|
||||
|
||||
disableContainer();
|
||||
waitUntilColourIs(OsuHoverTestContainer.IDLE_COLOUR);
|
||||
|
||||
enableContainer();
|
||||
waitUntilColourIs(OsuHoverTestContainer.HOVER_COLOUR);
|
||||
|
||||
disableContainer();
|
||||
waitUntilColourIs(OsuHoverTestContainer.IDLE_COLOUR);
|
||||
}
|
||||
|
||||
private void enableContainer() => setContainerEnabledTo(true);
|
||||
|
||||
private void disableContainer() => setContainerEnabledTo(false);
|
||||
|
||||
private void setContainerEnabledTo(bool newValue)
|
||||
{
|
||||
string word = newValue ? "Enable" : "Disable";
|
||||
AddStep($"{word} container", () => hoverContainer.Enabled.Value = newValue);
|
||||
}
|
||||
|
||||
private void moveToText() => AddStep("Move mouse to text", () => InputManager.MoveMouseTo(hoverContainer));
|
||||
|
||||
private void moveOut() => AddStep("Move out", doMoveOut);
|
||||
|
||||
private void checkHovered() => AddAssert("Check hovered", () => hoverContainer.IsHovered);
|
||||
|
||||
private void checkNotHovered() => AddAssert("Check not hovered", () => !hoverContainer.IsHovered);
|
||||
|
||||
private void checkColour(ColourInfo expectedColour)
|
||||
=> AddAssert($"Check colour to be '{expectedColour}'", () => currentColour.Equals(expectedColour));
|
||||
|
||||
private void waitUntilColourIs(ColourInfo expectedColour)
|
||||
=> AddUntilStep($"Wait until hover colour is {expectedColour}", () => currentColour.Equals(expectedColour));
|
||||
|
||||
private ColourInfo currentColour => colourContainer.DrawColourInfo.Colour;
|
||||
|
||||
/// <summary>
|
||||
/// Moves the cursor to top left corner of the screen
|
||||
/// </summary>
|
||||
private void doMoveOut()
|
||||
=> InputManager.MoveMouseTo(new Vector2(InputManager.ScreenSpaceDrawQuad.TopLeft.X, InputManager.ScreenSpaceDrawQuad.TopLeft.Y));
|
||||
|
||||
private sealed class OsuHoverTestContainer : OsuHoverContainer
|
||||
{
|
||||
public static readonly Color4 HOVER_COLOUR = Color4.Red;
|
||||
public static readonly Color4 IDLE_COLOUR = Color4.Green;
|
||||
|
||||
public OsuHoverTestContainer()
|
||||
{
|
||||
HoverColour = HOVER_COLOUR;
|
||||
IdleColour = IDLE_COLOUR;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,10 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Track;
|
||||
@ -12,22 +16,24 @@ using osu.Game.Beatmaps;
|
||||
|
||||
namespace osu.Game.Audio
|
||||
{
|
||||
/// <summary>
|
||||
/// A central store for the retrieval of <see cref="PreviewTrack"/>s.
|
||||
/// </summary>
|
||||
public class PreviewTrackManager : Component
|
||||
{
|
||||
private readonly BindableDouble muteBindable = new BindableDouble();
|
||||
|
||||
private AudioManager audio;
|
||||
private ITrackStore trackStore;
|
||||
private PreviewTrackStore trackStore;
|
||||
|
||||
private TrackManagerPreviewTrack current;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(AudioManager audio, FrameworkConfigManager config)
|
||||
{
|
||||
trackStore = audio.GetTrackStore(new OnlineStore());
|
||||
// this is a temporary solution to get around muting ourselves.
|
||||
// todo: update this once we have a BackgroundTrackManager or similar.
|
||||
trackStore = new PreviewTrackStore(new OnlineStore());
|
||||
|
||||
audio.AddItem(trackStore);
|
||||
trackStore.AddAdjustment(AdjustableProperty.Volume, audio.VolumeTrack);
|
||||
|
||||
this.audio = audio;
|
||||
|
||||
@ -103,5 +109,46 @@ namespace osu.Game.Audio
|
||||
|
||||
protected override Track GetTrack() => trackManager.Get($"https://b.ppy.sh/preview/{beatmapSetInfo?.OnlineBeatmapSetID}.mp3");
|
||||
}
|
||||
|
||||
private class PreviewTrackStore : AudioCollectionManager<AdjustableAudioComponent>, ITrackStore
|
||||
{
|
||||
private readonly IResourceStore<byte[]> store;
|
||||
|
||||
internal PreviewTrackStore(IResourceStore<byte[]> store)
|
||||
{
|
||||
this.store = store;
|
||||
}
|
||||
|
||||
public Track GetVirtual(double length = double.PositiveInfinity)
|
||||
{
|
||||
if (IsDisposed) throw new ObjectDisposedException($"Cannot retrieve items for an already disposed {nameof(PreviewTrackStore)}");
|
||||
|
||||
var track = new TrackVirtual(length);
|
||||
AddItem(track);
|
||||
return track;
|
||||
}
|
||||
|
||||
public Track Get(string name)
|
||||
{
|
||||
if (IsDisposed) throw new ObjectDisposedException($"Cannot retrieve items for an already disposed {nameof(PreviewTrackStore)}");
|
||||
|
||||
if (string.IsNullOrEmpty(name)) return null;
|
||||
|
||||
var dataStream = store.GetStream(name);
|
||||
|
||||
if (dataStream == null)
|
||||
return null;
|
||||
|
||||
Track track = new TrackBass(dataStream);
|
||||
AddItem(track);
|
||||
return track;
|
||||
}
|
||||
|
||||
public Task<Track> GetAsync(string name) => Task.Run(() => Get(name));
|
||||
|
||||
public Stream GetStream(string name) => store.GetStream(name);
|
||||
|
||||
public IEnumerable<string> GetAvailableResources() => store.GetAvailableResources();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,8 +24,13 @@ namespace osu.Game.Graphics.Containers
|
||||
{
|
||||
Enabled.ValueChanged += e =>
|
||||
{
|
||||
if (!e.NewValue)
|
||||
unhover();
|
||||
if (isHovered)
|
||||
{
|
||||
if (e.NewValue)
|
||||
fadeIn();
|
||||
else
|
||||
fadeOut();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -33,28 +38,28 @@ namespace osu.Game.Graphics.Containers
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
if (isHovered)
|
||||
return false;
|
||||
|
||||
isHovered = true;
|
||||
|
||||
if (!Enabled.Value)
|
||||
return false;
|
||||
|
||||
EffectTargets.ForEach(d => d.FadeColour(HoverColour, FADE_DURATION, Easing.OutQuint));
|
||||
isHovered = true;
|
||||
fadeIn();
|
||||
|
||||
return base.OnHover(e);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(HoverLostEvent e)
|
||||
{
|
||||
unhover();
|
||||
base.OnHoverLost(e);
|
||||
}
|
||||
|
||||
private void unhover()
|
||||
{
|
||||
if (!isHovered)
|
||||
return;
|
||||
|
||||
isHovered = false;
|
||||
EffectTargets.ForEach(d => d.FadeColour(IdleColour, FADE_DURATION, Easing.OutQuint));
|
||||
fadeOut();
|
||||
|
||||
base.OnHoverLost(e);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
@ -69,5 +74,9 @@ namespace osu.Game.Graphics.Containers
|
||||
base.LoadComplete();
|
||||
EffectTargets.ForEach(d => d.FadeColour(IdleColour));
|
||||
}
|
||||
|
||||
private void fadeIn() => EffectTargets.ForEach(d => d.FadeColour(HoverColour, FADE_DURATION, Easing.OutQuint));
|
||||
|
||||
private void fadeOut() => EffectTargets.ForEach(d => d.FadeColour(IdleColour, FADE_DURATION, Easing.OutQuint));
|
||||
}
|
||||
}
|
||||
|
@ -1,40 +1,40 @@
|
||||
// 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 osuTK;
|
||||
using osuTK.Graphics;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Backgrounds;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Backgrounds;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Overlays.Mods.Sections;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Screens;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Overlays.Mods
|
||||
{
|
||||
public class ModSelectOverlay : WaveOverlayContainer
|
||||
{
|
||||
private const float content_width = 0.8f;
|
||||
|
||||
protected Color4 LowMultiplierColour, HighMultiplierColour;
|
||||
|
||||
protected readonly TriangleButton DeselectAllButton;
|
||||
protected readonly OsuSpriteText MultiplierLabel, UnrankedLabel;
|
||||
private readonly FillFlowContainer footerContainer;
|
||||
protected readonly TriangleButton CloseButton;
|
||||
|
||||
protected readonly OsuSpriteText MultiplierLabel;
|
||||
protected readonly OsuSpriteText UnrankedLabel;
|
||||
|
||||
protected override bool BlockNonPositionalInput => false;
|
||||
|
||||
@ -46,154 +46,14 @@ namespace osu.Game.Overlays.Mods
|
||||
|
||||
protected readonly IBindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>();
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load(OsuColour colours, IBindable<RulesetInfo> ruleset, AudioManager audio, Bindable<IReadOnlyList<Mod>> mods)
|
||||
{
|
||||
LowMultiplierColour = colours.Red;
|
||||
HighMultiplierColour = colours.Green;
|
||||
UnrankedLabel.Colour = colours.Blue;
|
||||
protected Color4 LowMultiplierColour;
|
||||
protected Color4 HighMultiplierColour;
|
||||
|
||||
Ruleset.BindTo(ruleset);
|
||||
if (mods != null) SelectedMods.BindTo(mods);
|
||||
|
||||
sampleOn = audio.Samples.Get(@"UI/check-on");
|
||||
sampleOff = audio.Samples.Get(@"UI/check-off");
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
Ruleset.BindValueChanged(rulesetChanged, true);
|
||||
SelectedMods.BindValueChanged(selectedModsChanged, true);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
|
||||
Ruleset.UnbindAll();
|
||||
SelectedMods.UnbindAll();
|
||||
}
|
||||
|
||||
private void rulesetChanged(ValueChangedEvent<RulesetInfo> e)
|
||||
{
|
||||
if (e.NewValue == null) return;
|
||||
|
||||
var instance = e.NewValue.CreateInstance();
|
||||
|
||||
foreach (ModSection section in ModSectionsContainer.Children)
|
||||
section.Mods = instance.GetModsFor(section.ModType);
|
||||
|
||||
// attempt to re-select any already selected mods.
|
||||
// this may be the first time we are receiving the ruleset, in which case they will still match.
|
||||
selectedModsChanged(new ValueChangedEvent<IReadOnlyList<Mod>>(SelectedMods.Value, SelectedMods.Value));
|
||||
|
||||
// write the mods back to the SelectedMods bindable in the case a change was not applicable.
|
||||
// this generally isn't required as the previous line will perform deselection; just here for safety.
|
||||
refreshSelectedMods();
|
||||
}
|
||||
|
||||
private void selectedModsChanged(ValueChangedEvent<IReadOnlyList<Mod>> e)
|
||||
{
|
||||
foreach (ModSection section in ModSectionsContainer.Children)
|
||||
section.SelectTypes(e.NewValue.Select(m => m.GetType()).ToList());
|
||||
|
||||
updateMods();
|
||||
}
|
||||
|
||||
private void updateMods()
|
||||
{
|
||||
double multiplier = 1.0;
|
||||
bool ranked = true;
|
||||
|
||||
foreach (Mod mod in SelectedMods.Value)
|
||||
{
|
||||
multiplier *= mod.ScoreMultiplier;
|
||||
ranked &= mod.Ranked;
|
||||
}
|
||||
|
||||
MultiplierLabel.Text = $"{multiplier:N2}x";
|
||||
if (multiplier > 1.0)
|
||||
MultiplierLabel.FadeColour(HighMultiplierColour, 200);
|
||||
else if (multiplier < 1.0)
|
||||
MultiplierLabel.FadeColour(LowMultiplierColour, 200);
|
||||
else
|
||||
MultiplierLabel.FadeColour(Color4.White, 200);
|
||||
|
||||
UnrankedLabel.FadeTo(ranked ? 0 : 1, 200);
|
||||
}
|
||||
|
||||
protected override void PopOut()
|
||||
{
|
||||
base.PopOut();
|
||||
|
||||
footerContainer.MoveToX(footerContainer.DrawSize.X, WaveContainer.DISAPPEAR_DURATION, Easing.InSine);
|
||||
footerContainer.FadeOut(WaveContainer.DISAPPEAR_DURATION, Easing.InSine);
|
||||
|
||||
foreach (ModSection section in ModSectionsContainer.Children)
|
||||
{
|
||||
section.ButtonsContainer.TransformSpacingTo(new Vector2(100f, 0f), WaveContainer.DISAPPEAR_DURATION, Easing.InSine);
|
||||
section.ButtonsContainer.MoveToX(100f, WaveContainer.DISAPPEAR_DURATION, Easing.InSine);
|
||||
section.ButtonsContainer.FadeOut(WaveContainer.DISAPPEAR_DURATION, Easing.InSine);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void PopIn()
|
||||
{
|
||||
base.PopIn();
|
||||
|
||||
footerContainer.MoveToX(0, WaveContainer.APPEAR_DURATION, Easing.OutQuint);
|
||||
footerContainer.FadeIn(WaveContainer.APPEAR_DURATION, Easing.OutQuint);
|
||||
|
||||
foreach (ModSection section in ModSectionsContainer.Children)
|
||||
{
|
||||
section.ButtonsContainer.TransformSpacingTo(new Vector2(50f, 0f), WaveContainer.APPEAR_DURATION, Easing.OutQuint);
|
||||
section.ButtonsContainer.MoveToX(0, WaveContainer.APPEAR_DURATION, Easing.OutQuint);
|
||||
section.ButtonsContainer.FadeIn(WaveContainer.APPEAR_DURATION, Easing.OutQuint);
|
||||
}
|
||||
}
|
||||
|
||||
public void DeselectAll()
|
||||
{
|
||||
foreach (ModSection section in ModSectionsContainer.Children)
|
||||
section.DeselectAll();
|
||||
|
||||
refreshSelectedMods();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deselect one or more mods.
|
||||
/// </summary>
|
||||
/// <param name="modTypes">The types of <see cref="Mod"/>s which should be deselected.</param>
|
||||
/// <param name="immediate">Set to true to bypass animations and update selections immediately.</param>
|
||||
public void DeselectTypes(Type[] modTypes, bool immediate = false)
|
||||
{
|
||||
if (modTypes.Length == 0) return;
|
||||
|
||||
foreach (ModSection section in ModSectionsContainer.Children)
|
||||
section.DeselectTypes(modTypes, immediate);
|
||||
}
|
||||
private const float content_width = 0.8f;
|
||||
private readonly FillFlowContainer footerContainer;
|
||||
|
||||
private SampleChannel sampleOn, sampleOff;
|
||||
|
||||
private void modButtonPressed(Mod selectedMod)
|
||||
{
|
||||
if (selectedMod != null)
|
||||
{
|
||||
if (State == Visibility.Visible) sampleOn?.Play();
|
||||
DeselectTypes(selectedMod.IncompatibleMods, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (State == Visibility.Visible) sampleOff?.Play();
|
||||
}
|
||||
|
||||
refreshSelectedMods();
|
||||
}
|
||||
|
||||
private void refreshSelectedMods() => SelectedMods.Value = ModSectionsContainer.Children.SelectMany(s => s.SelectedMods).ToArray();
|
||||
|
||||
public ModSelectOverlay()
|
||||
{
|
||||
Waves.FirstWaveColour = OsuColour.FromHex(@"19b0e2");
|
||||
@ -364,6 +224,16 @@ namespace osu.Game.Overlays.Mods
|
||||
Right = 20
|
||||
}
|
||||
},
|
||||
CloseButton = new TriangleButton
|
||||
{
|
||||
Width = 180,
|
||||
Text = "Close",
|
||||
Action = Hide,
|
||||
Margin = new MarginPadding
|
||||
{
|
||||
Right = 20
|
||||
}
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = @"Score Multiplier:",
|
||||
@ -401,5 +271,171 @@ namespace osu.Game.Overlays.Mods
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load(OsuColour colours, IBindable<RulesetInfo> ruleset, AudioManager audio, Bindable<IReadOnlyList<Mod>> mods)
|
||||
{
|
||||
LowMultiplierColour = colours.Red;
|
||||
HighMultiplierColour = colours.Green;
|
||||
UnrankedLabel.Colour = colours.Blue;
|
||||
|
||||
Ruleset.BindTo(ruleset);
|
||||
if (mods != null) SelectedMods.BindTo(mods);
|
||||
|
||||
sampleOn = audio.Samples.Get(@"UI/check-on");
|
||||
sampleOff = audio.Samples.Get(@"UI/check-off");
|
||||
}
|
||||
|
||||
public void DeselectAll()
|
||||
{
|
||||
foreach (var section in ModSectionsContainer.Children)
|
||||
section.DeselectAll();
|
||||
|
||||
refreshSelectedMods();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deselect one or more mods.
|
||||
/// </summary>
|
||||
/// <param name="modTypes">The types of <see cref="Mod"/>s which should be deselected.</param>
|
||||
/// <param name="immediate">Set to true to bypass animations and update selections immediately.</param>
|
||||
public void DeselectTypes(Type[] modTypes, bool immediate = false)
|
||||
{
|
||||
if (modTypes.Length == 0) return;
|
||||
|
||||
foreach (var section in ModSectionsContainer.Children)
|
||||
section.DeselectTypes(modTypes, immediate);
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
Ruleset.BindValueChanged(rulesetChanged, true);
|
||||
SelectedMods.BindValueChanged(selectedModsChanged, true);
|
||||
}
|
||||
|
||||
protected override void PopOut()
|
||||
{
|
||||
base.PopOut();
|
||||
|
||||
footerContainer.MoveToX(footerContainer.DrawSize.X, WaveContainer.DISAPPEAR_DURATION, Easing.InSine);
|
||||
footerContainer.FadeOut(WaveContainer.DISAPPEAR_DURATION, Easing.InSine);
|
||||
|
||||
foreach (var section in ModSectionsContainer.Children)
|
||||
{
|
||||
section.ButtonsContainer.TransformSpacingTo(new Vector2(100f, 0f), WaveContainer.DISAPPEAR_DURATION, Easing.InSine);
|
||||
section.ButtonsContainer.MoveToX(100f, WaveContainer.DISAPPEAR_DURATION, Easing.InSine);
|
||||
section.ButtonsContainer.FadeOut(WaveContainer.DISAPPEAR_DURATION, Easing.InSine);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void PopIn()
|
||||
{
|
||||
base.PopIn();
|
||||
|
||||
footerContainer.MoveToX(0, WaveContainer.APPEAR_DURATION, Easing.OutQuint);
|
||||
footerContainer.FadeIn(WaveContainer.APPEAR_DURATION, Easing.OutQuint);
|
||||
|
||||
foreach (var section in ModSectionsContainer.Children)
|
||||
{
|
||||
section.ButtonsContainer.TransformSpacingTo(new Vector2(50f, 0f), WaveContainer.APPEAR_DURATION, Easing.OutQuint);
|
||||
section.ButtonsContainer.MoveToX(0, WaveContainer.APPEAR_DURATION, Easing.OutQuint);
|
||||
section.ButtonsContainer.FadeIn(WaveContainer.APPEAR_DURATION, Easing.OutQuint);
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool OnKeyDown(KeyDownEvent e)
|
||||
{
|
||||
switch (e.Key)
|
||||
{
|
||||
case Key.Number1:
|
||||
DeselectAllButton.Click();
|
||||
return true;
|
||||
|
||||
case Key.Number2:
|
||||
CloseButton.Click();
|
||||
return true;
|
||||
}
|
||||
|
||||
return base.OnKeyDown(e);
|
||||
}
|
||||
|
||||
private void rulesetChanged(ValueChangedEvent<RulesetInfo> e)
|
||||
{
|
||||
if (e.NewValue == null) return;
|
||||
|
||||
var instance = e.NewValue.CreateInstance();
|
||||
|
||||
foreach (var section in ModSectionsContainer.Children)
|
||||
section.Mods = instance.GetModsFor(section.ModType);
|
||||
|
||||
// attempt to re-select any already selected mods.
|
||||
// this may be the first time we are receiving the ruleset, in which case they will still match.
|
||||
selectedModsChanged(new ValueChangedEvent<IReadOnlyList<Mod>>(SelectedMods.Value, SelectedMods.Value));
|
||||
|
||||
// write the mods back to the SelectedMods bindable in the case a change was not applicable.
|
||||
// this generally isn't required as the previous line will perform deselection; just here for safety.
|
||||
refreshSelectedMods();
|
||||
}
|
||||
|
||||
private void selectedModsChanged(ValueChangedEvent<IReadOnlyList<Mod>> e)
|
||||
{
|
||||
foreach (var section in ModSectionsContainer.Children)
|
||||
section.SelectTypes(e.NewValue.Select(m => m.GetType()).ToList());
|
||||
|
||||
updateMods();
|
||||
}
|
||||
|
||||
private void updateMods()
|
||||
{
|
||||
var multiplier = 1.0;
|
||||
var ranked = true;
|
||||
|
||||
foreach (var mod in SelectedMods.Value)
|
||||
{
|
||||
multiplier *= mod.ScoreMultiplier;
|
||||
ranked &= mod.Ranked;
|
||||
}
|
||||
|
||||
MultiplierLabel.Text = $"{multiplier:N2}x";
|
||||
if (multiplier > 1.0)
|
||||
MultiplierLabel.FadeColour(HighMultiplierColour, 200);
|
||||
else if (multiplier < 1.0)
|
||||
MultiplierLabel.FadeColour(LowMultiplierColour, 200);
|
||||
else
|
||||
MultiplierLabel.FadeColour(Color4.White, 200);
|
||||
|
||||
UnrankedLabel.FadeTo(ranked ? 0 : 1, 200);
|
||||
}
|
||||
|
||||
private void modButtonPressed(Mod selectedMod)
|
||||
{
|
||||
if (selectedMod != null)
|
||||
{
|
||||
if (State == Visibility.Visible) sampleOn?.Play();
|
||||
DeselectTypes(selectedMod.IncompatibleMods, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (State == Visibility.Visible) sampleOff?.Play();
|
||||
}
|
||||
|
||||
refreshSelectedMods();
|
||||
}
|
||||
|
||||
private void refreshSelectedMods() => SelectedMods.Value = ModSectionsContainer.Children.SelectMany(s => s.SelectedMods).ToArray();
|
||||
|
||||
#region Disposal
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
|
||||
Ruleset.UnbindAll();
|
||||
SelectedMods.UnbindAll();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
@ -49,7 +49,6 @@ namespace osu.Game.Overlays.Profile.Sections
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(0, 2),
|
||||
},
|
||||
MoreButton = new ShowMoreButton
|
||||
|
@ -31,6 +31,7 @@ namespace osu.Game.Overlays.Toolbar
|
||||
public ToolbarRulesetSelector()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Y;
|
||||
AutoSizeAxes = Axes.X;
|
||||
|
||||
Children = new[]
|
||||
{
|
||||
@ -111,12 +112,6 @@ namespace osu.Game.Overlays.Toolbar
|
||||
|
||||
private void disabledChanged(bool isDisabled) => this.FadeColour(isDisabled ? Color4.Gray : Color4.White, 300);
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
Size = new Vector2(modeButtons.DrawSize.X, 1);
|
||||
}
|
||||
|
||||
private void rulesetChanged(ValueChangedEvent<RulesetInfo> e)
|
||||
{
|
||||
foreach (ToolbarRulesetButton m in modeButtons.Children.Cast<ToolbarRulesetButton>())
|
||||
|
@ -53,7 +53,7 @@ namespace osu.Game.Rulesets.UI
|
||||
/// <summary>
|
||||
/// The playfield.
|
||||
/// </summary>
|
||||
public Playfield Playfield => playfield.Value;
|
||||
public override Playfield Playfield => playfield.Value;
|
||||
|
||||
/// <summary>
|
||||
/// Place to put drawables above hit objects but below UI.
|
||||
@ -342,6 +342,11 @@ namespace osu.Game.Rulesets.UI
|
||||
/// </summary>
|
||||
public readonly BindableBool IsPaused = new BindableBool();
|
||||
|
||||
/// <summary>
|
||||
/// The playfield.
|
||||
/// </summary>
|
||||
public abstract Playfield Playfield { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The frame-stable clock which is being used for playfield display.
|
||||
/// </summary>
|
||||
|
113
osu.Game/Screens/Play/FailAnimation.cs
Normal file
113
osu.Game/Screens/Play/FailAnimation.cs
Normal file
@ -0,0 +1,113 @@
|
||||
// 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.Audio;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Screens.Play
|
||||
{
|
||||
/// <summary>
|
||||
/// Manage the animation to be applied when a player fails.
|
||||
/// Single file; automatically disposed after use.
|
||||
/// </summary>
|
||||
public class FailAnimation : Component
|
||||
{
|
||||
public Action OnComplete;
|
||||
|
||||
private readonly DrawableRuleset drawableRuleset;
|
||||
|
||||
private readonly BindableDouble trackFreq = new BindableDouble(1);
|
||||
|
||||
private Track track;
|
||||
|
||||
private const float duration = 2500;
|
||||
|
||||
private SampleChannel failSample;
|
||||
|
||||
public FailAnimation(DrawableRuleset drawableRuleset)
|
||||
{
|
||||
this.drawableRuleset = drawableRuleset;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(AudioManager audio, IBindable<WorkingBeatmap> beatmap)
|
||||
{
|
||||
track = beatmap.Value.Track;
|
||||
failSample = audio.Samples.Get(@"Gameplay/failsound");
|
||||
}
|
||||
|
||||
private bool started;
|
||||
|
||||
/// <summary>
|
||||
/// Start the fail animation playing.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">Thrown if started more than once.</exception>
|
||||
public void Start()
|
||||
{
|
||||
if (started) throw new InvalidOperationException("Animation cannot be started more than once.");
|
||||
|
||||
started = true;
|
||||
|
||||
failSample.Play();
|
||||
|
||||
this.TransformBindableTo(trackFreq, 0, duration).OnComplete(_ =>
|
||||
{
|
||||
OnComplete?.Invoke();
|
||||
Expire();
|
||||
});
|
||||
|
||||
track.AddAdjustment(AdjustableProperty.Frequency, trackFreq);
|
||||
|
||||
applyToPlayfield(drawableRuleset.Playfield);
|
||||
drawableRuleset.Playfield.HitObjectContainer.FlashColour(Color4.Red, 500);
|
||||
drawableRuleset.Playfield.HitObjectContainer.FadeOut(duration / 2);
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
if (!started)
|
||||
return;
|
||||
|
||||
applyToPlayfield(drawableRuleset.Playfield);
|
||||
}
|
||||
|
||||
private readonly List<DrawableHitObject> appliedObjects = new List<DrawableHitObject>();
|
||||
|
||||
private void applyToPlayfield(Playfield playfield)
|
||||
{
|
||||
foreach (var nested in playfield.NestedPlayfields)
|
||||
applyToPlayfield(nested);
|
||||
|
||||
foreach (DrawableHitObject obj in playfield.HitObjectContainer.AliveObjects)
|
||||
{
|
||||
if (appliedObjects.Contains(obj))
|
||||
continue;
|
||||
|
||||
obj.RotateTo(RNG.NextSingle(-90, 90), duration);
|
||||
obj.ScaleTo(obj.Scale * 0.5f, duration);
|
||||
obj.MoveToOffset(new Vector2(0, 400), duration);
|
||||
appliedObjects.Add(obj);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
track?.RemoveAdjustment(AdjustableProperty.Frequency, trackFreq);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
// 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.
|
||||
|
||||
using System;
|
||||
@ -173,7 +173,8 @@ namespace osu.Game.Screens.Play
|
||||
fadeOut(true);
|
||||
Restart();
|
||||
},
|
||||
}
|
||||
},
|
||||
failAnimation = new FailAnimation(DrawableRuleset) { OnComplete = onFailComplete, }
|
||||
};
|
||||
|
||||
DrawableRuleset.HasReplayLoaded.BindValueChanged(e => HUDOverlay.HoldToQuit.PauseOnFocusLost = !e.NewValue && PauseOnFocusLost, true);
|
||||
@ -345,13 +346,13 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
protected FailOverlay FailOverlay { get; private set; }
|
||||
|
||||
private FailAnimation failAnimation;
|
||||
|
||||
private bool onFail()
|
||||
{
|
||||
if (Mods.Value.OfType<IApplicableFailOverride>().Any(m => !m.AllowFail))
|
||||
return false;
|
||||
|
||||
GameplayClockContainer.Stop();
|
||||
|
||||
HasFailed = true;
|
||||
|
||||
// There is a chance that we could be in a paused state as the ruleset's internal clock (see FrameStabilityContainer)
|
||||
@ -360,9 +361,17 @@ namespace osu.Game.Screens.Play
|
||||
if (PauseOverlay.State == Visibility.Visible)
|
||||
PauseOverlay.Hide();
|
||||
|
||||
failAnimation.Start();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Called back when the transform finishes
|
||||
private void onFailComplete()
|
||||
{
|
||||
GameplayClockContainer.Stop();
|
||||
|
||||
FailOverlay.Retries = RestartCount;
|
||||
FailOverlay.Show();
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -489,6 +498,13 @@ namespace osu.Game.Screens.Play
|
||||
// still want to block if we are within the cooldown period and not already paused.
|
||||
return true;
|
||||
|
||||
if (HasFailed && ValidForResume && !FailOverlay.IsPresent)
|
||||
// ValidForResume is false when restarting
|
||||
{
|
||||
failAnimation.FinishTransforms(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
GameplayClockContainer.ResetLocalAdjustments();
|
||||
|
||||
fadeOut();
|
||||
|
@ -3,8 +3,13 @@
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Testing.Input;
|
||||
using osu.Game.Graphics.Cursor;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Tests.Visual
|
||||
{
|
||||
@ -15,21 +20,92 @@ namespace osu.Game.Tests.Visual
|
||||
|
||||
protected readonly ManualInputManager InputManager;
|
||||
|
||||
private readonly TriangleButton buttonTest;
|
||||
private readonly TriangleButton buttonLocal;
|
||||
|
||||
protected ManualInputManagerTestScene()
|
||||
{
|
||||
base.Content.Add(InputManager = new ManualInputManager
|
||||
base.Content.AddRange(new Drawable[]
|
||||
{
|
||||
UseParentInput = true,
|
||||
Child = content = new MenuCursorContainer { RelativeSizeAxes = Axes.Both },
|
||||
InputManager = new ManualInputManager
|
||||
{
|
||||
UseParentInput = true,
|
||||
Child = content = new MenuCursorContainer { RelativeSizeAxes = Axes.Both },
|
||||
},
|
||||
new Container
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
Margin = new MarginPadding(5),
|
||||
CornerRadius = 5,
|
||||
Masking = true,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
Colour = Color4.Black,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0.5f,
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Vertical,
|
||||
Margin = new MarginPadding(5),
|
||||
Spacing = new Vector2(5),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Text = "Input Priority"
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Margin = new MarginPadding(5),
|
||||
Spacing = new Vector2(5),
|
||||
Direction = FillDirection.Horizontal,
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
buttonLocal = new TriangleButton
|
||||
{
|
||||
Text = "local",
|
||||
Size = new Vector2(50, 30),
|
||||
Action = returnUserInput
|
||||
},
|
||||
buttonTest = new TriangleButton
|
||||
{
|
||||
Text = "test",
|
||||
Size = new Vector2(50, 30),
|
||||
Action = returnTestInput
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns input back to the user.
|
||||
/// </summary>
|
||||
protected void ReturnUserInput()
|
||||
protected override void Update()
|
||||
{
|
||||
AddStep("Return user input", () => InputManager.UseParentInput = true);
|
||||
base.Update();
|
||||
|
||||
buttonTest.Enabled.Value = InputManager.UseParentInput;
|
||||
buttonLocal.Enabled.Value = !InputManager.UseParentInput;
|
||||
}
|
||||
|
||||
private void returnUserInput() =>
|
||||
InputManager.UseParentInput = true;
|
||||
|
||||
private void returnTestInput() =>
|
||||
InputManager.UseParentInput = false;
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.4" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.518.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2019.606.1" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2019.607.0" />
|
||||
<PackageReference Include="SharpCompress" Version="0.23.0" />
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
||||
|
@ -104,9 +104,9 @@
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.128.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2019.606.1" />
|
||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2019.606.1" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.518.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2019.607.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2019.607.0" />
|
||||
<PackageReference Include="SharpCompress" Version="0.22.0" />
|
||||
<PackageReference Include="NUnit" Version="3.11.0" />
|
||||
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
||||
|
Loading…
Reference in New Issue
Block a user