1
0
mirror of https://github.com/ppy/osu.git synced 2025-03-19 07:07:18 +08:00

Merge branch 'master' into add-spectate-button-and-state

This commit is contained in:
smoogipoo 2021-04-07 22:07:52 +09:00
commit 99bee73ac1
21 changed files with 215 additions and 88 deletions

View File

@ -24,7 +24,7 @@
"Templates\\Rulesets\\ruleset-scrolling-empty\\osu.Game.Rulesets.EmptyScrolling\\osu.Game.Rulesets.EmptyScrolling.csproj",
"Templates\\Rulesets\\ruleset-scrolling-empty\\osu.Game.Rulesets.EmptyScrolling.Tests\\osu.Game.Rulesets.EmptyScrolling.Tests.csproj",
"Templates\\Rulesets\\ruleset-scrolling-example\\osu.Game.Rulesets.Pippidon\\osu.Game.Rulesets.Pippidon.csproj",
"Templates\\Rulesets\\ruleset-scrolling-example\\osu.Game.Rulesets.Pippidon.Tests\\osu.Game.Rulesets.Pippidon.Tests.csproj",
"Templates\\Rulesets\\ruleset-scrolling-example\\osu.Game.Rulesets.Pippidon.Tests\\osu.Game.Rulesets.Pippidon.Tests.csproj"
]
}
}
}

View File

@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Osu.Tests
get
{
if (content == null)
base.Content.Add(content = new OsuInputManager(new RulesetInfo { ID = 0 }));
base.Content.Add(content = new OsuInputManager(new OsuRuleset().RulesetInfo));
return content;
}

View File

