1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-14 08:52:55 +08:00

Merge branch 'master' into multiple-keys-one-binding

This commit is contained in:
Dean Herbert 2023-10-13 15:07:12 +09:00 committed by GitHub
commit 37411f923e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 209 additions and 103 deletions

View File

@ -12,12 +12,6 @@ namespace osu.Game.Rulesets.Mania.Judgements
{
switch (result)
{
case HitResult.LargeTickHit:
return DEFAULT_MAX_HEALTH_INCREASE * 0.1;
case HitResult.LargeTickMiss:
return -DEFAULT_MAX_HEALTH_INCREASE * 0.1;
case HitResult.Meh:
return -DEFAULT_MAX_HEALTH_INCREASE * 0.5;

View File

@ -385,22 +385,9 @@ namespace osu.Game.Rulesets.Mania
HitResult.Good,
HitResult.Ok,
HitResult.Meh,
HitResult.LargeTickHit,
};
}
public override LocalisableString GetDisplayNameForHitResult(HitResult result)
{
switch (result)
{
case HitResult.LargeTickHit:
return "hold tick";
}
return base.GetDisplayNameForHitResult(result);
}
public override StatisticItem[] CreateStatisticsForScore(ScoreInfo score, IBeatmap playableBeatmap) => new[]
{
new StatisticItem("Performance Breakdown", () => new PerformanceBreakdownChart(score, playableBeatmap)

View File

@ -11,8 +11,8 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Testing;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mania;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Judgements;
using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Play.HUD.JudgementCounter;
@ -57,7 +57,7 @@ namespace osu.Game.Tests.Visual.Gameplay
};
});
protected override Ruleset CreateRuleset() => new ManiaRuleset();
protected override Ruleset CreateRuleset() => new OsuRuleset();
private void applyOneJudgement(HitResult result)
{

View File

@ -2,16 +2,19 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Testing;
using osu.Framework.Utils;
using osu.Game.Overlays;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Catch;
using osu.Game.Rulesets.Mania;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Taiko;
using osu.Game.Rulesets.UI;
@ -34,6 +37,49 @@ namespace osu.Game.Tests.Visual.UserInterface
[Test]
public void TestMania() => createSwitchTestFor(new ManiaRuleset());
[Test]
public void TestShowRateAdjusts()
{
AddStep("create mod icons", () =>
{
Child = new FillFlowContainer
{
RelativeSizeAxes = Axes.Both,
Direction = FillDirection.Full,
ChildrenEnumerable = Ruleset.Value.CreateInstance().CreateAllMods()
.OfType<ModRateAdjust>()
.SelectMany(m =>
{
List<TestModSwitchTiny> icons = new List<TestModSwitchTiny> { new TestModSwitchTiny(m) };
for (double i = m.SpeedChange.MinValue; i < m.SpeedChange.MaxValue; i += m.SpeedChange.Precision * 10)
{
m = (ModRateAdjust)m.DeepClone();
m.SpeedChange.Value = i;
icons.Add(new TestModSwitchTiny(m, true));
}
return icons;
}),
};
});
AddStep("adjust rates", () =>
{
foreach (var icon in this.ChildrenOfType<TestModSwitchTiny>())
{
if (icon.Mod is ModRateAdjust rateAdjust)
{
rateAdjust.SpeedChange.Value = RNG.NextDouble() > 0.9
? rateAdjust.SpeedChange.Default
: RNG.NextDouble(rateAdjust.SpeedChange.MinValue, rateAdjust.SpeedChange.MaxValue);
}
}
});
AddToggleStep("toggle active", active => this.ChildrenOfType<TestModSwitchTiny>().ForEach(s => s.Active.Value = active));
}
private void createSwitchTestFor(Ruleset ruleset)
{
AddStep("no colour scheme", () => Child = createContent(ruleset, null));
@ -43,7 +89,7 @@ namespace osu.Game.Tests.Visual.UserInterface
AddStep($"{scheme} colour scheme", () => Child = createContent(ruleset, scheme));
}
AddToggleStep("toggle active", active => this.ChildrenOfType<ModSwitchTiny>().ForEach(s => s.Active.Value = active));
AddToggleStep("toggle active", active => this.ChildrenOfType<TestModSwitchTiny>().ForEach(s => s.Active.Value = active));
}
private static Drawable createContent(Ruleset ruleset, OverlayColourScheme? colourScheme)
@ -62,7 +108,7 @@ namespace osu.Game.Tests.Visual.UserInterface
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Full,
Spacing = new Vector2(5),
ChildrenEnumerable = group.Select(mod => new ModSwitchTiny(mod))
ChildrenEnumerable = group.Select(mod => new TestModSwitchTiny(mod))
})
};
@ -81,5 +127,15 @@ namespace osu.Game.Tests.Visual.UserInterface
return switchFlow;
}
private partial class TestModSwitchTiny : ModSwitchTiny
{
public new IMod Mod => base.Mod;
public TestModSwitchTiny(IMod mod, bool showExtendedInformation = false)
: base(mod, showExtendedInformation)
{
}
}
}
}

