1
0
mirror of https://github.com/ppy/osu.git synced 2025-02-13 11:12:54 +08:00

Merge pull request #14533 from frenzibyte/move-incompatibility-icon

Move mod incompatibility logic to "local player" mod select overlays
This commit is contained in:
Dean Herbert 2021-09-01 18:12:27 +09:00 committed by GitHub
commit ef64c05af8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 162 additions and 96 deletions

View File

@ -529,7 +529,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("invoke on back button", () => multiplayerScreen.OnBackButton());
AddAssert("mod overlay is hidden", () => this.ChildrenOfType<LocalPlayerModSelectOverlay>().Single().State.Value == Visibility.Hidden);
AddAssert("mod overlay is hidden", () => this.ChildrenOfType<UserModSelectOverlay>().Single().State.Value == Visibility.Hidden);
AddAssert("dialog overlay is hidden", () => DialogOverlay.State.Value == Visibility.Hidden);

View File

@ -422,7 +422,7 @@ namespace osu.Game.Tests.Visual.UserInterface
};
}
private class TestModSelectOverlay : LocalPlayerModSelectOverlay
private class TestModSelectOverlay : UserModSelectOverlay
{
public new Bindable<IReadOnlyList<Mod>> SelectedMods => base.SelectedMods;

View File

@ -151,7 +151,7 @@ namespace osu.Game.Tests.Visual.UserInterface
AddUntilStep("wait for ready", () => modSelect.State.Value == Visibility.Visible && modSelect.ButtonsLoaded);
}
private class TestModSelectOverlay : LocalPlayerModSelectOverlay
private class TestModSelectOverlay : UserModSelectOverlay
{
public new VisibilityContainer ModSettingsContainer => base.ModSettingsContainer;
public new TriangleButton CustomiseButton => base.CustomiseButton;

View File

@ -0,0 +1,117 @@
// 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.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Screens.Play.HUD;
using osu.Game.Utils;
using osuTK;
namespace osu.Game.Overlays.Mods
{
public class IncompatibilityDisplayingModButton : ModButton
{
private readonly CompositeDrawable incompatibleIcon;
[Resolved]
private Bindable<IReadOnlyList<Mod>> selectedMods { get; set; }
public IncompatibilityDisplayingModButton(Mod mod)
: base(mod)
{
ButtonContent.Add(incompatibleIcon = new IncompatibleIcon
{
Anchor = Anchor.BottomRight,
Origin = Anchor.Centre,
Position = new Vector2(-13),
});
}
protected override void LoadComplete()
{
base.LoadComplete();
selectedMods.BindValueChanged(_ => Scheduler.AddOnce(updateCompatibility), true);
}
protected override void DisplayMod(Mod mod)
{
base.DisplayMod(mod);
Scheduler.AddOnce(updateCompatibility);
}
private void updateCompatibility()
{
var m = SelectedMod ?? Mods.First();
bool isIncompatible = false;
if (selectedMods.Value.Count > 0 && !selectedMods.Value.Contains(m))
isIncompatible = !ModUtils.CheckCompatibleSet(selectedMods.Value.Append(m));
if (isIncompatible)
incompatibleIcon.Show();
else
incompatibleIcon.Hide();
}
public override ITooltip<Mod> GetCustomTooltip() => new IncompatibilityDisplayingTooltip();
private class IncompatibilityDisplayingTooltip : ModButtonTooltip
{
private readonly OsuSpriteText incompatibleText;
private readonly Bindable<IReadOnlyList<Mod>> incompatibleMods = new Bindable<IReadOnlyList<Mod>>();
[Resolved]
private Bindable<RulesetInfo> ruleset { get; set; }
public IncompatibilityDisplayingTooltip()
{
AddRange(new Drawable[]
{
incompatibleText = new OsuSpriteText
{
Margin = new MarginPadding { Top = 5 },
Font = OsuFont.GetFont(weight: FontWeight.Regular),
Text = "Incompatible with:"
},
new ModDisplay
{
Current = incompatibleMods,
ExpansionMode = ExpansionMode.AlwaysExpanded,
Scale = new Vector2(0.7f)
}
});
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
incompatibleText.Colour = colours.BlueLight;
}
protected override void UpdateDisplay(Mod mod)
{
base.UpdateDisplay(mod);
var incompatibleTypes = mod.IncompatibleMods;
var allMods = ruleset.Value.CreateInstance().GetAllMods();
incompatibleMods.Value = allMods.Where(m => m.GetType() != mod.GetType() && incompatibleTypes.Any(t => t.IsInstanceOfType(m))).ToList();
incompatibleText.Text = incompatibleMods.Value.Any() ? "Incompatible with:" : "Compatible with all mods";
}
}
}
}

View File

@ -11,29 +11,24 @@ using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI;
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Input.Events;
using osu.Framework.Localisation;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
using osu.Game.Utils;
namespace osu.Game.Overlays.Mods
{
/// <summary>
/// Represents a clickable button which can cycle through one of more mods.
/// </summary>
public class ModButton : ModButtonEmpty, IHasCustomTooltip
public class ModButton : ModButtonEmpty, IHasCustomTooltip<Mod>
{
private ModIcon foregroundIcon;
private ModIcon backgroundIcon;
private readonly SpriteText text;
private readonly Container<ModIcon> iconsContainer;
private readonly CompositeDrawable incompatibleIcon;
/// <summary>
/// Fired when the selection changes.
@ -48,9 +43,6 @@ namespace osu.Game.Overlays.Mods
// A selected index of -1 means not selected.
private int selectedIndex = -1;
[Resolved]
private Bindable<IReadOnlyList<Mod>> selectedMods { get; set; }
/// <summary>
/// Change the selected mod index of this button.
/// </summary>
@ -109,7 +101,7 @@ namespace osu.Game.Overlays.Mods
.RotateTo(rotate_angle * direction)
.RotateTo(0f, mod_switch_duration, mod_switch_easing);
Schedule(() => displayMod(newSelection));
Schedule(() => DisplayMod(newSelection));
}
}
@ -138,7 +130,8 @@ namespace osu.Game.Overlays.Mods
}
private Mod mod;
private readonly Container scaleContainer;
protected readonly Container ButtonContent;
public Mod Mod
{
@ -162,7 +155,7 @@ namespace osu.Game.Overlays.Mods
if (Mods.Length > 0)
{
displayMod(Mods[0]);
DisplayMod(Mods[0]);
}
}
}
@ -173,13 +166,13 @@ namespace osu.Game.Overlays.Mods
protected override bool OnMouseDown(MouseDownEvent e)
{
scaleContainer.ScaleTo(0.9f, 800, Easing.Out);
ButtonContent.ScaleTo(0.9f, 800, Easing.Out);
return base.OnMouseDown(e);
}
protected override void OnMouseUp(MouseUpEvent e)
{
scaleContainer.ScaleTo(1, 500, Easing.OutElastic);
ButtonContent.ScaleTo(1, 500, Easing.OutElastic);
// only trigger the event if we are inside the area of the button
if (Contains(e.ScreenSpaceMousePosition))
@ -238,30 +231,13 @@ namespace osu.Game.Overlays.Mods
public void Deselect() => changeSelectedIndex(-1);
private void displayMod(Mod mod)
protected virtual void DisplayMod(Mod mod)
{
if (backgroundIcon != null)
backgroundIcon.Mod = foregroundIcon.Mod;
foregroundIcon.Mod = mod;
text.Text = mod.Name;
Colour = mod.HasImplementation ? Color4.White : Color4.Gray;
Scheduler.AddOnce(updateCompatibility);
}
private void updateCompatibility()
{
var m = SelectedMod ?? Mods.First();
bool isIncompatible = false;
if (selectedMods.Value.Count > 0 && !selectedMods.Value.Contains(m))
isIncompatible = !ModUtils.CheckCompatibleSet(selectedMods.Value.Append(m));
if (isIncompatible)
incompatibleIcon.Show();
else
incompatibleIcon.Hide();
}
private void createIcons()
@ -307,7 +283,7 @@ namespace osu.Game.Overlays.Mods
Anchor = Anchor.TopCentre,
Children = new Drawable[]
{
scaleContainer = new Container
ButtonContent = new Container
{
Children = new Drawable[]
{
@ -317,12 +293,6 @@ namespace osu.Game.Overlays.Mods
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
},
incompatibleIcon = new IncompatibleIcon
{
Origin = Anchor.Centre,
Anchor = Anchor.BottomRight,
Position = new Vector2(-13),
}
},
RelativeSizeAxes = Axes.Both,
Origin = Anchor.Centre,
@ -342,15 +312,8 @@ namespace osu.Game.Overlays.Mods
Mod = mod;
}
protected override void LoadComplete()
{
base.LoadComplete();
public virtual ITooltip<Mod> GetCustomTooltip() => new ModButtonTooltip();
selectedMods.BindValueChanged(_ => Scheduler.AddOnce(updateCompatibility), true);
}
public ITooltip GetCustomTooltip() => new ModButtonTooltip();
public object TooltipContent => SelectedMod ?? Mods.FirstOrDefault();
public Mod TooltipContent => SelectedMod ?? Mods.FirstOrDefault();
}
}