@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
[BackgroundDependencyLoader]
private void load()
{
SetContents(() => new TaikoInputManager(new RulesetInfo { ID = 1 })
SetContents(() => new TaikoInputManager(new TaikoRuleset().RulesetInfo)
{
RelativeSizeAxes = Axes.Both,
Child = new Container

View File

@ -740,6 +740,36 @@ namespace osu.Game.Tests.Beatmaps.Formats
Assert.That(fifth.ControlPoints[5].Type.Value, Is.EqualTo(PathType.Bezier));
Assert.That(fifth.ControlPoints[6].Position.Value, Is.EqualTo(new Vector2(5, 5)));
Assert.That(fifth.ControlPoints[6].Type.Value, Is.EqualTo(null));
// Implicit perfect-curve multi-segment(Should convert to bezier to match stable)
var sixth = ((IHasPath)decoded.HitObjects[5]).Path;
Assert.That(sixth.ControlPoints[0].Position.Value, Is.EqualTo(Vector2.Zero));
Assert.That(sixth.ControlPoints[0].Type.Value == PathType.Bezier);
Assert.That(sixth.ControlPoints[1].Position.Value, Is.EqualTo(new Vector2(75, 145)));
Assert.That(sixth.ControlPoints[1].Type.Value == null);
Assert.That(sixth.ControlPoints[2].Position.Value, Is.EqualTo(new Vector2(170, 75)));
Assert.That(sixth.ControlPoints[2].Type.Value == PathType.Bezier);
Assert.That(sixth.ControlPoints[3].Position.Value, Is.EqualTo(new Vector2(300, 145)));
Assert.That(sixth.ControlPoints[3].Type.Value == null);
Assert.That(sixth.ControlPoints[4].Position.Value, Is.EqualTo(new Vector2(410, 20)));
Assert.That(sixth.ControlPoints[4].Type.Value == null);
// Explicit perfect-curve multi-segment(Should not convert to bezier)
var seventh = ((IHasPath)decoded.HitObjects[6]).Path;
Assert.That(seventh.ControlPoints[0].Position.Value, Is.EqualTo(Vector2.Zero));
Assert.That(seventh.ControlPoints[0].Type.Value == PathType.PerfectCurve);
Assert.That(seventh.ControlPoints[1].Position.Value, Is.EqualTo(new Vector2(75, 145)));
Assert.That(seventh.ControlPoints[1].Type.Value == null);
Assert.That(seventh.ControlPoints[2].Position.Value, Is.EqualTo(new Vector2(170, 75)));
Assert.That(seventh.ControlPoints[2].Type.Value == PathType.PerfectCurve);
Assert.That(seventh.ControlPoints[3].Position.Value, Is.EqualTo(new Vector2(300, 145)));
Assert.That(seventh.ControlPoints[3].Type.Value == null);
Assert.That(seventh.ControlPoints[4].Position.Value, Is.EqualTo(new Vector2(410, 20)));
Assert.That(seventh.ControlPoints[4].Type.Value == null);
}
}
}

View File

@ -38,7 +38,7 @@ namespace osu.Game.Tests.Online
private BeatmapSetInfo testBeatmapSet;
private readonly Bindable<PlaylistItem> selectedItem = new Bindable<PlaylistItem>();
private OnlinePlayBeatmapAvailablilityTracker availablilityTracker;
private OnlinePlayBeatmapAvailabilityTracker availabilityTracker;
[BackgroundDependencyLoader]
private void load(AudioManager audio, GameHost host)
@ -67,7 +67,7 @@ namespace osu.Game.Tests.Online
Ruleset = { Value = testBeatmapInfo.Ruleset },
};
Child = availablilityTracker = new OnlinePlayBeatmapAvailablilityTracker
Child = availabilityTracker = new OnlinePlayBeatmapAvailabilityTracker
{
SelectedItem = { BindTarget = selectedItem, }
};
@ -118,7 +118,7 @@ namespace osu.Game.Tests.Online
});
addAvailabilityCheckStep("state still not downloaded", BeatmapAvailability.NotDownloaded);
AddStep("recreate tracker", () => Child = availablilityTracker = new OnlinePlayBeatmapAvailablilityTracker
AddStep("recreate tracker", () => Child = availabilityTracker = new OnlinePlayBeatmapAvailabilityTracker
{
SelectedItem = { BindTarget = selectedItem }
});
@ -127,7 +127,7 @@ namespace osu.Game.Tests.Online
private void addAvailabilityCheckStep(string description, Func<BeatmapAvailability> expected)
{
AddAssert(description, () => availablilityTracker.Availability.Value.Equals(expected.Invoke()));
AddAssert(description, () => availabilityTracker.Availability.Value.Equals(expected.Invoke()));
}
private static BeatmapInfo getTestBeatmapInfo(string archiveFile)

View File

@ -15,3 +15,10 @@ osu file format v128
// Last control point in segment duplicated
0,0,5000,2,0,B|1:1|2:2|3:3|3:3|B|4:4|5:5,2,200
// Implicit perfect-curve multi-segment (Should convert to bezier to match stable)
0,0,6000,2,0,P|75:145|170:75|170:75|300:145|410:20,1,475,0:0:0:0:
// Explicit perfect-curve multi-segment (Should not convert to bezier)
0,0,7000,2,0,P|75:145|P|170:75|300:145|410:20,1,650,0:0:0:0:

View File

@ -27,7 +27,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
public class TestSceneMultiplayerReadyButton : MultiplayerTestScene
{
private MultiplayerReadyButton button;
private OnlinePlayBeatmapAvailablilityTracker beatmapTracker;
private OnlinePlayBeatmapAvailabilityTracker beatmapTracker;
private BeatmapSetInfo importedSet;
private readonly Bindable<PlaylistItem> selectedItem = new Bindable<PlaylistItem>();
@ -44,7 +44,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default));
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).Wait();
Add(beatmapTracker = new OnlinePlayBeatmapAvailablilityTracker
Add(beatmapTracker = new OnlinePlayBeatmapAvailabilityTracker
{
SelectedItem = { BindTarget = selectedItem }
});

View File

@ -0,0 +1,35 @@
// 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.Graphics;
using osu.Game.Screens.Select;
namespace osu.Game.Tests.Visual.SongSelect
{
public class TestSceneSongSelectFooter : OsuManualInputManagerTestScene
{
public TestSceneSongSelectFooter()
{
AddStep("Create footer", () =>
{
Footer footer;
AddRange(new Drawable[]
{
footer = new Footer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
}
});
footer.AddButton(new FooterButtonMods(), null);
footer.AddButton(new FooterButtonRandom
{
NextRandom = () => { },
PreviousRandom = () => { },
}, null);
footer.AddButton(new FooterButtonOptions(), null);
});
}
}
}

View File