View File

@ -14,6 +14,8 @@ namespace osu.Game.Input.Bindings
{
public partial class GlobalActionContainer : DatabasedKeyBindingContainer<GlobalAction>, IHandleGlobalKeyboardInput, IKeyBindingHandler<GlobalAction>
{
protected override bool Prioritised => true;
private readonly IKeyBindingHandler<GlobalAction>? handler;
public GlobalActionContainer(OsuGameBase? game)
@ -23,22 +25,62 @@ namespace osu.Game.Input.Bindings
handler = h;
}
protected override bool Prioritised => true;
// IMPORTANT: Take care when changing order of the items in the enumerable.
// It is used to decide the order of precedence, with the earlier items having higher precedence.
public override IEnumerable<IKeyBinding> DefaultKeyBindings => GlobalKeyBindings
.Concat(EditorKeyBindings)
.Concat(InGameKeyBindings)
.Concat(ReplayKeyBindings)
.Concat(SongSelectKeyBindings)
.Concat(AudioControlKeyBindings)
/// <summary>
/// All default key bindings across all categories, ordered with highest priority first.
/// </summary>
/// <remarks>
/// IMPORTANT: Take care when changing order of the items in the enumerable.
/// It is used to decide the order of precedence, with the earlier items having higher precedence.
/// </remarks>
public override IEnumerable<IKeyBinding> DefaultKeyBindings => globalKeyBindings
.Concat(editorKeyBindings)
.Concat(inGameKeyBindings)
.Concat(replayKeyBindings)
.Concat(songSelectKeyBindings)
.Concat(audioControlKeyBindings)
// Overlay bindings may conflict with more local cases like the editor so they are checked last.
// It has generally been agreed on that local screens like the editor should have priority,
// based on such usages potentially requiring a lot more key bindings that may be "shared" with global ones.
.Concat(OverlayKeyBindings);
.Concat(overlayKeyBindings);
public static IEnumerable<KeyBinding> GlobalKeyBindings => new[]
public static IEnumerable<KeyBinding> GetDefaultBindingsFor(GlobalActionCategory category)
{
switch (category)
{
case GlobalActionCategory.General:
return globalKeyBindings;
case GlobalActionCategory.Editor:
return editorKeyBindings;
case GlobalActionCategory.InGame:
return inGameKeyBindings;
case GlobalActionCategory.Replay:
return replayKeyBindings;
case GlobalActionCategory.SongSelect:
return songSelectKeyBindings;
case GlobalActionCategory.AudioControl:
return audioControlKeyBindings;
case GlobalActionCategory.Overlays:
return overlayKeyBindings;
default:
throw new ArgumentOutOfRangeException(nameof(category), category, $"Unexpected {nameof(GlobalActionCategory)}");
}
}
public static IEnumerable<GlobalAction> GetGlobalActionsFor(GlobalActionCategory category)
=> GetDefaultBindingsFor(category).Select(binding => binding.Action).Cast<GlobalAction>().Distinct();
public bool OnPressed(KeyBindingPressEvent<GlobalAction> e) => handler?.OnPressed(e) == true;
public void OnReleased(KeyBindingReleaseEvent<GlobalAction> e) => handler?.OnReleased(e);
private static IEnumerable<KeyBinding> globalKeyBindings => new[]
{
new KeyBinding(InputKey.Up, GlobalAction.SelectPrevious),
new KeyBinding(InputKey.Down, GlobalAction.SelectNext),
@ -68,7 +110,7 @@ namespace osu.Game.Input.Bindings
new KeyBinding(InputKey.F12, GlobalAction.TakeScreenshot),
};
public static IEnumerable<KeyBinding> OverlayKeyBindings => new[]
private static IEnumerable<KeyBinding> overlayKeyBindings => new[]
{
new KeyBinding(InputKey.F8, GlobalAction.ToggleChat),
new KeyBinding(InputKey.F6, GlobalAction.ToggleNowPlaying),
@ -78,7 +120,7 @@ namespace osu.Game.Input.Bindings
new KeyBinding(new[] { InputKey.Control, InputKey.N }, GlobalAction.ToggleNotifications),
};
public static IEnumerable<KeyBinding> EditorKeyBindings => new[]
private static IEnumerable<KeyBinding> editorKeyBindings => new[]
{
new KeyBinding(new[] { InputKey.F1 }, GlobalAction.EditorComposeMode),
new KeyBinding(new[] { InputKey.F2 }, GlobalAction.EditorDesignMode),
@ -102,7 +144,7 @@ namespace osu.Game.Input.Bindings
new KeyBinding(new[] { InputKey.Control, InputKey.R }, GlobalAction.EditorToggleRotateControl),
};
public static IEnumerable<KeyBinding> InGameKeyBindings => new[]
private static IEnumerable<KeyBinding> inGameKeyBindings => new[]
{
new KeyBinding(InputKey.Space, GlobalAction.SkipCutscene),
new KeyBinding(InputKey.ExtraMouseButton2, GlobalAction.SkipCutscene),
@ -119,7 +161,7 @@ namespace osu.Game.Input.Bindings
new KeyBinding(InputKey.F2, GlobalAction.ExportReplay),
};
public static IEnumerable<KeyBinding> ReplayKeyBindings => new[]
private static IEnumerable<KeyBinding> replayKeyBindings => new[]
{
new KeyBinding(InputKey.Space, GlobalAction.TogglePauseReplay),
new KeyBinding(InputKey.MouseMiddle, GlobalAction.TogglePauseReplay),
@ -128,7 +170,7 @@ namespace osu.Game.Input.Bindings
new KeyBinding(new[] { InputKey.Control, InputKey.H }, GlobalAction.ToggleReplaySettings),
};
public static IEnumerable<KeyBinding> SongSelectKeyBindings => new[]
private static IEnumerable<KeyBinding> songSelectKeyBindings => new[]
{
new KeyBinding(InputKey.F1, GlobalAction.ToggleModSelection),
new KeyBinding(InputKey.F2, GlobalAction.SelectNextRandom),
@ -137,7 +179,7 @@ namespace osu.Game.Input.Bindings
new KeyBinding(InputKey.BackSpace, GlobalAction.DeselectAllMods),
};
public static IEnumerable<KeyBinding> AudioControlKeyBindings => new[]
private static IEnumerable<KeyBinding> audioControlKeyBindings => new[]
{
new KeyBinding(new[] { InputKey.Alt, InputKey.Up }, GlobalAction.IncreaseVolume),
new KeyBinding(new[] { InputKey.Alt, InputKey.Down }, GlobalAction.DecreaseVolume),
@ -154,43 +196,6 @@ namespace osu.Game.Input.Bindings
new KeyBinding(InputKey.PlayPause, GlobalAction.MusicPlay),
new KeyBinding(InputKey.F3, GlobalAction.MusicPlay)
};
public static IEnumerable<KeyBinding> GetDefaultBindingsFor(GlobalActionCategory category)
{
switch (category)
{
case GlobalActionCategory.General:
return GlobalKeyBindings;
case GlobalActionCategory.Editor:
return EditorKeyBindings;
case GlobalActionCategory.InGame:
return InGameKeyBindings;
case GlobalActionCategory.Replay:
return ReplayKeyBindings;
case GlobalActionCategory.SongSelect:
return SongSelectKeyBindings;
case GlobalActionCategory.AudioControl:
return AudioControlKeyBindings;
case GlobalActionCategory.Overlays:
return OverlayKeyBindings;
default:
throw new ArgumentOutOfRangeException(nameof(category), category, $"Unexpected {nameof(GlobalActionCategory)}");
}
}
public static IEnumerable<GlobalAction> GetGlobalActionsFor(GlobalActionCategory category)
=> GetDefaultBindingsFor(category).Select(binding => binding.Action).Cast<GlobalAction>().Distinct();
public bool OnPressed(KeyBindingPressEvent<GlobalAction> e) => handler?.OnPressed(e) == true;
public void OnReleased(KeyBindingReleaseEvent<GlobalAction> e) => handler?.OnReleased(e);
}
public enum GlobalAction

