1
0
mirror of https://github.com/ppy/osu.git synced 2025-02-05 20:42:55 +08:00

Merge branch 'master' into realm-key-binding-store

This commit is contained in:
Dean Herbert 2021-01-21 15:45:59 +09:00
commit 259f6504fb
18 changed files with 324 additions and 188 deletions

View File

@ -17,10 +17,12 @@ using osu.Framework.Utils;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Objects.Legacy; using osu.Game.Rulesets.Objects.Legacy;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using osuTK; using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
@ -129,6 +131,31 @@ namespace osu.Game.Tests.Visual.Gameplay
AddUntilStep("no DHOs shown", () => !this.ChildrenOfType<DrawableTestHitObject>().Any()); AddUntilStep("no DHOs shown", () => !this.ChildrenOfType<DrawableTestHitObject>().Any());
} }
[Test]
public void TestApplyHitResultOnKilled()
{
ManualClock clock = null;
bool anyJudged = false;
void onNewResult(JudgementResult _) => anyJudged = true;
var beatmap = new Beatmap();
beatmap.HitObjects.Add(new TestKilledHitObject { Duration = 20 });
createTest(beatmap, 10, () => new FramedClock(clock = new ManualClock()));
AddStep("subscribe to new result", () =>
{
anyJudged = false;
drawableRuleset.NewResult += onNewResult;
});
AddStep("skip past object", () => clock.CurrentTime = beatmap.HitObjects[0].GetEndTime() + 1000);
AddAssert("object judged", () => anyJudged);
AddStep("clean up", () => drawableRuleset.NewResult -= onNewResult);
}
private void createTest(IBeatmap beatmap, int poolSize, Func<IFrameBasedClock> createClock = null) => AddStep("create test", () => private void createTest(IBeatmap beatmap, int poolSize, Func<IFrameBasedClock> createClock = null) => AddStep("create test", () =>
{ {
var ruleset = new TestPoolingRuleset(); var ruleset = new TestPoolingRuleset();
@ -192,6 +219,7 @@ namespace osu.Game.Tests.Visual.Gameplay
private void load() private void load()
{ {
RegisterPool<TestHitObject, DrawableTestHitObject>(poolSize); RegisterPool<TestHitObject, DrawableTestHitObject>(poolSize);
RegisterPool<TestKilledHitObject, DrawableTestKilledHitObject>(poolSize);
} }
protected override HitObjectLifetimeEntry CreateLifetimeEntry(HitObject hitObject) => new TestHitObjectLifetimeEntry(hitObject); protected override HitObjectLifetimeEntry CreateLifetimeEntry(HitObject hitObject) => new TestHitObjectLifetimeEntry(hitObject);
@ -220,19 +248,30 @@ namespace osu.Game.Tests.Visual.Gameplay
protected override IEnumerable<TestHitObject> ConvertHitObject(HitObject original, IBeatmap beatmap, CancellationToken cancellationToken) protected override IEnumerable<TestHitObject> ConvertHitObject(HitObject original, IBeatmap beatmap, CancellationToken cancellationToken)
{ {
switch (original)
{
case TestKilledHitObject h:
yield return h;
break;
default:
yield return new TestHitObject yield return new TestHitObject
{ {
StartTime = original.StartTime, StartTime = original.StartTime,
Duration = 250 Duration = 250
}; };
break;
}
} }
} }
#endregion #endregion
#region HitObject #region HitObjects
private class TestHitObject : ConvertHitObject private class TestHitObject : ConvertHitObject, IHasDuration
{ {
public double EndTime => StartTime + Duration; public double EndTime => StartTime + Duration;
@ -287,6 +326,30 @@ namespace osu.Game.Tests.Visual.Gameplay
} }
} }
private class TestKilledHitObject : TestHitObject
{
}
private class DrawableTestKilledHitObject : DrawableHitObject<TestKilledHitObject>
{
public DrawableTestKilledHitObject()
: base(null)
{
}
protected override void UpdateHitStateTransforms(ArmedState state)
{
base.UpdateHitStateTransforms(state);
Expire();
}
public override void OnKilled()
{
base.OnKilled();
ApplyResult(r => r.Type = r.Judgement.MinResult);
}
}
#endregion #endregion
} }
} }

View File