@ -333,9 +333,10 @@ namespace osu.Game.Beatmaps.Formats
// Explicit segments have a new format in which the type is injected into the middle of the control point string.
// To preserve compatibility with osu-stable as much as possible, explicit segments with the same type are converted to use implicit segments by duplicating the control point.
bool needsExplicitSegment = point.Type.Value != lastType;
// One exception are consecutive perfect curves, which aren't supported in osu!stable and can lead to decoding issues if encoded as implicit segments
bool needsExplicitSegment = point.Type.Value != lastType || point.Type.Value == PathType.PerfectCurve;
// One exception to this is when the last two control points of the last segment were duplicated. This is not a scenario supported by osu!stable.
// Another exception to this is when the last two control points of the last segment were duplicated. This is not a scenario supported by osu!stable.
// Lazer does not add implicit segments for the last two control points of _any_ explicit segment, so an explicit segment is forced in order to maintain consistency with the decoder.
if (i > 1)
{

View File

@ -64,12 +64,20 @@ namespace osu.Game.Input.Bindings
protected override void ReloadMappings()
{
var defaults = DefaultKeyBindings.ToList();
if (ruleset != null && !ruleset.ID.HasValue)
// if the provided ruleset is not stored to the database, we have no way to retrieve custom bindings.
// fallback to defaults instead.
KeyBindings = DefaultKeyBindings;
KeyBindings = defaults;
else
KeyBindings = store.Query(ruleset?.ID, variant).ToList();
{
KeyBindings = store.Query(ruleset?.ID, variant)
// this ordering is important to ensure that we read entries from the database in the order
// enforced by DefaultKeyBindings. allow for song select to handle actions that may otherwise
// have been eaten by the music controller due to query order.
.OrderBy(b => defaults.FindIndex(d => (int)d.Action == b.IntAction)).ToList();
}
}
}
}

View File

@ -27,7 +27,11 @@ namespace osu.Game.Input.Bindings
handler = game;
}
public override IEnumerable<IKeyBinding> DefaultKeyBindings => GlobalKeyBindings.Concat(InGameKeyBindings).Concat(AudioControlKeyBindings).Concat(EditorKeyBindings);
public override IEnumerable<IKeyBinding> DefaultKeyBindings => GlobalKeyBindings
.Concat(EditorKeyBindings)
.Concat(InGameKeyBindings)
.Concat(SongSelectKeyBindings)
.Concat(AudioControlKeyBindings);
public IEnumerable<KeyBinding> GlobalKeyBindings => new[]
{
@ -80,6 +84,14 @@ namespace osu.Game.Input.Bindings
new KeyBinding(InputKey.Control, GlobalAction.HoldForHUD),
};
public IEnumerable<KeyBinding> SongSelectKeyBindings => new[]
{
new KeyBinding(InputKey.F1, GlobalAction.ToggleModSelection),
new KeyBinding(InputKey.F2, GlobalAction.SelectNextRandom),
new KeyBinding(new[] { InputKey.Shift, InputKey.F2 }, GlobalAction.SelectPreviousRandom),
new KeyBinding(InputKey.F3, GlobalAction.ToggleBeatmapOptions)
};
public IEnumerable<KeyBinding> AudioControlKeyBindings => new[]
{
new KeyBinding(new[] { InputKey.Alt, InputKey.Up }, GlobalAction.IncreaseVolume),
@ -217,5 +229,18 @@ namespace osu.Game.Input.Bindings
[Description("Toggle in-game interface")]
ToggleInGameInterface,
// Song select keybindings
[Description("Toggle Mod Select")]
ToggleModSelection,
[Description("Random")]
SelectNextRandom,
[Description("Rewind")]
SelectPreviousRandom,
[Description("Beatmap Options")]
ToggleBeatmapOptions,
}
}

View File