View File

@ -1,19 +1,14 @@
// 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.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Screens.Play.HUD;
using osuTK;
namespace osu.Game.Overlays.Mods
@ -22,12 +17,8 @@ namespace osu.Game.Overlays.Mods
{
private readonly OsuSpriteText descriptionText;
private readonly Box background;
private readonly OsuSpriteText incompatibleText;
private readonly Bindable<IReadOnlyList<Mod>> incompatibleMods = new Bindable<IReadOnlyList<Mod>>();
[Resolved]
private Bindable<RulesetInfo> ruleset { get; set; }
protected override Container<Drawable> Content { get; }
public ModButtonTooltip()
{
@ -35,13 +26,13 @@ namespace osu.Game.Overlays.Mods
Masking = true;
CornerRadius = 5;
Children = new Drawable[]
InternalChildren = new Drawable[]
{
background = new Box
{
RelativeSizeAxes = Axes.Both
},
new FillFlowContainer
Content = new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Vertical,
@ -51,19 +42,7 @@ namespace osu.Game.Overlays.Mods
descriptionText = new OsuSpriteText
{
Font = OsuFont.GetFont(weight: FontWeight.Regular),
Margin = new MarginPadding { Bottom = 5 }
},
incompatibleText = new OsuSpriteText
{
Font = OsuFont.GetFont(weight: FontWeight.Regular),
Text = "Incompatible with:"
},
new ModDisplay
{
Current = incompatibleMods,
ExpansionMode = ExpansionMode.AlwaysExpanded,
Scale = new Vector2(0.7f)
}
}
},
};
@ -74,7 +53,6 @@ namespace osu.Game.Overlays.Mods
{
background.Colour = colours.Gray3;
descriptionText.Colour = colours.BlueLighter;
incompatibleText.Colour = colours.BlueLight;
}
protected override void PopIn() => this.FadeIn(200, Easing.OutQuint);
@ -84,19 +62,17 @@ namespace osu.Game.Overlays.Mods
public void SetContent(Mod mod)
{
if (mod.Equals(lastMod)) return;
if (mod.Equals(lastMod))
return;
lastMod = mod;
UpdateDisplay(mod);
}
protected virtual void UpdateDisplay(Mod mod)
{
descriptionText.Text = mod.Description;
var incompatibleTypes = mod.IncompatibleMods;
var allMods = ruleset.Value.CreateInstance().GetAllMods();
incompatibleMods.Value = allMods.Where(m => m.GetType() != mod.GetType() && incompatibleTypes.Any(t => t.IsInstanceOfType(m))).ToList();
incompatibleText.Text = !incompatibleMods.Value.Any() ? "Compatible with all mods" : "Incompatible with:";
}
public void Move(Vector2 pos) => Position = pos;