@ -231,8 +231,8 @@ namespace osu.Game.Tests.Visual.Online
}); });
}); });
AddAssert("shown beatmaps of current ruleset", () => overlay.Header.Picker.Difficulties.All(b => b.Beatmap.Ruleset.Equals(overlay.Header.RulesetSelector.Current.Value))); AddAssert("shown beatmaps of current ruleset", () => overlay.Header.HeaderContent.Picker.Difficulties.All(b => b.Beatmap.Ruleset.Equals(overlay.Header.RulesetSelector.Current.Value)));
AddAssert("left-most beatmap selected", () => overlay.Header.Picker.Difficulties.First().State == BeatmapPicker.DifficultySelectorState.Selected); AddAssert("left-most beatmap selected", () => overlay.Header.HeaderContent.Picker.Difficulties.First().State == BeatmapPicker.DifficultySelectorState.Selected);
} }
[Test] [Test]
@ -310,12 +310,12 @@ namespace osu.Game.Tests.Visual.Online
private void downloadAssert(bool shown) private void downloadAssert(bool shown)
{ {
AddAssert($"is download button {(shown ? "shown" : "hidden")}", () => overlay.Header.DownloadButtonsVisible == shown); AddAssert($"is download button {(shown ? "shown" : "hidden")}", () => overlay.Header.HeaderContent.DownloadButtonsVisible == shown);
} }
private class TestBeatmapSetOverlay : BeatmapSetOverlay private class TestBeatmapSetOverlay : BeatmapSetOverlay
{ {
public new Header Header => base.Header; public new BeatmapSetHeader Header => base.Header;
} }
} }
} }

View File

@ -11,12 +11,10 @@ using osu.Framework.Platform;
using osu.Framework.Screens; using osu.Framework.Screens;
using osu.Framework.Testing; using osu.Framework.Testing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.Rooms; using osu.Game.Online.Rooms;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu;
using osu.Game.Screens.OnlinePlay; using osu.Game.Screens.OnlinePlay;
using osu.Game.Screens.OnlinePlay.Match.Components;
using osu.Game.Screens.OnlinePlay.Playlists; using osu.Game.Screens.OnlinePlay.Playlists;
using osu.Game.Tests.Beatmaps; using osu.Game.Tests.Beatmaps;
using osu.Game.Users; using osu.Game.Users;
@ -85,8 +83,7 @@ namespace osu.Game.Tests.Visual.Playlists
AddStep("move mouse to create button", () => AddStep("move mouse to create button", () =>
{ {
var footer = match.ChildrenOfType<Footer>().Single(); InputManager.MoveMouseTo(this.ChildrenOfType<PlaylistsMatchSettingsOverlay.CreateRoomButton>().Single());
InputManager.MoveMouseTo(footer.ChildrenOfType<OsuButton>().Single());
}); });
AddStep("click", () => InputManager.Click(MouseButton.Left)); AddStep("click", () => InputManager.Click(MouseButton.Left));

View File

@ -368,6 +368,7 @@ namespace osu.Game
if (!SelectedMods.Disabled) if (!SelectedMods.Disabled)
SelectedMods.Value = Array.Empty<Mod>(); SelectedMods.Value = Array.Empty<Mod>();
AvailableMods.Value = dict; AvailableMods.Value = dict;
} }

View File