@ -16,7 +16,7 @@ namespace osu.Game.Online.Rooms
/// This differs from a regular download tracking composite as this accounts for the
/// databased beatmap set's checksum, to disallow from playing with an altered version of the beatmap.
/// </summary>
public class OnlinePlayBeatmapAvailablilityTracker : DownloadTrackingComposite<BeatmapSetInfo, BeatmapManager>
public class OnlinePlayBeatmapAvailabilityTracker : DownloadTrackingComposite<BeatmapSetInfo, BeatmapManager>
{
public readonly IBindable<PlaylistItem> SelectedItem = new Bindable<PlaylistItem>();

View File

@ -308,17 +308,15 @@ namespace osu.Game
AddInternal(RulesetConfigCache);
MenuCursorContainer = new MenuCursorContainer { RelativeSizeAxes = Axes.Both };
GlobalInputManager globalInput;
MenuCursorContainer.Child = globalInput = new GlobalInputManager(this)
var globalInput = new GlobalInputManager(this)
{
RelativeSizeAxes = Axes.Both,
Child = content = new OsuTooltipContainer(MenuCursorContainer.Cursor) { RelativeSizeAxes = Axes.Both }
Child = MenuCursorContainer = new MenuCursorContainer { RelativeSizeAxes = Axes.Both }
};
base.Content.Add(CreateScalingContainer().WithChild(MenuCursorContainer));
MenuCursorContainer.Child = content = new OsuTooltipContainer(MenuCursorContainer.Cursor) { RelativeSizeAxes = Axes.Both };
base.Content.Add(CreateScalingContainer().WithChild(globalInput));
KeyBindingStore.Register(globalInput.GlobalBindings);
dependencies.Cache(globalInput.GlobalBindings);

View File

@ -21,6 +21,7 @@ namespace osu.Game.Overlays.KeyBinding
{
Add(new DefaultBindingsSubsection(manager));
Add(new AudioControlKeyBindingsSubsection(manager));
Add(new SongSelectKeyBindingSubsection(manager));
Add(new InGameKeyBindingsSubsection(manager));
Add(new EditorKeyBindingsSubsection(manager));
}
@ -36,6 +37,17 @@ namespace osu.Game.Overlays.KeyBinding
}
}
private class SongSelectKeyBindingSubsection : KeyBindingsSubsection
{
protected override string Header => "Song Select";
public SongSelectKeyBindingSubsection(GlobalActionContainer manager)
: base(null)
{
Defaults = manager.SongSelectKeyBindings;
}
}
private class InGameKeyBindingsSubsection : KeyBindingsSubsection
{
protected override string Header => "In Game";

View File

@ -16,7 +16,7 @@ namespace osu.Game.Screens.OnlinePlay.Components
private IBindable<BeatmapAvailability> availability;
[BackgroundDependencyLoader]
private void load(OnlinePlayBeatmapAvailablilityTracker beatmapTracker)
private void load(OnlinePlayBeatmapAvailabilityTracker beatmapTracker)
{
availability = beatmapTracker.Availability.GetBoundCopy();

View File

@ -56,15 +56,15 @@ namespace osu.Game.Screens.OnlinePlay.Match
private IBindable<WeakReference<BeatmapSetInfo>> managerUpdated;
[Cached]
protected OnlinePlayBeatmapAvailablilityTracker BeatmapAvailablilityTracker { get; }
protected OnlinePlayBeatmapAvailabilityTracker BeatmapAvailabilityTracker { get; }
protected IBindable<BeatmapAvailability> BeatmapAvailability => BeatmapAvailablilityTracker.Availability;
protected IBindable<BeatmapAvailability> BeatmapAvailability => BeatmapAvailabilityTracker.Availability;
protected RoomSubScreen()
{
AddRangeInternal(new Drawable[]
{
BeatmapAvailablilityTracker = new OnlinePlayBeatmapAvailablilityTracker
BeatmapAvailabilityTracker = new OnlinePlayBeatmapAvailabilityTracker
{
SelectedItem = { BindTarget = SelectedItem }
},

View File

@ -4,7 +4,6 @@
using System;
using osuTK;
using osuTK.Graphics;
using osuTK.Input;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
@ -13,10 +12,12 @@ using osu.Framework.Input.Events;
using osu.Framework.Localisation;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.Containers;
using osu.Game.Input.Bindings;
using osu.Framework.Input.Bindings;
namespace osu.Game.Screens.Select
{
public class FooterButton : OsuClickableContainer
public class FooterButton : OsuClickableContainer, IKeyBindingHandler<GlobalAction>
{
public const float SHEAR_WIDTH = 7.5f;
@ -105,6 +106,7 @@ namespace osu.Game.Screens.Select
AutoSizeAxes = Axes.Both,
Child = SpriteText = new OsuSpriteText
{
AlwaysPresent = true,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
}
@ -118,7 +120,7 @@ namespace osu.Game.Screens.Select
public Action Hovered;
public Action HoverLost;
public Key? Hotkey;
public GlobalAction? Hotkey;
protected override void UpdateAfterChildren()
{
@ -168,15 +170,17 @@ namespace osu.Game.Screens.Select
return base.OnClick(e);
}
protected override bool OnKeyDown(KeyDownEvent e)
public virtual bool OnPressed(GlobalAction action)
{
if (!e.Repeat && e.Key == Hotkey)
if (action == Hotkey)
{
Click();
return true;
}
return base.OnKeyDown(e);
return false;
}
public virtual void OnReleased(GlobalAction action) { }
}
}

View File

@ -14,7 +14,7 @@ using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osuTK;
using osuTK.Graphics;
using osuTK.Input;
using osu.Game.Input.Bindings;
namespace osu.Game.Screens.Select
{
@ -57,7 +57,7 @@ namespace osu.Game.Screens.Select
lowMultiplierColour = colours.Red;
highMultiplierColour = colours.Green;
Text = @"mods";
Hotkey = Key.F1;
Hotkey = GlobalAction.ToggleModSelection;
}
protected override void LoadComplete()

View File

@ -4,7 +4,7 @@
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Game.Graphics;
using osuTK.Input;
using osu.Game.Input.Bindings;
namespace osu.Game.Screens.Select
{
@ -16,7 +16,7 @@ namespace osu.Game.Screens.Select
SelectedColour = colours.Blue;
DeselectedColour = SelectedColour.Opacity(0.5f);
Text = @"options";
Hotkey = Key.F3;
Hotkey = GlobalAction.ToggleBeatmapOptions;
}
}
}

View File

@ -1,35 +1,23 @@
// 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 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;
using osu.Game.Input.Bindings;
using osuTK;
namespace osu.Game.Screens.Select
{
public class FooterButtonRandom : FooterButton
{
private readonly SpriteText secondaryText;
private bool secondaryActive;
public Action NextRandom { get; set; }
public Action PreviousRandom { get; set; }
public FooterButtonRandom()
{
TextContainer.Add(secondaryText = new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Text = @"rewind",
Alpha = 0,
});
// force both text sprites to always be present to avoid width flickering while they're being swapped out
SpriteText.AlwaysPresent = secondaryText.AlwaysPresent = true;
}
private bool rewindSearch;
[BackgroundDependencyLoader]
private void load(OsuColour colours)
@ -37,34 +25,57 @@ namespace osu.Game.Screens.Select
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 void OnKeyUp(KeyUpEvent e)
{
secondaryActive = e.ShiftPressed;
updateText();
base.OnKeyUp(e);
}
private void updateText()
{
if (secondaryActive)
Action = () =>
{
SpriteText.FadeOut(120, Easing.InQuad);
secondaryText.FadeIn(120, Easing.InQuad);
if (rewindSearch)
{
const double fade_time = 500;
OsuSpriteText rewindSpriteText;
TextContainer.Add(rewindSpriteText = new OsuSpriteText
{
Alpha = 0,
Text = @"rewind",
AlwaysPresent = true, // make sure the button is sized large enough to always show this
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
});
rewindSpriteText.FadeOutFromOne(fade_time, Easing.In);
rewindSpriteText.MoveTo(Vector2.Zero).MoveTo(new Vector2(0, 10), fade_time, Easing.In);
rewindSpriteText.Expire();
SpriteText.FadeInFromZero(fade_time, Easing.In);
PreviousRandom.Invoke();
}
else
{
NextRandom.Invoke();
}
};
}
public override bool OnPressed(GlobalAction action)
{
rewindSearch = action == GlobalAction.SelectPreviousRandom;
if (action != GlobalAction.SelectNextRandom && action != GlobalAction.SelectPreviousRandom)
{
return false;
}
else
Click();
return true;
}
public override void OnReleased(GlobalAction action)
{
if (action == GlobalAction.SelectPreviousRandom)
{
SpriteText.FadeIn(120, Easing.InQuad);
secondaryText.FadeOut(120, Easing.InQuad);
rewindSearch = false;
}
}
}

View File

@ -307,7 +307,11 @@ namespace osu.Game.Screens.Select
protected virtual IEnumerable<(FooterButton, OverlayContainer)> CreateFooterButtons() => new (FooterButton, OverlayContainer)[]
{
(new FooterButtonMods { Current = Mods }, ModSelect),
(new FooterButtonRandom { Action = triggerRandom }, null),
(new FooterButtonRandom
{
NextRandom = () => Carousel.SelectNextRandom(),
PreviousRandom = Carousel.SelectPreviousRandom
}, null),
(new FooterButtonOptions(), BeatmapOptions)
};
@ -522,14 +526,6 @@ namespace osu.Game.Screens.Select
}
}
private void triggerRandom()
{
if (GetContainingInputManager().CurrentState.Keyboard.ShiftPressed)
Carousel.SelectPreviousRandom();
else
Carousel.SelectNextRandom();
}
public override void OnEntering(IScreen last)
{
base.OnEntering(last);