View File

@ -3,15 +3,16 @@
using osu.Framework.Allocation;
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.Utils;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Overlays;
using osu.Game.Rulesets.Mods;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Rulesets.UI
@ -21,8 +22,10 @@ namespace osu.Game.Rulesets.UI
public BindableBool Active { get; } = new BindableBool();
public const float DEFAULT_HEIGHT = 30;
private const float width = 73;
private readonly IMod mod;
protected readonly IMod Mod;
private readonly bool showExtendedInformation;
private readonly Box background;
private readonly OsuSpriteText acronymText;
@ -33,33 +36,69 @@ namespace osu.Game.Rulesets.UI
private Color4 activeBackgroundColour;
private Color4 inactiveBackgroundColour;
public ModSwitchTiny(IMod mod)
{
this.mod = mod;
Size = new Vector2(73, DEFAULT_HEIGHT);
private readonly CircularContainer extendedContent;
private readonly Box extendedBackground;
private readonly OsuSpriteText extendedText;
private ModSettingChangeTracker? modSettingsChangeTracker;
InternalChild = new CircularContainer
public ModSwitchTiny(IMod mod, bool showExtendedInformation = false)
{
Mod = mod;
this.showExtendedInformation = showExtendedInformation;
AutoSizeAxes = Axes.X;
Height = DEFAULT_HEIGHT;
InternalChildren = new Drawable[]
{
RelativeSizeAxes = Axes.Both,
Masking = true,
Children = new Drawable[]
extendedContent = new CircularContainer
{
background = new Box
Name = "extended content",
Width = 100 + DEFAULT_HEIGHT / 2,
RelativeSizeAxes = Axes.Y,
Masking = true,
X = width,
Margin = new MarginPadding { Left = -DEFAULT_HEIGHT },
Children = new Drawable[]
{
RelativeSizeAxes = Axes.Both
},
acronymText = new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Shadow = false,
Font = OsuFont.Numeric.With(size: 24, weight: FontWeight.Black),
Text = mod.Acronym,
Margin = new MarginPadding
extendedBackground = new Box
{
Top = 4
}
RelativeSizeAxes = Axes.Both,
},
extendedText = new OsuSpriteText
{
Margin = new MarginPadding { Left = 3 * DEFAULT_HEIGHT / 4 },
Font = OsuFont.Default.With(size: 30f, weight: FontWeight.Bold),
UseFullGlyphHeight = false,
Text = mod.ExtendedIconInformation,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
},
}
},
new CircularContainer
{
Width = width,
RelativeSizeAxes = Axes.Y,
Masking = true,
Children = new Drawable[]
{
background = new Box
{
RelativeSizeAxes = Axes.Both
},
acronymText = new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Shadow = false,
Font = OsuFont.Numeric.With(size: 24, weight: FontWeight.Black),
Text = mod.Acronym,
Margin = new MarginPadding
{
Top = 4
}
},
},
}
};
}
@ -68,7 +107,7 @@ namespace osu.Game.Rulesets.UI
private void load(OsuColour colours, OverlayColourProvider? colourProvider)
{
inactiveBackgroundColour = colourProvider?.Background5 ?? colours.Gray3;
activeBackgroundColour = colours.ForModType(mod.Type);
activeBackgroundColour = colours.ForModType(Mod.Type);
inactiveForegroundColour = colourProvider?.Background2 ?? colours.Gray5;
activeForegroundColour = Interpolation.ValueAt<Colour4>(0.1f, Colour4.Black, activeForegroundColour, 0, 1);
@ -80,12 +119,37 @@ namespace osu.Game.Rulesets.UI
Active.BindValueChanged(_ => updateState(), true);
FinishTransforms(true);
if (Mod is Mod actualMod)
{
modSettingsChangeTracker = new ModSettingChangeTracker(new[] { actualMod });
modSettingsChangeTracker.SettingChanged = _ => updateExtendedInformation();
}
updateExtendedInformation();
}
private void updateExtendedInformation()
{
bool showExtended = showExtendedInformation && !string.IsNullOrEmpty(Mod.ExtendedIconInformation);
extendedContent.Alpha = showExtended ? 1 : 0;
extendedText.Text = Mod.ExtendedIconInformation;
}
private void updateState()
{
acronymText.FadeColour(Active.Value ? activeForegroundColour : inactiveForegroundColour, 200, Easing.OutQuint);
background.FadeColour(Active.Value ? activeBackgroundColour : inactiveBackgroundColour, 200, Easing.OutQuint);
extendedText.Colour = Active.Value ? activeBackgroundColour.Lighten(0.2f) : inactiveBackgroundColour;
extendedBackground.Colour = Active.Value ? activeBackgroundColour.Darken(2.4f) : inactiveBackgroundColour.Darken(2.8f);
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
modSettingsChangeTracker?.Dispose();
}
}
}

View File

@ -346,7 +346,7 @@ namespace osu.Game.Scoring
case HitResult.LargeBonus:
case HitResult.SmallBonus:
if (MaximumStatistics.TryGetValue(r.result, out int count) && count > 0)
yield return new HitResultDisplayStatistic(r.result, value, null, r.displayName);
yield return new HitResultDisplayStatistic(r.result, value, count, r.displayName);
break;