@ -1,25 +1,55 @@
// 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 osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Effects;
using osu.Game.Beatmaps;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Overlays.BeatmapSet namespace osu.Game.Overlays.BeatmapSet
{ {
public class BeatmapSetHeader : OverlayHeader public class BeatmapSetHeader : OverlayHeader
{ {
public readonly Bindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>(); public readonly Bindable<BeatmapSetInfo> BeatmapSet = new Bindable<BeatmapSetInfo>();
public BeatmapSetHeaderContent HeaderContent { get; private set; }
[Cached]
public BeatmapRulesetSelector RulesetSelector { get; private set; } public BeatmapRulesetSelector RulesetSelector { get; private set; }
protected override OverlayTitle CreateTitle() => new BeatmapHeaderTitle(); [Cached(typeof(IBindable<RulesetInfo>))]
private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>();
public BeatmapSetHeader()
{
Masking = true;
EdgeEffect = new EdgeEffectParameters
{
Colour = Color4.Black.Opacity(0.25f),
Type = EdgeEffectType.Shadow,
Radius = 3,
Offset = new Vector2(0f, 1f),
};
}
protected override Drawable CreateContent() => HeaderContent = new BeatmapSetHeaderContent
{
BeatmapSet = { BindTarget = BeatmapSet }
};
protected override Drawable CreateTitleContent() => RulesetSelector = new BeatmapRulesetSelector protected override Drawable CreateTitleContent() => RulesetSelector = new BeatmapRulesetSelector
{ {
Current = Ruleset Current = ruleset
}; };
protected override OverlayTitle CreateTitle() => new BeatmapHeaderTitle();
private class BeatmapHeaderTitle : OverlayTitle private class BeatmapHeaderTitle : OverlayTitle
{ {
public BeatmapHeaderTitle() public BeatmapHeaderTitle()

View File

@ -3,12 +3,10 @@
using System.Linq; using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps.Drawables; using osu.Game.Beatmaps.Drawables;
using osu.Game.Graphics; using osu.Game.Graphics;
@ -18,18 +16,21 @@ using osu.Game.Online;
using osu.Game.Online.API; using osu.Game.Online.API;
using osu.Game.Overlays.BeatmapListing.Panels; using osu.Game.Overlays.BeatmapListing.Panels;
using osu.Game.Overlays.BeatmapSet.Buttons; using osu.Game.Overlays.BeatmapSet.Buttons;
using osu.Game.Rulesets;
using osuTK; using osuTK;
using osuTK.Graphics;
namespace osu.Game.Overlays.BeatmapSet namespace osu.Game.Overlays.BeatmapSet
{ {
public class Header : BeatmapDownloadTrackingComposite public class BeatmapSetHeaderContent : BeatmapDownloadTrackingComposite
{ {
private const float transition_duration = 200; private const float transition_duration = 200;
private const float buttons_height = 45; private const float buttons_height = 45;
private const float buttons_spacing = 5; private const float buttons_spacing = 5;
public bool DownloadButtonsVisible => downloadButtonsContainer.Any();
public readonly Details Details;
public readonly BeatmapPicker Picker;
private readonly UpdateableBeatmapSetCover cover; private readonly UpdateableBeatmapSetCover cover;
private readonly Box coverGradient; private readonly Box coverGradient;
private readonly OsuSpriteText title, artist; private readonly OsuSpriteText title, artist;
@ -38,52 +39,23 @@ namespace osu.Game.Overlays.BeatmapSet
private readonly FillFlowContainer downloadButtonsContainer; private readonly FillFlowContainer downloadButtonsContainer;
private readonly BeatmapAvailability beatmapAvailability; private readonly BeatmapAvailability beatmapAvailability;
private readonly BeatmapSetOnlineStatusPill onlineStatusPill; private readonly BeatmapSetOnlineStatusPill onlineStatusPill;
public Details Details; private readonly FavouriteButton favouriteButton;
private readonly FillFlowContainer fadeContent;
public bool DownloadButtonsVisible => downloadButtonsContainer.Any(); private readonly LoadingSpinner loading;
[Resolved] [Resolved]
private IAPIProvider api { get; set; } private IAPIProvider api { get; set; }
public BeatmapRulesetSelector RulesetSelector => beatmapSetHeader.RulesetSelector; [Resolved]
public readonly BeatmapPicker Picker; private BeatmapRulesetSelector rulesetSelector { get; set; }
private readonly FavouriteButton favouriteButton; public BeatmapSetHeaderContent()
private readonly FillFlowContainer fadeContent;
private readonly LoadingSpinner loading;
private readonly BeatmapSetHeader beatmapSetHeader;
[Cached(typeof(IBindable<RulesetInfo>))]
private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>();
public Header()
{ {
ExternalLinkButton externalLink; ExternalLinkButton externalLink;
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y; AutoSizeAxes = Axes.Y;
Masking = true; InternalChild = new Container
EdgeEffect = new EdgeEffectParameters
{
Colour = Color4.Black.Opacity(0.25f),
Type = EdgeEffectType.Shadow,
Radius = 3,
Offset = new Vector2(0f, 1f),
};
InternalChild = new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Children = new Drawable[]
{
beatmapSetHeader = new BeatmapSetHeader
{
Ruleset = { BindTarget = ruleset },
},
new Container
{ {
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y, AutoSizeAxes = Axes.Y,
@ -217,8 +189,6 @@ namespace osu.Game.Overlays.BeatmapSet
Details = new Details(), Details = new Details(),
}, },
}, },
},
},
} }
}; };
@ -239,7 +209,7 @@ namespace osu.Game.Overlays.BeatmapSet
BeatmapSet.BindValueChanged(setInfo => BeatmapSet.BindValueChanged(setInfo =>
{ {
Picker.BeatmapSet = RulesetSelector.BeatmapSet = author.BeatmapSet = beatmapAvailability.BeatmapSet = Details.BeatmapSet = setInfo.NewValue; Picker.BeatmapSet = rulesetSelector.BeatmapSet = author.BeatmapSet = beatmapAvailability.BeatmapSet = Details.BeatmapSet = setInfo.NewValue;
cover.BeatmapSet = setInfo.NewValue; cover.BeatmapSet = setInfo.NewValue;
if (setInfo.NewValue == null) if (setInfo.NewValue == null)

View File

@ -19,15 +19,12 @@ using osuTK;
namespace osu.Game.Overlays namespace osu.Game.Overlays
{ {
public class BeatmapSetOverlay : FullscreenOverlay<OverlayHeader> // we don't provide a standard header for now. public class BeatmapSetOverlay : FullscreenOverlay<BeatmapSetHeader>
{ {
public const float X_PADDING = 40; public const float X_PADDING = 40;
public const float Y_PADDING = 25; public const float Y_PADDING = 25;
public const float RIGHT_WIDTH = 275; public const float RIGHT_WIDTH = 275;
//todo: should be an OverlayHeader? or maybe not?
protected new readonly Header Header;
[Resolved] [Resolved]
private RulesetStore rulesets { get; set; } private RulesetStore rulesets { get; set; }
@ -39,7 +36,7 @@ namespace osu.Game.Overlays
private readonly Box background; private readonly Box background;
public BeatmapSetOverlay() public BeatmapSetOverlay()
: base(OverlayColourScheme.Blue, null) : base(OverlayColourScheme.Blue, new BeatmapSetHeader())
{ {
OverlayScrollContainer scroll; OverlayScrollContainer scroll;
Info info; Info info;
@ -72,14 +69,14 @@ namespace osu.Game.Overlays
Direction = FillDirection.Vertical, Direction = FillDirection.Vertical,
Children = new Drawable[] Children = new Drawable[]
{ {
Header = new Header(), Header,
info = new Info() info = new Info()
} }
}, },
}, },
new ScoresContainer new ScoresContainer
{ {
Beatmap = { BindTarget = Header.Picker.Beatmap } Beatmap = { BindTarget = Header.HeaderContent.Picker.Beatmap }
}, },
comments = new CommentsSection() comments = new CommentsSection()
}, },
@ -91,7 +88,7 @@ namespace osu.Game.Overlays
info.BeatmapSet.BindTo(beatmapSet); info.BeatmapSet.BindTo(beatmapSet);
comments.BeatmapSet.BindTo(beatmapSet); comments.BeatmapSet.BindTo(beatmapSet);
Header.Picker.Beatmap.ValueChanged += b => Header.HeaderContent.Picker.Beatmap.ValueChanged += b =>
{ {
info.Beatmap = b.NewValue; info.Beatmap = b.NewValue;
@ -125,7 +122,7 @@ namespace osu.Game.Overlays
req.Success += res => req.Success += res =>
{ {
beatmapSet.Value = res.ToBeatmapSet(rulesets); beatmapSet.Value = res.ToBeatmapSet(rulesets);
Header.Picker.Beatmap.Value = Header.BeatmapSet.Value.Beatmaps.First(b => b.OnlineBeatmapID == beatmapId); Header.HeaderContent.Picker.Beatmap.Value = Header.BeatmapSet.Value.Beatmaps.First(b => b.OnlineBeatmapID == beatmapId);
}; };
API.Queue(req); API.Queue(req);

View File

@ -24,6 +24,13 @@ namespace osu.Game.Overlays
[Resolved] [Resolved]
private AudioManager audio { get; set; } private AudioManager audio { get; set; }
private readonly float finalFillAlpha;
protected HoldToConfirmOverlay(float finalFillAlpha = 1)
{
this.finalFillAlpha = finalFillAlpha;
}
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
@ -42,8 +49,10 @@ namespace osu.Game.Overlays
Progress.ValueChanged += p => Progress.ValueChanged += p =>
{ {
audioVolume.Value = 1 - p.NewValue; var target = p.NewValue * finalFillAlpha;
overlay.Alpha = (float)p.NewValue;
audioVolume.Value = 1 - target;
overlay.Alpha = (float)target;
}; };
audio.Tracks.AddAdjustment(AdjustableProperty.Volume, audioVolume); audio.Tracks.AddAdjustment(AdjustableProperty.Volume, audioVolume);

View File

@ -30,6 +30,7 @@ namespace osu.Game.Overlays.Mods
{ {
public class ModSelectOverlay : WaveOverlayContainer public class ModSelectOverlay : WaveOverlayContainer
{ {
private readonly Func<Mod, bool> isValidMod;
public const float HEIGHT = 510; public const float HEIGHT = 510;
protected readonly TriangleButton DeselectAllButton; protected readonly TriangleButton DeselectAllButton;
@ -60,8 +61,10 @@ namespace osu.Game.Overlays.Mods
private SampleChannel sampleOn, sampleOff; private SampleChannel sampleOn, sampleOff;
public ModSelectOverlay() public ModSelectOverlay(Func<Mod, bool> isValidMod = null)
{ {
this.isValidMod = isValidMod ?? (m => true);
Waves.FirstWaveColour = Color4Extensions.FromHex(@"19b0e2"); Waves.FirstWaveColour = Color4Extensions.FromHex(@"19b0e2");
Waves.SecondWaveColour = Color4Extensions.FromHex(@"2280a2"); Waves.SecondWaveColour = Color4Extensions.FromHex(@"2280a2");
Waves.ThirdWaveColour = Color4Extensions.FromHex(@"005774"); Waves.ThirdWaveColour = Color4Extensions.FromHex(@"005774");
@ -403,7 +406,7 @@ namespace osu.Game.Overlays.Mods
if (mods.NewValue == null) return; if (mods.NewValue == null) return;
foreach (var section in ModSectionsContainer.Children) foreach (var section in ModSectionsContainer.Children)
section.Mods = mods.NewValue[section.ModType]; section.Mods = mods.NewValue[section.ModType].Where(isValidMod);
} }
private void selectedModsChanged(ValueChangedEvent<IReadOnlyList<Mod>> mods) private void selectedModsChanged(ValueChangedEvent<IReadOnlyList<Mod>> mods)

View File

@ -38,6 +38,18 @@ namespace osu.Game.Overlays.Settings.Sections
private List<SkinInfo> skinItems; private List<SkinInfo> skinItems;
private int firstNonDefaultSkinIndex
{
get
{
var index = skinItems.FindIndex(s => s.ID > 0);
if (index < 0)
index = skinItems.Count;
return index;
}
}
[Resolved] [Resolved]
private SkinManager skins { get; set; } private SkinManager skins { get; set; }
@ -112,21 +124,22 @@ namespace osu.Game.Overlays.Settings.Sections
private void updateItems() private void updateItems()
{ {
skinItems = skins.GetAllUsableSkins(); skinItems = skins.GetAllUsableSkins();
skinItems.Insert(firstNonDefaultSkinIndex, random_skin_info);
// insert after lazer built-in skins sortUserSkins(skinItems);
int firstNonDefault = skinItems.FindIndex(s => s.ID > 0);
if (firstNonDefault < 0)
firstNonDefault = skinItems.Count;
skinItems.Insert(firstNonDefault, random_skin_info);
skinDropdown.Items = skinItems; skinDropdown.Items = skinItems;
} }
private void itemUpdated(ValueChangedEvent<WeakReference<SkinInfo>> weakItem) private void itemUpdated(ValueChangedEvent<WeakReference<SkinInfo>> weakItem)
{ {
if (weakItem.NewValue.TryGetTarget(out var item)) if (weakItem.NewValue.TryGetTarget(out var item))
Schedule(() => skinDropdown.Items = skinDropdown.Items.Where(i => !i.Equals(item)).Append(item).ToArray()); {
Schedule(() =>
{
List<SkinInfo> newDropdownItems = skinDropdown.Items.Where(i => !i.Equals(item)).Append(item).ToList();
sortUserSkins(newDropdownItems);
skinDropdown.Items = newDropdownItems;
});
}
} }
private void itemRemoved(ValueChangedEvent<WeakReference<SkinInfo>> weakItem) private void itemRemoved(ValueChangedEvent<WeakReference<SkinInfo>> weakItem)
@ -135,6 +148,13 @@ namespace osu.Game.Overlays.Settings.Sections
Schedule(() => skinDropdown.Items = skinDropdown.Items.Where(i => i.ID != item.ID).ToArray()); Schedule(() => skinDropdown.Items = skinDropdown.Items.Where(i => i.ID != item.ID).ToArray());
} }
private void sortUserSkins(List<SkinInfo> skinsList)
{
// Sort user skins separately from built-in skins
skinsList.Sort(firstNonDefaultSkinIndex, skinsList.Count - firstNonDefaultSkinIndex,
Comparer<SkinInfo>.Create((a, b) => string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase)));
}
private class SkinSettingsDropdown : SettingsDropdown<SkinInfo> private class SkinSettingsDropdown : SettingsDropdown<SkinInfo>
{ {
protected override OsuDropdown<SkinInfo> CreateDropdown() => new SkinDropdownControl(); protected override OsuDropdown<SkinInfo> CreateDropdown() => new SkinDropdownControl();

View File

@ -124,9 +124,11 @@ namespace osu.Game.Rulesets.UI
Debug.Assert(drawableMap.ContainsKey(entry)); Debug.Assert(drawableMap.ContainsKey(entry));
var drawable = drawableMap[entry]; var drawable = drawableMap[entry];
// OnKilled can potentially change the hitobject's result, so it needs to run first before unbinding.
drawable.OnKilled();
drawable.OnNewResult -= onNewResult; drawable.OnNewResult -= onNewResult;
drawable.OnRevertResult -= onRevertResult; drawable.OnRevertResult -= onRevertResult;
drawable.OnKilled();
drawableMap.Remove(entry); drawableMap.Remove(entry);

View File

@ -13,6 +13,11 @@ namespace osu.Game.Screens.Menu
public void Abort() => AbortConfirm(); public void Abort() => AbortConfirm();
public ExitConfirmOverlay()
: base(0.7f)
{
}
public bool OnPressed(GlobalAction action) public bool OnPressed(GlobalAction action)
{ {
if (action == GlobalAction.Back) if (action == GlobalAction.Back)

View File

@ -13,6 +13,7 @@ using osu.Game.Beatmaps;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer;
using osu.Game.Online.Rooms; using osu.Game.Online.Rooms;
using osu.Game.Overlays.Mods;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Screens.Select; using osu.Game.Screens.Select;
@ -109,5 +110,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
} }
protected override BeatmapDetailArea CreateBeatmapDetailArea() => new PlayBeatmapDetailArea(); protected override BeatmapDetailArea CreateBeatmapDetailArea() => new PlayBeatmapDetailArea();
protected override ModSelectOverlay CreateModSelectOverlay() => new ModSelectOverlay(isValidMod);
private bool isValidMod(Mod mod) => !(mod is ModAutoplay) && (mod as MultiMod)?.Mods.Any(mm => mm is ModAutoplay) != true;
} }
} }

View File

@ -44,6 +44,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
[CanBeNull] [CanBeNull]
private IDisposable readyClickOperation; private IDisposable readyClickOperation;
private GridContainer mainContent;
public MultiplayerMatchSubScreen(Room room) public MultiplayerMatchSubScreen(Room room)
{ {
Title = room.RoomID.Value == null ? "New room" : room.Name.Value; Title = room.RoomID.Value == null ? "New room" : room.Name.Value;
@ -55,7 +57,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
{ {
InternalChildren = new Drawable[] InternalChildren = new Drawable[]
{ {
new GridContainer mainContent = new GridContainer
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Content = new[] Content = new[]
@ -178,6 +180,19 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
State = { Value = client.Room == null ? Visibility.Visible : Visibility.Hidden } State = { Value = client.Room == null ? Visibility.Visible : Visibility.Hidden }
} }
}; };
if (client.Room == null)
{
// A new room is being created.
// The main content should be hidden until the settings overlay is hidden, signaling the room is ready to be displayed.
mainContent.Hide();
settingsOverlay.State.BindValueChanged(visibility =>
{
if (visibility.NewValue == Visibility.Hidden)
mainContent.Show();
}, true);
}
} }
protected override void LoadComplete() protected override void LoadComplete()

View File

@ -33,6 +33,8 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
private OverlinedHeader participantsHeader; private OverlinedHeader participantsHeader;
private GridContainer mainContent;
public PlaylistsRoomSubScreen(Room room) public PlaylistsRoomSubScreen(Room room)
{ {
Title = room.RoomID.Value == null ? "New playlist" : room.Name.Value; Title = room.RoomID.Value == null ? "New playlist" : room.Name.Value;
@ -44,7 +46,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
{ {
InternalChildren = new Drawable[] InternalChildren = new Drawable[]
{ {
new GridContainer mainContent = new GridContainer
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Content = new[] Content = new[]
@ -190,6 +192,19 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
State = { Value = roomId.Value == null ? Visibility.Visible : Visibility.Hidden } State = { Value = roomId.Value == null ? Visibility.Visible : Visibility.Hidden }
} }
}; };
if (roomId.Value == null)
{
// A new room is being created.
// The main content should be hidden until the settings overlay is hidden, signaling the room is ready to be displayed.
mainContent.Hide();
settingsOverlay.State.BindValueChanged(visibility =>
{
if (visibility.NewValue == Visibility.Hidden)
mainContent.Show();
}, true);
}
} }
[Resolved] [Resolved]

View File

@ -10,6 +10,8 @@ using osu.Framework.Graphics;
using osu.Framework.Screens; using osu.Framework.Screens;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Online.Rooms; using osu.Game.Online.Rooms;
using osu.Game.Overlays.Mods;
using osu.Game.Rulesets.Mods;
using osu.Game.Screens.OnlinePlay; using osu.Game.Screens.OnlinePlay;
using osu.Game.Screens.OnlinePlay.Components; using osu.Game.Screens.OnlinePlay.Components;
@ -78,5 +80,9 @@ namespace osu.Game.Screens.Select
item.RequiredMods.Clear(); item.RequiredMods.Clear();
item.RequiredMods.AddRange(Mods.Value.Select(m => m.CreateCopy())); item.RequiredMods.AddRange(Mods.Value.Select(m => m.CreateCopy()));
} }
protected override ModSelectOverlay CreateModSelectOverlay() => new ModSelectOverlay(isValidMod);
private bool isValidMod(Mod mod) => !(mod is ModAutoplay) && (mod as MultiMod)?.Mods.Any(mm => mm is ModAutoplay) != true;
} }
} }

View File

@ -251,11 +251,7 @@ namespace osu.Game.Screens.Select
Children = new Drawable[] Children = new Drawable[]
{ {
BeatmapOptions = new BeatmapOptionsOverlay(), BeatmapOptions = new BeatmapOptionsOverlay(),
ModSelect = new ModSelectOverlay ModSelect = CreateModSelectOverlay()
{
Origin = Anchor.BottomCentre,
Anchor = Anchor.BottomCentre,
}
} }
} }
} }
@ -305,6 +301,8 @@ namespace osu.Game.Screens.Select
} }
} }
protected virtual ModSelectOverlay CreateModSelectOverlay() => new ModSelectOverlay();
protected virtual void ApplyFilterToCarousel(FilterCriteria criteria) protected virtual void ApplyFilterToCarousel(FilterCriteria criteria)
{ {
// if not the current screen, we want to get carousel in a good presentation state before displaying (resume or enter). // if not the current screen, we want to get carousel in a good presentation state before displaying (resume or enter).

View File

@ -17,7 +17,7 @@ using osuTK.Graphics;
namespace osu.Game.Tests.Beatmaps namespace osu.Game.Tests.Beatmaps
{ {
public class LegacyBeatmapSkinColourTest : ScreenTestScene public abstract class LegacyBeatmapSkinColourTest : ScreenTestScene
{ {
protected readonly Bindable<bool> BeatmapSkins = new Bindable<bool>(); protected readonly Bindable<bool> BeatmapSkins = new Bindable<bool>();
protected readonly Bindable<bool> BeatmapColours = new Bindable<bool>(); protected readonly Bindable<bool> BeatmapColours = new Bindable<bool>();