View File

@ -51,14 +51,14 @@ namespace osu.Game.Overlays.Mods
if (m == null)
return new ModButtonEmpty();
return new ModButton(m)
return CreateModButton(m).With(b =>
{
SelectionChanged = mod =>
b.SelectionChanged = mod =>
{
ModButtonStateChanged(mod);
Action?.Invoke(mod);
},
};
};
});
}).ToArray();
modsLoadCts?.Cancel();
@ -247,6 +247,8 @@ namespace osu.Game.Overlays.Mods
Text = text
};
protected virtual ModButton CreateModButton(Mod mod) => new ModButton(mod);
/// <summary>
/// Play out all remaining animations immediately to leave mods in a good (final) state.
/// </summary>

View File

@ -5,7 +5,7 @@ using osu.Game.Rulesets.Mods;
namespace osu.Game.Overlays.Mods
{
public class LocalPlayerModSelectOverlay : ModSelectOverlay
public class UserModSelectOverlay : ModSelectOverlay
{
protected override void OnModSelected(Mod mod)
{
@ -14,5 +14,17 @@ namespace osu.Game.Overlays.Mods
foreach (var section in ModSectionsContainer.Children)
section.DeselectTypes(mod.IncompatibleMods, true, mod);
}
protected override ModSection CreateModSection(ModType type) => new UserModSection(type);
private class UserModSection : ModSection
{
public UserModSection(ModType type)
: base(type)
{
}
protected override ModButton CreateModButton(Mod mod) => new IncompatibilityDisplayingModButton(mod);
}
}
}

View File

@ -429,10 +429,6 @@ namespace osu.Game.Screens.OnlinePlay.Match
/// <param name="room">The room to change the settings of.</param>
protected abstract RoomSettingsOverlay CreateRoomSettingsOverlay(Room room);
private class UserModSelectOverlay : LocalPlayerModSelectOverlay
{
}
public class UserModSelectButton : PurpleTriangleButton
{
}

View File

@ -152,7 +152,7 @@ namespace osu.Game.Screens.OnlinePlay
return base.OnExiting(next);
}
protected override ModSelectOverlay CreateModSelectOverlay() => new LocalPlayerModSelectOverlay
protected override ModSelectOverlay CreateModSelectOverlay() => new UserModSelectOverlay
{
IsValidMod = IsValidMod
};

View File

@ -315,7 +315,7 @@ namespace osu.Game.Screens.Select
(new FooterButtonOptions(), BeatmapOptions)
};
protected virtual ModSelectOverlay CreateModSelectOverlay() => new LocalPlayerModSelectOverlay();
protected virtual ModSelectOverlay CreateModSelectOverlay() => new UserModSelectOverlay();
protected virtual void ApplyFilterToCarousel(FilterCriteria criteria)
{